<rss version="2.0">
  <channel>
    <title>TILs on Leon Mika</title>
    <link>https://lmika.org/categories/tils/</link>
    <description></description>
    
    <language>en</language>
    
    <lastBuildDate>Sun, 12 Jul 2026 09:39:07 +1000</lastBuildDate>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/07/12/i-saw-someone-strapping-a.html</link>
      <pubDate>Sun, 12 Jul 2026 09:39:07 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/07/12/i-saw-someone-strapping-a.html</guid>
      <description>&lt;p&gt;I saw someone strapping a hockey stick with a unicycle beside them the other day. It was a little odd, but I didn&amp;rsquo;t think much of it, until today when I saw a few other people with hockey sticks pushing unicycles towards a gym. It&amp;rsquo;s when I realised that &lt;a href=&#34;https://en.wikipedia.org/wiki/Unicycle_hockey&#34;&gt;Unicycle Hockey&lt;/a&gt; is a thing. TIL.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Vibelog: Weatherpatch - UI Improvement</title>
      <link>https://lmika.org/2026/07/04/vibelog-weatherpatch-ui-improvement.html</link>
      <pubDate>Sat, 04 Jul 2026 16:13:28 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/07/04/vibelog-weatherpatch-ui-improvement.html</guid>
      <description>&lt;p&gt;A few weeks ago, I vibe-coded a web-app called Weatherpatch. This is an app that is designed to receive email newsletters and produce them as an RSS feeds: basically what Feedbin does, but without needing to use Feedbin. The app was vibe-coded with Opus, and while functional, it is hardly an example of good design (unless you&amp;rsquo;re a fan of Cubism). To wit:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/out-20260704-155830.png&#34; width=&#34;600&#34; height=&#34;455&#34; alt=&#34;Auto-generated description: A user interface displays an inbound email address for subscribing to newsletters and options to manage feeds, including renaming, deleting, and merging them.&#34;&gt;
&lt;p&gt;Yeah, Opus just threw the feed management controls all over the place. And I tolerated it for a time. I was more interested in having something functional, rather than pretty. But the thing about a bad UI is that it makes using the app feel bad. Sure I&amp;rsquo;m not in there managing feeds, but I would like to go in there are copy-paste the email address when setting a new one up.&lt;/p&gt;
&lt;p&gt;Seeing that Fable is available again (thanks, US government, I guess?) and that I haven&amp;rsquo;t given it a proper shakedown test last time, I figured it was worth throwing it at the problem, and seeing if it could fix the design Opus threw together. I also wanted to try out the &lt;a href=&#34;https://www.skills.sh/anthropics/skills/frontend-design&#34;&gt;frontend-design&lt;/a&gt; plugin. Here&amp;rsquo;s the initial prompt:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;The UI design of this webapp is quite primitive. While functional it doesn&amp;rsquo;t make it pleasant to use. Can you propose an improved design? Don&amp;rsquo;t change the underlying technology: just the UI and styling.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;It took a while, but came up with the following diagnosis:&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;Fable&amp;rsquo;s diagnosis of the issue&lt;/summary&gt;
  &lt;p&gt;What makes the current UI feel primitive&lt;/p&gt;
&lt;p&gt;Looking at the templates, three things stand out:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It&amp;rsquo;s stock Pico. Default palette, default type — it looks like every Pico demo, with no identity of its own.&lt;/li&gt;
&lt;li&gt;Every feed card shows its full management UI all the time. Each card carries a rename input, rename button, delete button, merge dropdown, and merge button — with ten feeds that&amp;rsquo;s fifty always-visible controls for actions you perform maybe once a month. The thing you actually want from a feed (its URL) is buried among them.&lt;/li&gt;
&lt;li&gt;Raw 60-character URLs dominate every card. The random slugs are unguessable by design, which means they&amp;rsquo;re also unreadable — printing them in full conveys nothing.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Proposed direction: &amp;ldquo;Synoptic chart&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The name weatherpatch is a gift — the app is essentially a weather station for newsletters, with feeds as stations reporting in. The direction leans into meteorological chart vernacular, kept quiet and instrument-like, since this is a tool you visit briefly, not a marketing page.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Palette — cool &amp;ldquo;chart paper&amp;rdquo; background (#F4F7F6), slate ink (#22303A), isobar blue for links (#33636F), and one accent: RSS orange (#D95B10). The orange is subject-grounded — the whole point of the app is producing RSS — and it&amp;rsquo;s used sparingly: the logo dot, the copy button, focus rings, the RSS chip.&lt;/li&gt;
&lt;li&gt;Type — IBM Plex Sans for UI, IBM Plex Mono for everything machine-ish: the inbound address, URLs, section labels. Monospace is load-bearing here, not decorative — the app&amp;rsquo;s most characteristic artifacts are random strings. (In production I&amp;rsquo;d embed the woff2 files in static/ alongside the CSS so the single-binary, no-CDN property holds; system-font fallbacks if you&amp;rsquo;d rather add zero bytes.)&lt;/li&gt;
&lt;li&gt;Signature element — the inbound address as a station call-sign: a hero panel at the top of the dashboard with the address in large mono type, one prominent &amp;ldquo;Copy address&amp;rdquo; button, and a faint set of isobar contour lines etched behind it (inline SVG, centre labelled &amp;ldquo;1013&amp;rdquo;). One place of boldness; everything else stays disciplined.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The UX changes (bigger win than the styling)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Progressive disclosure. Rename/merge/delete move behind a native &amp;lt;details&amp;gt; &amp;ldquo;Manage&amp;rdquo; disclosure per card — no JavaScript needed, and each card collapses to one line: title + two chips.&lt;/li&gt;
&lt;li&gt;URLs become copy chips. RSS and JSON chips copy the URL on click (your existing data-copy handler works unchanged — the chips just carry the attribute). The full URLs remain visible as plain links inside the Manage panel for the times you want to open or inspect them. Copying is the primary use of a feed URL, so it gets the primary affordance.&lt;/li&gt;
&lt;li&gt;A real empty state and a properly styled login card with a styled error alert (currently an inline style=&amp;ldquo;color:#b00020&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Microcopy tightened throughout: &amp;ldquo;Give this address to every newsletter you subscribe to. New senders show up below as feeds.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What stays and what changes&lt;/p&gt;
&lt;p&gt;Everything server-side stays as-is: Go templates, Fiber, embedded assets, POST-redirect-GET forms, app.js patterns. The change is replacing pico.min.css (~80 KB) with a hand-rolled weatherpatch.css (~8 KB) — same delivery mechanism, and at three pages the custom stylesheet is small enough to own outright. Template edits are modest (the &amp;lt;details&amp;gt; structure, chips, hero panel).&lt;/p&gt;
&lt;p&gt;Two optional extras that would touch Go code lightly (no technology change, just flagging since you said UI-only): per-feed item count and last-received date — the data is already in SQLite and would make the dashboard feel like stations actually reporting — and a favicon route using the RSS-arcs logo mark.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;It also produced a mockup in a static HTML file, which was quite an improvement over what was there. I then went back and forth with it a couple of times, asking it to move command arguments to modals, and have it produce a mock with more than a handful of items:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Okay, that&amp;rsquo;s a good start. I do wonder if it&amp;rsquo;d be worth merging the actions onto a single line. Maybe have &amp;ldquo;Rename, Merge&amp;rdquo; on the left and &amp;ldquo;Delete&amp;rdquo; on the right. The Rename and Merge buttons will display modal dialogs prompting for the input: a text field rename, and a select list (not a drop-down) for the merge. Delete will be on the right, and show a confirmation dialog as a modal. Use HTML dialog elements for this. Add any JavaScript you need, but keep it vanilla JavaScript.&lt;/p&gt;
&lt;p&gt;[…]&lt;/p&gt;
&lt;p&gt;Can you demonstrate how this would look with 30 feeds? I just want to make sure the Merge feed can handle that many feed items in the modal. I&amp;rsquo;m think we need to make sure the list doesn&amp;rsquo;t grow too large.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;I include in this gallery various screenshots in how the mocks evolved during this time.&lt;/p&gt;
&lt;div class=&#34;img-gallery&#34;&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2026/out-20260704-160119.png&#34;
     
        alt=&#34;Auto-generated description: A dashboard interface for managing email subscription feeds, showing an inbound address, active feeds with options to manage, merge, rename, or delete them, and buttons to copy the address or view feed formats in RSS and JSON.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  First version of the mock which, while prettier, was quite similar to the old UI in that the controls were just present on each card.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2026/out-20260704-160143.png&#34;
     
        alt=&#34;Auto-generated description: A dashboard interface displays an inbound email address with options to copy it and manage multiple newsletter feeds through RSS and JSON formats, including features to rename, merge, or delete them.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  The mock after I asked Claude to place input items in modals.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2026/out-20260704-160151.png&#34;
     
        alt=&#34;Auto-generated description: A dashboard interface for weatherpatch shows an inbound email address and multiple newsletter feeds, with a pop-up window to rename the Money Stuff feed.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  The rename modal.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2026/out-20260704-160204.png&#34;
     
        alt=&#34;Auto-generated description: A web interface shows a Merge feed popup window allowing the user to move everything from the Money Stuff feed to one of three other feeds: Golang Weekly, The Sizzle, or Hacker Newsletter, with options to cancel or merge.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  The merge feed modal.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2026/out-20260704-160212.png&#34;
     
        alt=&#34;Auto-generated description: A dashboard interface is shown with an inbound address, multiple active feeds listed, and a confirmation popup for deleting the Money Stuff feed.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  The delete confirmation modal, which previously used the browser&amp;amp;#39;s &amp;amp;#39;confirm&amp;amp;#39; function.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2026/out-20260704-160407.png&#34;
     
        alt=&#34;Auto-generated description: A user interface displays a feed merging option where the Money Stuff feed can be merged into another selected feed from a list.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  A modified merge feed modal after I asked Claude to consider a large number of feeds.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;After about half an hour of this, it was good enough to get Claude to implement it. I deployed the changes, and now the UI looks pretty decent.&lt;/p&gt;
&lt;p&gt;So all in all, I&amp;rsquo;m impressed. I would like to know how much of this was down to Fable, and how much of it was the frontend-design plugin. I don&amp;rsquo;t expect to be using Fable often, given how expensive it is. But for a large job like this, it did a good job.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Vibelog: Show As Table - A DSL In a Hurry</title>
      <link>https://lmika.org/2026/06/28/vibelog-show-as-table-a.html</link>
      <pubDate>Sun, 28 Jun 2026 11:36:12 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/06/28/vibelog-show-as-table-a.html</guid>
      <description>&lt;p&gt;I was asked to make a couple of diagrams for the purpose of showcasing a database design. These diagrams were mainly used to show the relationship between entities, so I chose to use TLDraw for this. But there was a need to add some example rows, which TLDraw does not make easy. Furthermore, there was a bit of a push to get this done quickly, as these were to be shown to various stakeholders the next day.&lt;/p&gt;
&lt;p&gt;Given all this, I thought it was worth asking Claude to make a tool to generate a table as an image from a DSL.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;The initial prompt&lt;/summary&gt;
  &lt;p&gt;Please generate for me a Go application which takes a DSL of the following form:&lt;/p&gt;
&lt;p&gt;```&lt;br&gt;
Title&lt;/p&gt;
&lt;p&gt;Name Value&lt;br&gt;
&amp;ldquo;Name2&amp;rdquo; &amp;ldquo;Value2&amp;rdquo;&lt;br&gt;
```&lt;/p&gt;
&lt;p&gt;It is to render this as a &amp;ldquo;card&amp;rdquo; with Title appearing above a box which contains two columns: the left containing the name and the right containing the value. The columns are to be presented as two columns of a table that will rendered as this: [Image #1]&lt;/p&gt;
&lt;p&gt;The result should be a PNG that I can include in another diagram.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;In short, I was to provide the data in the form of a table, and the tool Claude wrote is to generate it as an image, that I could import into TLDraw. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key Value
First John
Last Smith
Address &amp;#34;123 Fake St.&amp;#34;
City Melbourne
&lt;/code&gt;&lt;/pre&gt;&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/show-as-table-1.png&#34; width=&#34;267&#34; height=&#34;237&#34; alt=&#34;Auto-generated description: A table displays a key-value pair list containing personal information with keys First, Last, Address, and City, and corresponding values John, Smith, 123 Fake St., and Melbourne.&#34;&gt;
&lt;p&gt;This was my first attempt at using the image upload for Claude Code, with the intent of producing something that that mimics it. I don&amp;rsquo;t have it handy with me but the image was of a table rendered in a GUI of a database client of some sort (I didn&amp;rsquo;t pick the table, someone else took a screenshot and said &amp;ldquo;make it look like this&amp;rdquo;). And Claude managed to get it looking pretty close. It originally chose to use the builtin Golang fonts, but switched Jetbrains Mono for the headers and Inter for the table cells, after I asked it to use a more &amp;ldquo;professional&amp;rdquo; font.&lt;/p&gt;
&lt;p&gt;From there, the DSL evolved as the needs of the task arise, without any grand vision of it&amp;rsquo;s design. The diagram title was dropped, comments in the form of lines beginning with hash were added, and a row could be highlighted by prefixing it with a &lt;code&gt;*&lt;/code&gt;. How Claude did this was up to it. It was given pretty-much free reign in many of details, including how to highlight a row (it chose to do so using a yellow background):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key Value
First John
# Middle None
Last Smith
Address &amp;#34;123 Fake St.&amp;#34;
City Melbourne
* Registered Yes
&lt;/code&gt;&lt;/pre&gt;&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/show-as-table-2.png&#34; width=&#34;291&#34; height=&#34;274&#34; alt=&#34;Auto-generated description: A table displays personal information with keys such as First, Last, Address, City, and Registered, paired with the values John, Smith, 123 Fake St., Melbourne, and Yes respectively.&#34;&gt;
&lt;p&gt;The DSL eventually extended to include tables with multiple columns.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;Prompt to add multiple columns and highlights&lt;/summary&gt;
  &lt;p&gt;Please also add support for multiple columns, i.e. more than 2. And any row that begins with a &lt;code&gt;*&lt;/code&gt; should be highlighted, e.g &lt;code&gt;*name value&lt;/code&gt; (do not include the leading star)&lt;/p&gt;
&lt;/details&gt;

&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key          &amp;#34;Person 1&amp;#34;      &amp;#34;Person 2&amp;#34;
First        John            Mary
Last         Smith           Smith
Address      &amp;#34;123 Fake St.&amp;#34;  &amp;#34;456 Fake Rd.&amp;#34;
City         Melbourne       Sydney
* Registered Yes             No
&lt;/code&gt;&lt;/pre&gt;&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/show-as-table-3.png&#34; width=&#34;300&#34; height=&#34;196&#34; alt=&#34;Auto-generated description: A table compares two people, John and Mary Smith, listing their last names, addresses, cities, and registration status.&#34;&gt;
&lt;p&gt;And multiple tables stacked vertically, with matching cell widths.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;Prompt to stack multiple tables&lt;/summary&gt;
  &lt;p&gt;Okay. I would also like you to support dividers between subsequent tables. When I have a line of the form &amp;ldquo;&amp;mdash;&amp;rdquo;, it will indicate that I want two tables, positioned vertically, with a transparent gap between the two of about 1.5 times [since updated to be 1/2 that] the row height. The column sizes of both tables should be the same, in that they should be wide enough to fit whatever the widest cell of both tables.&lt;/p&gt;
&lt;/details&gt;

&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key          &amp;#34;Person 1&amp;#34;
First        John
Last         Smith
Address      &amp;#34;123 Fake St.&amp;#34;
City         Melbourne
* Registered Yes
---
Key          &amp;#34;Person 2&amp;#34;
First        Mary
Last         Smith
Address      &amp;#34;456 North Fake Road, South&amp;#34;
City         Sydney
Registered   No
&lt;/code&gt;&lt;/pre&gt;&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/show-as-table-4.png&#34; width=&#34;300&#34; height=&#34;392&#34; alt=&#34;Auto-generated description: The image shows two tables listing personal information for John Smith from Melbourne, who is registered, and Mary Smith from Sydney, who is not registered.&#34;&gt;
&lt;p&gt;Finally, a dark-mode was added. The colours were taken from a fork of this where someone added a dark mode directly. I wanted the ability to invoke dark mode via a switch, and simply adopting the fork meant I would loose the multi-table features I asked Claude to add. So I copied their version of the source, and asked Claude to crib the colours from it:&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;Prompt to add dark mode&lt;/summary&gt;
  &lt;p&gt;Okay. Someone has forked a version of this tool and implemented a dark version. They have shared with me the code located in @dark-version/main.go. Can you please adopt the colour scheme of this tool, and apply it when the flag &amp;ldquo;-dark&amp;rdquo; is present.&lt;/p&gt;
&lt;/details&gt;

&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key          &amp;#34;Person 1&amp;#34;
First        John
Last         Smith
Address      &amp;#34;123 Fake St.&amp;#34;
City         Melbourne
* Registered Yes
&amp;#34;Dark Mode&amp;#34;  Yes
&lt;/code&gt;&lt;/pre&gt;&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/show-as-table-5.png&#34; width=&#34;291&#34; height=&#34;311&#34; alt=&#34;Auto-generated description: A table presents personal details for John Smith including his address, city, and preferences with registered and dark mode set to yes.&#34;&gt;
&lt;p&gt;The results were decent, although you can guess that I didn&amp;rsquo;t actually run this tool in dark mode with a highlighted row.&lt;/p&gt;
&lt;p&gt;So, why do I write about this? Not that I need a reason, but I always find these badly designed, hacked together DSLs fascinating. You can learn a lot about using something that&amp;rsquo;s truly terrible. Using this particular DSL  for the task at hand is fine, but I can&amp;rsquo;t really see myself using it for anything else. Having the table cells defined as white-spaced table columns is not the easiest thing to maintain, let alone something easy to review when checked into Git. Yet it is obvious, and maybe with some better tooling it could be made to work better.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/06/20/its-not-a-proper-trip.html</link>
      <pubDate>Sat, 20 Jun 2026 11:24:03 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/06/20/its-not-a-proper-trip.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s not a proper trip to Canberra without a visit to Tuggeranong. Went to my favourite cafe and walked around the lake, this time in a clockwise direction. Was a lovely morning for it.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/c1fc7246cb.jpg&#34; width=&#34;600&#34; height=&#34;451&#34; alt=&#34;Auto-generated description: A brick café with outdoor seating is located in front of modern residential buildings under a partly cloudy sky.&#34;&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/d2347eeb63.jpg&#34; width=&#34;600&#34; height=&#34;451&#34; alt=&#34;Auto-generated description: A calm lake bordered by grassy land and trees is set against a backdrop of gently rolling hills under a cloudy sky.&#34;&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/06/13/its-hard-finding-places-in.html</link>
      <pubDate>Sat, 13 Jun 2026 07:41:04 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/06/13/its-hard-finding-places-in.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s hard finding places in the Belconnen area that are opened early, at least during the weekend. Settled on coming here which is more geared towards takeaways. So that does mean sitting outside in the cold air, but the coffee is warm, and the barista just turned on the outdoor heaters.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/pxl-20260612-213050251.jpg&#34; width=&#34;600&#34; height=&#34;451&#34; alt=&#34;Auto-generated description: A modern coffee shop with a glass and metal structure is situated in front of a tall residential building.&#34;&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/pxl-20260612-213318534.jpg&#34; width=&#34;600&#34; height=&#34;451&#34; alt=&#34;Auto-generated description: A cafe seating area features empty metal chairs and wooden tables, with a portable heater in the center.&#34;&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/06/04/touch-metro-i-can-understand.html</link>
      <pubDate>Thu, 04 Jun 2026 17:12:56 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/06/04/touch-metro-i-can-understand.html</guid>
      <description>&lt;p&gt;Touché, Metro. I can understand why you kept us outside of Clifton Hill for 15 minutes. That was some legitimate flooding.&lt;/p&gt;

  &lt;blockquote class=&#34;alert alert-selfreply&#34;&gt;
    &lt;p class=&#34;alert-heading&#34;&gt;
      
    &lt;/p&gt;
    &lt;p&gt;&lt;time datetime=&#34;2026-06-04T00:00:00Z&#34; class=&#34;reply-timestamp&#34;&gt;07:15&lt;/time&gt; Although I would add that 10-15 mm hardly constitues a torrential downpour.&lt;/p&gt;
  &lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/05/20/some-minor-teething-issues-with.html</link>
      <pubDate>Wed, 20 May 2026 08:00:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/05/20/some-minor-teething-issues-with.html</guid>
      <description>&lt;p&gt;Some minor teething issues with my new headphones. While trying to turn off noise cancelling I pushed a button which paired it with someone&amp;rsquo;s device, and started hearing their music. Had to resort to getting the app, which doesn&amp;rsquo;t thrill me, but it&amp;rsquo;s better than randomly pressing buttons.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/out-20260520-065232.png&#34; alt=&#34;Auto-generated description: A screenshot from a mobile app interface shows settings for a JBL Live 670NC device, including options for spatial sound, gestures, voice awareness, audio and video modes, and personal sound amplification.&#34;&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/05/14/tial-that-sleep-is-actually.html</link>
      <pubDate>Thu, 14 May 2026 15:10:02 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/05/14/tial-that-sleep-is-actually.html</guid>
      <description>&lt;p&gt;TIAL that &lt;code&gt;sleep&lt;/code&gt; is actually not available on the Distroless Docker images, at least from what I can see from &lt;a href=&#34;https://stackoverflow.com/questions/66579990/how-can-run-sleep-command-to-distroless&#34;&gt;Stack Overflow&lt;/a&gt;. So if you&amp;rsquo;re going to use Pod Lifecycle events to wait for requests to finish up, you&amp;rsquo;ll need some other means of sleeping.&lt;/p&gt;

</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/04/13/til-that-moon-towers-a.html</link>
      <pubDate>Mon, 13 Apr 2026 20:43:09 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/04/13/til-that-moon-towers-a.html</guid>
      <description>&lt;p&gt;TIL that moon towers, a thing I saw in an episode of Rick and Morty that I thought was completely fictional, are &lt;a href=&#34;https://en.wikipedia.org/wiki/Moonlight_tower&#34;&gt;actually a real thing&lt;/a&gt;, or at least were. I guess Rick and Morty live in Austin, Texas. 😏&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/02/22/sometimes-a-til-today-i.html</link>
      <pubDate>Sun, 22 Feb 2026 08:40:13 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/02/22/sometimes-a-til-today-i.html</guid>
      <description>&lt;p&gt;Sometimes a TIL (today I learnt) should really be classified as a WTTMT (wish they told me this).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/01/28/til-you-can-option-drag.html</link>
      <pubDate>Wed, 28 Jan 2026 12:23:08 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/01/28/til-you-can-option-drag.html</guid>
      <description>&lt;p&gt;TIL you can Option drag things that have a MacOS URL scheme into Obsidian to create a link to them. Managed to do this for both a file and an email.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/01/15/good-morning-everyone-this-is.html</link>
      <pubDate>Thu, 15 Jan 2026 05:47:40 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/01/15/good-morning-everyone-this-is.html</guid>
      <description>&lt;p&gt;&lt;em&gt;Good morning, everyone. This is a reminder that the orange seats are priority for passengers with special requirements.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Oh, so the orange coloured seat fabric indicates that it&amp;rsquo;s a priority seat?! I had no idea. I just thought it was because the seats are different. TIL.💡&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>First Impressions Of Google Antigravity</title>
      <link>https://lmika.org/2025/11/22/first-impressions-of-google-antigravity.html</link>
      <pubDate>Sat, 22 Nov 2025 13:03:33 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/22/first-impressions-of-google-antigravity.html</guid>
      <description>&lt;p&gt;Well, as predicted, I had a go at using Google Antigravity.&lt;/p&gt;
&lt;p&gt;I downloaded last Wednesday to try out the editor and agent. I didn&amp;rsquo;t have a good idea for it so I simply asked it to produce &lt;a href=&#34;https://tools.lmika.app/timestamps/&#34;&gt;an additional tool&lt;/a&gt; for my suite of online tools: one for dealing with timestamps and timezone conversions. I had plans for this one for a while, although they were relatively vague, it seemed like a good test of Gemini as a coding agent.&lt;/p&gt;
&lt;p&gt;I started with a bit of vibe-coding to see how much it could produce on it&amp;rsquo;s own. Here the prompt I used:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Note the tools located in &amp;ldquo;site&amp;rdquo;. I would like another one made that will process timestamps.&lt;/p&gt;
&lt;p&gt;The tool will consist of two text boxes side-by-side. The text box to the left will be user input: the user will use this to enter timestamps of various types, with one timestamp per line. On the right will be the output. It is not designed to be editable, but the user should be able to scroll, copy, and otherwise get the text from this pane.&lt;/p&gt;
&lt;p&gt;Above the two should be a select picker of operations. Beside that are two radio buttons: &amp;ldquo;UTC&amp;rdquo; and &amp;ldquo;Local&amp;rdquo;. This is for selecting the given timezone, where Local is the browser&amp;rsquo;s local timezone.&lt;/p&gt;
&lt;p&gt;The way this works is that the user will enter a line of input in the text area in the left. When changed, as long as the line of input is valid, the tool will apply the operation and display the result on the same line as the input in the text area on the right. The operation to apply will depend on the picker. Blank lines and any line beginning with &amp;ldquo;#&amp;rdquo; are valid and are to be copied as is. Timestamps are to be displayed in ISO 8601 within the selected timezone.&lt;/p&gt;
&lt;p&gt;The picker should have the following options, which do the following operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Convert from Unix&amp;rdquo;: converts the input in seconds from the Unix epoch into a timestamp on the right.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Convert from Unix Micro&amp;rdquo;: converts the input in milliseconds from the Unix epoch into a timestamp on the right.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;To UTC&amp;rdquo;: converts the input in ISO 8601 in the selected timezone into UTC, regardless of what timezone is chosen. &amp;ldquo;From UTC&amp;rdquo;: converts the input in ISO 8601, which is assumed to be in UTC, into the selected timezone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This should be implemented as a static HTML page with vanilla JavaScript.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;The agent did crash a few times: probably launch day, go-live teething problems. At one point it stopped halfway, and I had to ask it to &amp;ldquo;continue with the implementation plan.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;In the end it did manage to produce a decent-looking HTML UI, plus a working JavaScript implementation of what I described. The quality of the generated code was… fine. The JavaScript worked, but it wasn&amp;rsquo;t as neat as something produced by Claude Code, and definitely not as neat as something I would&amp;rsquo;ve written myself (the HTML was fine).&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20251119-224038.png&#34; width=&#34;600&#34; height=&#34;361&#34; alt=&#34;Auto-generated description: A timestamp converter interface displays UNIX time conversions for specified dates and the current time.&#34;&gt;
&lt;p&gt;I had ideas of going further, so I asked the agent to port the JavaScript to Go and to produce a WSDL target, like many of the other tools.  The agent had no issues doing so.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Please port the main logic defined in &amp;ldquo;main.js&amp;rdquo; to Go targetting WASM, in a new directory located in &amp;ldquo;cmds&amp;rdquo;. You can use the other WASM files found in &amp;ldquo;cmds&amp;rdquo; as a guide.&lt;/p&gt;
&lt;p&gt;In it&amp;rsquo;s place, please change &amp;ldquo;site/timestamps/main.js&amp;rdquo; to be a WASM launcher, much like ther other launchers defined in &amp;ldquo;site/clocks&amp;rdquo; and &amp;ldquo;site/templates&amp;rdquo;. Add the new Go target to the Makefile&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;I then &amp;ldquo;started driving&amp;rdquo; by extending the Go code by adding a parser for a potential mini-language. And from this I got to experience Antigravity as a code editor. And it&amp;rsquo;s essentially VS Code, which honestly is not my favourite IDE. In fact, with all the LLM-powered code completion, it&amp;rsquo;s a little closer to Cursor, which I only tried once before. I was turned off by Cursor due to all the suggestions getting in the way, and Antigravity is a bit like that too. I kind of wish there&amp;rsquo;s more prioritising of suggestions: those that fix an compile error, or can be inferred by a refactor should have more weight than those that lack the context to be more than just mere guesses. The latter is rarely what I want, and I usually have to leave the home row to reach for the Escape, or I&amp;rsquo;ve accidentally pressed tab and have to back-out of the unwanted insert. Maybe that&amp;rsquo;s something that I can adjust: I haven&amp;rsquo;t looked, but I would prefer it if it just did nothing if it couldn&amp;rsquo;t be sure of what I want.&lt;/p&gt;
&lt;p&gt;I also tried the testing agent, where it spun up Chrome and drove it to test the UI. The agent did have some issues launching the service — probably because I had the dev server already running — but it did successfully test the UI out. The tests were unsuccessful, and I had to go in and debug it, but hey, that&amp;rsquo;s something, I guess.&lt;/p&gt;
&lt;p&gt;So, would I use Antigravity again? I mean, it&amp;rsquo;s a decent IDE (or maybe it&amp;rsquo;s better to say that it&amp;rsquo;s built on a decent IDE), and I think the agents work quite well. But I probably wouldn&amp;rsquo;t use it again, mainly because it&amp;rsquo;s now how I like to interact with agents. I&amp;rsquo;ve grown accustom to how Claude Code works, where the agent takes instruction from you on your terms. Otherwise it stays out of the way. And to be fair, that&amp;rsquo;s sort of how the agent in Antigravity works too. If they just toned down the suggestions in the editor itself, it may be something for me in the future. We&amp;rsquo;ll see.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Github FOMO</title>
      <link>https://lmika.org/2025/11/19/github-fomo.html</link>
      <pubDate>Wed, 19 Nov 2025 07:29:49 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/19/github-fomo.html</guid>
      <description>&lt;p&gt;We&amp;rsquo;re coming up to about a year-and-a-half of moving my code to a &lt;a href=&#34;https://lmika.org/2024/07/09/a-tour-of.html&#34;&gt;self-hosted Forgejo instance&lt;/a&gt;. So far it&amp;rsquo;s been great, but I will admit that I am suffering from a bit of Github FOMO. So much of the technical world assumes your code lives on Github. Many tools assume you&amp;rsquo;re either pushing code, or distributing binaries via Github. None of the AI coding assistances work with anything other than Github.&lt;/p&gt;
&lt;p&gt;Even when you&amp;rsquo;re considering whether you should advertise where the source code of your open-source projects, it feels a little funny posting a link to an SCM that is not Github. Open-source development is a social activity, and I doubt it helps the appeal of your project in the eyes of potential contributors if your code is not where they tend to be. Doubly so when when you consider that they&amp;rsquo;ll need to create an account on your SCM service to contribute.&lt;/p&gt;
&lt;p&gt;There are other costs that I haven even considered, like the stability of external services your open-source SCM relies on. I found I wasn&amp;rsquo;t able to run any CI/CD builds last night because Codeberg was down and the pipelines were unable to fetch the Git checkout action. The idea of relying on services hosted by volunteers is a nice one, but I can imagine Microsoft&amp;rsquo;s SLAs being a lot stricter when it comes to keeping Github online.&lt;/p&gt;
&lt;p&gt;So yeah, it&amp;rsquo;s cold and lonely out here. I&amp;rsquo;ll keep at it though: I think the benefits that come from having my own place for my code is worth it. But I do wonder if I should move some projects back, at least some of the &amp;ldquo;big&amp;rdquo; ones. Not that any of the projects I&amp;rsquo;m working on need contributors, but just to be where others are. There&amp;rsquo;s still value in that.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/11/11/til-that-is-the-symbol.html</link>
      <pubDate>Tue, 11 Nov 2025 16:28:33 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/11/til-that-is-the-symbol.html</guid>
      <description>&lt;p&gt;TIL that &lt;code&gt;⎋&lt;/code&gt; is the symbol for &lt;a href=&#34;https://en.wikipedia.org/wiki/Esc_key#symbol&#34;&gt;the Escape key&lt;/a&gt;. HT &lt;a href=&#34;https://social.lol/@jason&#34;&gt;@jason@social.lol&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/10/24/its-funny-how-i-approach.html</link>
      <pubDate>Fri, 24 Oct 2025 10:19:41 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/24/its-funny-how-i-approach.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s funny how I approach certain features in the tools I make, such as adding UCL to Dynamo Browse. It&amp;rsquo;s been several months since I&amp;rsquo;ve done this, and I haven&amp;rsquo;t really used it for anything substantial until today. I guess because I get the sense that it&amp;rsquo;s half-finished (mainly due to the fact that it is half-finished) I tend to approach such features gingerly: in a careful way so as to avoid any problems. That&amp;rsquo;s probably not the best way to approach these features though. They need to be taken through the ringer, and just used, lest I never find their limitations or bugs that need to be fixed.&lt;/p&gt;
&lt;p&gt;Anyway, this is a long winded way of saying that I&amp;rsquo;m glad I actually replaced the old scripting engine in Dynamo Browse with UCL. It was added to be used, and it actually came in useful today.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Godot Game - A Trigger That Reveals Secrets</title>
      <link>https://lmika.org/2025/10/12/devlog-godot-game-a-trigger.html</link>
      <pubDate>Sun, 12 Oct 2025 10:09:40 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/12/devlog-godot-game-a-trigger.html</guid>
      <description>&lt;p&gt;Okay, I think I need something to hide secret areas from the player and reveal it to them when they approach it. I&amp;rsquo;ve lived without this mechanic for a while, placing secret areas a fair distance from the main game area, so that they&amp;rsquo;re not visible. But such distances make it difficult to place time-limited things within those secret areas, like the invulnerability power-up, since travelling back to the main area to use it would eat up into the player&amp;rsquo;s power-up time. I could add ways for the player to return to the main play area quickly, like doors, but that complicates the level geometry and I need to place them out of the way, like in the sky.&lt;/p&gt;
&lt;p&gt;So, I&amp;rsquo;ll add a new element to do this. It will be an &lt;code&gt;Area2D&lt;/code&gt; node with an associated tile layer as a child. When the player enters the &lt;code&gt;Area2D&lt;/code&gt;, the tile layer is hidden away and the player can see the revealed secret. The player leaving the &lt;code&gt;Area2D&lt;/code&gt; will make the tile layer visible again.&lt;/p&gt;
&lt;p&gt;Okay, the new &lt;code&gt;SecretReveal&lt;/code&gt; scene has been built. The root node is an &lt;code&gt;Area2D&lt;/code&gt; which takes, as children when added to the main scene, a &lt;code&gt;CollisionShape2D&lt;/code&gt; to act as the trigger space, and a tile layer to act as the tiles to hide/show. The tile layer needs to be in the foreground, which is Z Index 10 and with collision turned off, so that it&amp;rsquo;ll reveal the mid and background layers. The script simply tracks entering bodies (it monitors layer 2, which is dedicated to the player).&lt;/p&gt;
&lt;p&gt;Now, the next question is how to fade the tile map in and out. I could just toggle the visibility but that&amp;rsquo;s way too jarring. What I hope to achieve is to add an animation player to &lt;code&gt;SecretReveal&lt;/code&gt; which will play a fade transition as the player enters or exits the &lt;code&gt;Area2D&lt;/code&gt;. But how to do that without using scripting? I rather use the primitives offered to me as I&amp;rsquo;m guessing they&amp;rsquo;ll be more efficient than throwing events around in GDSscript.&lt;/p&gt;
&lt;p&gt;One possibility is the &lt;code&gt;Modulate&lt;/code&gt; option in the &lt;code&gt;CanvasItem&lt;/code&gt; properties. After quickly playing around with this in the editor, it looks like it&amp;rsquo;s possible to adjust the alpha channel on this property, and that would adjust the visibility of the tile layer:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-12-at-10.02.17.gif&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;057d625dbf85066aaf4426135761271e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-12-at-10.02.17.gif&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-12 at 10.02.17.gif&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;So this looks viable. I&amp;rsquo;m actually glad that &lt;code&gt;Area2D&lt;/code&gt; has this property, despite not actually rendering itself in any way (outside of the editor) Let&amp;rsquo;s give it a try.&lt;/p&gt;
&lt;p&gt;Okay, that works. Hooking it up to an animation player playing an animation that fades out and fades in the tiles when the player enters and leaves the trigger area works. It needs some improvement though. If the player were to enter and leave the target area quickly, the visibility would quickly &amp;ldquo;jump&amp;rdquo; from partially visible to fully visible. I suspect the reason for this is that the animation is always starting from the start.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-12-at-10.10.53.gif&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;057d625dbf85066aaf4426135761271e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-12-at-10.10.53.gif&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-12 at 10.10.53.gif&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;One technique I used in the past is to preserve the current timestamp of the animation when I change it. But the animations here are using non-linear easing as it makes for a better transition.&lt;/p&gt;
&lt;p&gt;So what I&amp;rsquo;ll try is a single animation that will be played forwards and backwards. When there&amp;rsquo;s a need to play the animation, the logic will detect whether the animation player is currently playing, and will resume playback from it&amp;rsquo;s current position in the desired direction.&lt;/p&gt;
&lt;p&gt;Okay, so this is what I settled with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-gdscript&#34; data-lang=&#34;gdscript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_on_body_entered&lt;/span&gt;(body: &lt;span style=&#34;color:#a6e22e&#34;&gt;Node2D&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	candidate_body &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;is_playing&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;play_section&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reveal_secret&amp;#34;&lt;/span&gt;, \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		    animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;current_animation_position)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;play&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reveal_secret&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_on_body_exited&lt;/span&gt;(body: &lt;span style=&#34;color:#a6e22e&#34;&gt;Node2D&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; body &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; candidate_body:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		candidate_body &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;is_playing&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;play_section&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reveal_secret&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;, \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			    animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;current_animation_position, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;play_backwards&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reveal_secret&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What I&amp;rsquo;m doing is when the player enters the trigger space, I&amp;rsquo;ll play the &amp;ldquo;reveal secret&amp;rdquo; animation, either from the start or from the current position, depending if the animation player is playing. If the player leaves the trigger space, and the animation player is not playing, I&amp;rsquo;ll play the &amp;ldquo;reveal secret&amp;rdquo; in reverse from the end. When it is playing, I do something similar but I need to set the end position to the current animation position, rather than the start position. I&amp;rsquo;m guessing the animation player will take the initial position as the end when it&amp;rsquo;s playing in reverse, which makes sense.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the transition looks now:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-12-at-10.27.25.gif&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;057d625dbf85066aaf4426135761271e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-12-at-10.27.25.gif&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-12 at 10.27.25.gif&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Much smoother.&lt;/p&gt;
&lt;p&gt;Now to try it out in level 3-1. And yeah, this is a much better way to do secrets. I can build them close to the play area and the player no longer needs to navigate them blindly, or walk a million miles just to get to the bonus. I won&amp;rsquo;t overdo it though. I&amp;rsquo;m going to keep some of the large secrets that are naturally out of the way as they were. The player will need to react fast to enter them so I want to make sure they have the opportunity to see them.&lt;/p&gt;
&lt;p&gt;I am wondering whether to merge this with the &amp;ldquo;You found a secret&amp;rdquo; trigger, but I think I&amp;rsquo;ll keep them separate for now.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Blogging Tools - Podcast Clip Favourites</title>
      <link>https://lmika.org/2025/10/05/devlog-blogging-tools-podcast-clip.html</link>
      <pubDate>Sun, 05 Oct 2025 16:52:30 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/05/devlog-blogging-tools-podcast-clip.html</guid>
      <description>&lt;p&gt;Inspired by the way &lt;a href=&#34;https://ronjeffries.com/articles/-w025/y/t/&#34;&gt;Ron Jeffries writes&lt;/a&gt; about his work, as well as by &lt;a href=&#34;https://blog.martin-haehnel.de/2025/10/03/whiledo/&#34;&gt;Martin Hähnel&lt;/a&gt; attempt at this, I thought for this instalment of Devlog I&amp;rsquo;ll try a more &amp;ldquo;lab notes&amp;rdquo; approach. This means a potentially more mundane and less satisfactory description of project work today: less showing of what was accomplished, and more of a running commentary. I wanted to see if I liked this style of writing, and if it helped me or slowed me down. Preliminary results were mixed: it did slow me down, but I found it enjoyable. I&amp;rsquo;ll try this a few more times to see how I feel about it.&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s coding session is to continue the work of adding saved favourite podcast clips from Blogging Tools. Previously this was a standalone application connected to a database, but along with the tech stack used to build this falling out of active support, along with the feeds no longer working for reasons I rather not look into, I want to replace this with a static site that takes nothing to maintain. One other thing is that I want to move away from referencing links to the podcast clips and saving actual audio. Since I&amp;rsquo;m dealing with copyrighted material, some of it that is for pay, this site will be kept private.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m choosing to use Blogging Tools for this as it has a relatively decent podcast clipper that I use for clips I publish to my site. For the static site itself, I&amp;rsquo;m choosing to look at Hugo, given that I&amp;rsquo;m comfortable with this approach too. Although I do have some concerns about the long term viability of this for sites I don&amp;rsquo;t touch that often. An initial attempt at this used another site I use to track audio that used a template that fell out of maintenance and broke when I moved to Hugo 0.151. The Hugo maintainers really need to clean up their versioning act.&lt;/p&gt;
&lt;p&gt;Anyway, the current status of this is a temporary Hugo site with a new template. At this stage, I&amp;rsquo;ve got Blogging Tools running a new job type that will take the clipped audio and image thumbnail, save them as static data to Hugo, and publish a new post.&lt;/p&gt;
&lt;p&gt;At the moment, the template isn&amp;rsquo;t including the thumbnail or audio HTML. This is now a point of committing to this site and template: moving it out of the temp directory and into a proper workspace. So let&amp;rsquo;s start that now. I&amp;rsquo;m using the &lt;a href=&#34;https://github.com/ldeso/hugo-flex&#34;&gt;Hugo Flex&lt;/a&gt; theme as it provides a nice clean canvas to start with, and it seems to be in active maintenance (something to watch out for when dealing with Hugo themes). Added the git module, and setting Goldmark unsafe to true (once again) and now the new Hugo site is ready:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.35.03-localhost-fd2731f7bcc3.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.35.03-localhost-fd2731f7bcc3.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 09.35.03 localhost fd2731f7bcc3.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Now testing this with Blogging Tools. I&amp;rsquo;ve already got an ATP clip ready to go. And after remembering to change the target directory from the temp Hugo site to the real one, I am ready to test the extract. All that involves is clicking &amp;ldquo;Save&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.36.41-localhost-bdf14f391c73.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.36.41-localhost-bdf14f391c73.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 09.36.41 localhost bdf14f391c73.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Okay, that didn&amp;rsquo;t work for a very stupid reason. I set the target directory to Blogging Tools repo, not the Hugo site. Made the change (Blogging Tools is being run using &lt;a href=&#34;https://github.com/air-verse/air&#34;&gt;Air&lt;/a&gt; which gives me file watching capabilities one would see in the frontend world) and can now see that the new post was written to the new Hugo site.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.43.17-localhost-42cb85cfbe26.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.43.17-localhost-42cb85cfbe26.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 09.43.17 localhost 42cb85cfbe26.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Now to adjust the template a little, just to add the audio and thumbnail. The Markdown files produced by Blogging Tools have all the clip information in the front matter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title: &amp;#34;449:  An Unclean Mouse&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;episode:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  guid: some-random-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  url: &amp;#34;https://atp.fm/449&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  title: &amp;#34;449:  An Unclean Mouse&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  date: 2021-09-23 12:27:49 +1000 AEST
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  image_src: &amp;#34;https://cdn.atp.fm/artwork-bootleg&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  audio_src: &amp;#34;https://example.com/file.mp3&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;show:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  title: &amp;#34;Accidental Tech Podcast: Unedited Live Stream&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clip:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  start: 0s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  duration: 60ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;date: 2021-09-23 12:27:49 +1000 AEST
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;thumbnail: images/DQkt_Lk5QRjXVHE0rdR09.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;audio: audio/5fFX8m0BqqFqTwlVAtb2Y.mp3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test thing
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oh, before I do that. Let me fix the dates should that they&amp;rsquo;re in UTC and formatted as ISO 8601. This is a quick change to the template used by Blogging Tools:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;date: {{.Clip.EpisodeDate.UTC.Format &amp;#34;2006-01-02T15:04:05Z07:00&amp;#34;}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another quick test… perfect. The dates are coming through again. Oh, and a quick aside: because the front matter is all included in one Go template, I had to make sure to properly quote the string values, lest they contain colons and other constructs YAML doesn&amp;rsquo;t like. Easy way to do that is pipe them through &lt;code&gt;printf &amp;quot;%q&amp;quot;&lt;/code&gt;, which quotes them as if they&amp;rsquo;re Go strings. May not be perfect but it&amp;rsquo;s good enough for now:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;title: {{.Clip.EpisodeTitle | printf &amp;#34;%q&amp;#34;}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, lets fix the template. I&amp;rsquo;ll start by creating a new template in &lt;code&gt;layouts/clips/singles.html&lt;/code&gt; which is a copy-and-paste of the existing theme post. I&amp;rsquo;ll then add details of the front matter, such as the thumbnail and audio player. This I can get using the &lt;a href=&#34;https://gohugo.io/configuration/params/&#34;&gt;Params&lt;/a&gt; template construct. I&amp;rsquo;ll start by just printing it:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-gotemplate&#34; data-lang=&#34;gotemplate&#34;&gt;{{ define &amp;#34;main&amp;#34; }}

  {{ $context := dict &amp;#34;page&amp;#34; . &amp;#34;level&amp;#34; 1 &amp;#34;isdateshown&amp;#34; true }}
  {{ partial &amp;#34;heading.html&amp;#34; $context }}
  
  Audio = {{.Params.audio}}, image = {{.Params.thumbnail}}
  
  {{ .Content }}
  {{ partial &amp;#34;tags.html&amp;#34; . }}
  {{ partial &amp;#34;comments.html&amp;#34; . }}

{{ end }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.54.52-localhost-c59d83c214d9-1.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.54.52-localhost-c59d83c214d9-1.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 09.54.52 localhost c59d83c214d9 1.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;I had to restart Hugo, but that&amp;rsquo;s coming through. I need to convert these into proper URLs though. I&amp;rsquo;ll start by trying the &lt;a href=&#34;https://gohugo.io/functions/urls/absurl/&#34;&gt;absurl&lt;/a&gt; template function:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-gotemplate&#34; data-lang=&#34;gotemplate&#34;&gt;Audio = {{ absURL .Params.audio}}, image = {{ absURL .Params.thumbnail}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.57.47-localhost-392aecb7bb5f-1.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.57.47-localhost-392aecb7bb5f-1.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 09.57.47 localhost 392aecb7bb5f 1.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Okay, getting better. Let&amp;rsquo;s try and turn them into proper HTML elements:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  &amp;lt;img src=&amp;#34;{{ absURL .Params.thumbnail}}&amp;#34;&amp;gt;
  &amp;lt;audio src=&amp;#34;{{ absURL .Params.audio}}&amp;#34; controls&amp;gt;&amp;lt;/audio&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.59.35-localhost-56693aeddfc3-1.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-09.59.35-localhost-56693aeddfc3-1.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 09.59.35 localhost 56693aeddfc3 1.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Good, the image and audio is coming through. Image looks a little large but I&amp;rsquo;ll fix that at little later. Oh, and it looks like the clips are showing up in the home page already. That&amp;rsquo;s a nice touch. I do want to change the clip paths though. At the moment, they&amp;rsquo;re saved using the auto-incrementing clip ID, which is not ideal. Clip metadata is stored in an Sqlite database and the library I&amp;rsquo;m using — which is &lt;a href=&#34;modernc.org/sqlite&#34;&gt;a Go port of Sqlite3 that&lt;/a&gt; doesn&amp;rsquo;t need CGO — has a nasty habit of reusing row IDs. I really should replace this with an auto-generated primary key. But that&amp;rsquo;s for later.&lt;/p&gt;
&lt;p&gt;Right now, I think I&amp;rsquo;ll use a hash of the episode Guid for the path. ATP seems to have randomly generated hashes but I know that some RSS feeds choose to use URLs, which won&amp;rsquo;t do for a path. Why the Guid? Well, I want to be able to regenerate a clip if need be, replacing the existing one.&lt;/p&gt;
&lt;p&gt;Actually, no, that won&amp;rsquo;t do. I want to be able to create multiple clips from the same episode. So maybe I&amp;rsquo;ll use a hash that includes the Guid and clip timestamp. So let&amp;rsquo;s try that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;clipPathRaw&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%v:%v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;clip&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EpisodeGUID&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;clip&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ClipStart&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;clipPathHash&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;md5&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sum&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;clipPathRaw&lt;/span&gt;))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;clipPath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hex&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EncodeToString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;clipPathHash&lt;/span&gt;[:])  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;postFilename&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;filepath&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Join&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;postDir&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%v.md&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;clipPath&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MD5 should be fine: these don&amp;rsquo;t need to be cryptographically safe. Also, &lt;code&gt;md5.Sum&lt;/code&gt; returns an &lt;code&gt;[16]byte&lt;/code&gt; array, and I keep forgetting how to return this as a &lt;code&gt;[]byte&lt;/code&gt; slice. Apparently it&amp;rsquo;s &lt;code&gt;array[:]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another quick test. Yeah, it works. The clip paths now look like this: &lt;code&gt;http://localhost:1313/clips/210da5b665c38c809eb1ea481b1b22de/&lt;/code&gt; Not great, but I tend to browse this visually so I think I can live with this.&lt;/p&gt;
&lt;p&gt;Okay, next thing is having Blogging Tools generate the clips and commit them to Git. The goal is to have the Hugo site stored in a Git repository and built to a private, undisclosed website. I did this for Nano Journal, which synchronised journal entries to a Git repo after saving it locally. Looking at the code, though, I have no idea how I setup the credentials. There&amp;rsquo;s nothing in the config hinting at a certificate so I may have done it manually.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also wondering if I can use &lt;a href=&#34;https://github.com/go-git/go-git&#34;&gt;Go Git&lt;/a&gt; for this. I didn&amp;rsquo;t use this for Nano Journal, as I wanted to use LFS; which Go Git doesn&amp;rsquo;t support (instead I just shelled out to &lt;code&gt;git&lt;/code&gt;). But I&amp;rsquo;m wondering if I can live without LFS for this.&lt;/p&gt;
&lt;p&gt;Okay, let&amp;rsquo;s try this. I&amp;rsquo;ll push the current Hugo site to a test repo on my Forgejo instance and see whether I can check it out from Blogging Tools. This will be done as a user that I&amp;rsquo;ll configure Blogging Tools to act as.&lt;/p&gt;
&lt;p&gt;Then I added Go Git to blogging tool and created a new provider for Git. Added a method to either pull or clone a remote repository, checkout a branch, and pull updates from the repo. I&amp;rsquo;ve chosen to use the file system for keeping the local workspace so that Blogging Tools doesn&amp;rsquo;t need to keep cloning the repo whenever there&amp;rsquo;s a need to add a clip. This I&amp;rsquo;m just going to keep in ephemeral storage so that when the Docker container gets cycled and the workspace lost, it&amp;rsquo;ll just recreate it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Provider&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;CloneOrPull&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Repository&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;isDir&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;workspace&lt;/span&gt;) {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#75715e&#34;&gt;// Workspace doesn&amp;#39;t exist. Pull from repo.  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PlainClone&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;workspace&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CloneOptions&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;:               &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repoURL&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;RecurseSubmodules&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DefaultSubmoduleRecursionDepth&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;Auth&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BasicAuth&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#a6e22e&#34;&gt;Username&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#a6e22e&#34;&gt;Password&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       })  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PlainOpen&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;workspace&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;worktree&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Worktree&lt;/span&gt;()  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worktree&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pull&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PullOptions&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;RemoteURL&lt;/span&gt;:         &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repoURL&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;RecurseSubmodules&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DefaultSubmoduleRecursionDepth&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;ReferenceName&lt;/span&gt;:     &lt;span style=&#34;color:#a6e22e&#34;&gt;plumbing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReferenceName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;),  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;Auth&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BasicAuth&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;Username&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;Password&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worktree&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Checkout&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CheckoutOptions&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;Branch&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;plumbing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReferenceName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;),  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Quick test of this, and I&amp;rsquo;m seeing a &amp;ldquo;repository doesn&amp;rsquo;t exist&amp;rdquo; error.&lt;/p&gt;
&lt;p&gt;Actually, no. That was because of an earlier use of the repository URL when I actually wanted the workspace. But now I&amp;rsquo;m seeing a &amp;ldquo;reference not found&amp;rdquo; error when I try to pull from the origin:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-11.24.51-localhost-87f4f1d9b693.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-11.24.51-localhost-87f4f1d9b693.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 11.24.51 localhost 87f4f1d9b693.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Ah, okay. I should&amp;rsquo;ve used &lt;code&gt;plumbing.NewBranchReferenceName&lt;/code&gt; here. That&amp;rsquo;s fix that. Now it&amp;rsquo;s an &lt;code&gt;already up-to-date&lt;/code&gt; error. That&amp;rsquo;s fine, I&amp;rsquo;ll just add an ignore case here:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worktree&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pull&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PullOptions&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;RemoteURL&lt;/span&gt;:         &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repoURL&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;RecurseSubmodules&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DefaultSubmoduleRecursionDepth&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ReferenceName&lt;/span&gt;:     &lt;span style=&#34;color:#a6e22e&#34;&gt;plumbing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewBranchReferenceName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;),  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Auth&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BasicAuth&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;Username&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;Password&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Is&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NoErrAlreadyUpToDate&lt;/span&gt;) {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another test:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-11.28.44-localhost-055ec2134222.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/2025-10-05-11.28.44-localhost-055ec2134222.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;2025-10-05 11.28.44 localhost 055ec2134222.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;And that worked. I managed to pull changes from remote.&lt;/p&gt;
&lt;p&gt;Deleting the workspace and trying a clone. Hmm, that&amp;rsquo;s strange. I&amp;rsquo;m seeing an &lt;code&gt;authentication required&lt;/code&gt; error, yet it looks like the repository was cloned successfully. Let me try and ignore that error.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;warn: error received alongside repo: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Okay, that worked. It&amp;rsquo;s not pretty, but I think it&amp;rsquo;s fine for now.&lt;/p&gt;
&lt;p&gt;Now to commit the new files to the repository. Although partial failures from staging multiple files — one file is stage but the second one fails for some reason — may introduce some problems where the state is not completely settled, so I may also need a method of ensuring the workspace is pristine: no files should exist after cloning or pulling that is not staged. So need to add that first. I don&amp;rsquo;t see a method to do this on the Workspace type, so basically what I&amp;rsquo;ll do is reset hard, and then iterate over the untracked files and remove them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Reset&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetOptions&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Mode&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HardReset&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Status&lt;/span&gt;()  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Worktree&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Untracked&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Remove&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, that&amp;rsquo;s the plan eventually. I&amp;rsquo;ll just log them for now.&lt;/p&gt;
&lt;p&gt;Then it&amp;rsquo;s just a matter of adding files and commit the changes. First attempt at this failed with an &lt;code&gt;entry not found&lt;/code&gt; error. That was just a bad path. Adding files now working, along with committing, and now we&amp;rsquo;re failing at the push. Reason is that unlike all the other Go Git methods, which were pretty high level, this one leaks a bit of the mechanics of Git, requiring the use of a &lt;a href=&#34;https://git-scm.com/book/en/v2/Git-Internals-The-Refspec&#34;&gt;Ref Spec&lt;/a&gt;. I&amp;rsquo;ve just hard coded it to a version which will push the local main branch to the origin main branch.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Push&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PushOptions&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;RemoteURL&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repoURL&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Auth&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BasicAuth&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;Username&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;Password&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;RefSpecs&lt;/span&gt;: []&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RefSpec&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RefSpec&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;+refs/heads/%v:refs/remotes/origin/%v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;)),  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oh, before that, I finding a &lt;code&gt;cannot create empty commit: clean working tree&lt;/code&gt;. I&amp;rsquo;m opening the work tree between staging the files and committing. Is that the problem?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-05-at-21.57.36.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;9ea5d8956f0e4d3138d476569919f9c7&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-05-at-21.57.36.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;cleanshot-2025-10-05-at-21.57.36.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Hmm, no. It might be that I&amp;rsquo;m adding the full path of the file to the index. Running &lt;code&gt;git status&lt;/code&gt; in that repository yielded full path entries, which is very uncharacteristic. Furthermore, trying to unstage them did nothing. I&amp;rsquo;ll remove the repo directory and change the logic to get the relative path of the file before they&amp;rsquo;re added:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;files&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;relPath&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;filepath&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Rel&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;workspace&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;relPath&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Commit&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CommitOptions&lt;/span&gt;{}); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fault&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wrap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oh, it was because the files I was trying to add were already added to the repository from earlier in the day, and they weren&amp;rsquo;t being changed by the job. Let me remove them from the repository and try again.&lt;/p&gt;
&lt;p&gt;Okay, it was that. Commits are now working, although pushes don&amp;rsquo;t seem to be synchronising the commits. When I look at recent changes in Forgejo, it only shows my commits, not the ones created by the service user I made for Blogging Tools. Will try adjusting the refspec to push all heads:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;RefSpecs&lt;/span&gt;: []&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RefSpec&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;+refs/heads/*:refs/remotes/origin/*&amp;#34;&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nah, that didn&amp;rsquo;t help. The method is returning no error, yet it doesn&amp;rsquo;t seem to be synchronising the branches. Will need to learn more about how this all works. But I think that&amp;rsquo;s something for later.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/09/03/can-humanity-create-an-ai.html</link>
      <pubDate>Wed, 03 Sep 2025 08:37:24 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/09/03/can-humanity-create-an-ai.html</guid>
      <description>&lt;p&gt;Can humanity create an AI so intelligent, that it knows not to interrupt with a marketing interstitial when I&amp;rsquo;ve started typing out the prompt? One of the greatest questions of our time, apparently. 😒&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/13/upgraded-my-obsidian-plan-which.html</link>
      <pubDate>Wed, 13 Aug 2025 13:07:41 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/13/upgraded-my-obsidian-plan-which.html</guid>
      <description>&lt;p&gt;Upgraded my Obsidian plan which gives me 10 vaults to sync. I&amp;rsquo;m currently using 2: one for my personal notes and one for TIL Computer. I&amp;rsquo;m contemplating moving my journal to a 3rd. Just need to find uses for the other 7.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/05/some-followup-on-moving-til.html</link>
      <pubDate>Tue, 05 Aug 2025 08:21:56 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/05/some-followup-on-moving-til.html</guid>
      <description>&lt;p&gt;Some follow-up on moving TIL Computer to Quartz. I mentioned that I wanted to eventually set-up a hot-key for activating search. Well, Quartz comes out of the box with that already: press &lt;kbd&gt;Cmd&lt;/kbd&gt;+&lt;kbd&gt;K&lt;/kbd&gt; to open the search. Very nice!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/02/there-was-something-about-the.html</link>
      <pubDate>Sat, 02 Aug 2025 08:16:22 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/02/there-was-something-about-the.html</guid>
      <description>&lt;p&gt;There was something about the appearance of iOS 26 Safari WebViews I wasn&amp;rsquo;t too sure about, and now I know: there&amp;rsquo;s a material transition between the header and the web-page, but there&amp;rsquo;s nothing separating the two. No edge, no gradient. This looks unnatural and, dare I say, a little amateur.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20250802-081137.png&#34; width=&#34;600&#34; height=&#34;243&#34; alt=&#34;Auto-generated description: A blurred web page showing techdirt.com and partial text related to a department.&#34;&gt;

  &lt;blockquote class=&#34;alert alert-selfreply&#34;&gt;
    &lt;p class=&#34;alert-heading&#34;&gt;
      
    &lt;/p&gt;
    &lt;p&gt;&lt;time datetime=&#34;2025-08-01T22:24:09Z&#34; class=&#34;reply-timestamp&#34;&gt;08:24&lt;/time&gt; It may not be so egregious if there&amp;rsquo;s a mark difference in colour between the two, but with something like this that&amp;rsquo;s effectively transparent, it just looks broken.&lt;/p&gt;
  &lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Brief Look At Microsoft&#39;s New CLI Text Editor</title>
      <link>https://lmika.org/2025/06/23/took-a-look-at-microsofts.html</link>
      <pubDate>Mon, 23 Jun 2025 08:09:38 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/06/23/took-a-look-at-microsofts.html</guid>
      <description>&lt;p&gt;Took a look at &lt;a href=&#34;https://devblogs.microsoft.com/commandline/edit-is-now-open-source/&#34;&gt;Microsoft&amp;rsquo;s new CLI text editor&lt;/a&gt;. There&amp;rsquo;s no MacOS version yet but &lt;a href=&#34;https://simonwillison.net/2025/Jun/21/edit-is-now-open-source/#atom-everything&#34;&gt;Simon Willison&lt;/a&gt; has made a Docker image for it, and once I satisfied MacOS&amp;rsquo; insatiable fear that I don&amp;rsquo;t know what I&amp;rsquo;m doing regarding Terminal and Docker&amp;rsquo;s access to other files&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, I managed to launch it.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20250623-075947.png&#34; width=&#34;600&#34; height=&#34;395&#34; alt=&#34;Auto-generated description: A text editor window displays a simple script mentioning Microsoft&#39;s CLI text editor, with menus for File, Edit, View, and Help visible at the top.&#34;&gt;
&lt;p&gt;And yeah, works well. Reminds me of &lt;code&gt;EDIT.EXE&lt;/code&gt; from my DOS using days.&lt;/p&gt;
&lt;p&gt;Since I was running this in Docker, I knew my experience may be slightly off from what&amp;rsquo;s expected. But one thing I would suggest Microsoft doing if they do want to bring this to the Mac is to have a version that works with terminals with light backgrounds: the grey body text is readable but a bit more contrast would be welcome. Also, adding some Emacs/Readline keyboard bindings would be nice. I found myself pressing Option+Left, which I&amp;rsquo;ve mapped to Ctrl+W, to try and go back a word, and I kept getting asked if I wanted to close and save the file. Seems like the keyboard bindings are mapped to what is typical on Windows, which I can understand.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20250623-080114.png&#34; width=&#34;600&#34; height=&#34;787&#34; alt=&#34;Auto-generated description: Two text editor windows display partial menus including file options like New File, with some text in the lower window reading Hello.&#34;&gt;
&lt;figcaption&gt;I think the colours shown on the menu are little buggy.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;But on the whole, I can see this being useful for Windows users that need to duck into a text file when they&amp;rsquo;re using the CLI. I don&amp;rsquo;t think it&amp;rsquo;ll be useful to me — I do know how to quit from Vim — but I frequently need to do this myself whenever I&amp;rsquo;m using the Terminal, and having to switch modes from CLI to GUI always includes a risk of loosing context. So I could imagine appreciating this if I were a Windows users.&lt;/p&gt;
&lt;p&gt;One last thing: I like how they managed to get it down to less than 250kB. A worthy goal for any editor that is not aiming to be feature rich enough to replace your daily driver.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Four prompts in total today. Four!&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/04/22/podcasters-im-begging-you-if.html</link>
      <pubDate>Tue, 22 Apr 2025 07:15:36 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/04/22/podcasters-im-begging-you-if.html</guid>
      <description>&lt;p&gt;Podcasters, I&amp;rsquo;m begging you: if you mention an article in your show, no matter how trivial it may be, put a link to it in the show notes. Take a page from your YouTube making cousins, who fill their video descriptions with links, even to things that seem inconsequential to the topic of the video.&lt;/p&gt;

  &lt;blockquote class=&#34;alert alert-selfreply&#34;&gt;
    &lt;p class=&#34;alert-heading&#34;&gt;
      
    &lt;/p&gt;
    &lt;p&gt;&lt;time datetime=&#34;2025-04-21T21:48:16Z&#34; class=&#34;reply-timestamp&#34;&gt;07:48&lt;/time&gt; Mea culpa: the link that I thought was missing from the show notes was actually there. The author was read out on the show but not the title, which is why I didn&amp;rsquo;t recognise it. So my apologies: I was wrong.&lt;/p&gt;
&lt;p&gt;The post still stands though, for those podcasts that refuse to put any links in the show notes. But most tech/tech adjacent shows do this really well, so I hope you know this post doesn&amp;rsquo;t apply to you. 🙂&lt;/p&gt;
  &lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Airing Of Draft Posts</title>
      <link>https://lmika.org/2025/04/07/airing-on-draft-microposts.html</link>
      <pubDate>Mon, 07 Apr 2025 20:52:38 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/04/07/airing-on-draft-microposts.html</guid>
      <description>&lt;p&gt;I was going through my drafts this evening and I found that I had a number of them. Around 26 in total, created over the last year or so, many of them half-finished or almost finished thoughts. Some are not worth keeping around, and will be going straight to the big /dev/null in the sky. But I found a few that are worth preserving, at least in some form. And since they&amp;rsquo;re no longer worth publishing as separate posts in-and-of-themselves — which is probably why they were kept as drafts — I&amp;rsquo;d thought I&amp;rsquo;d just list them here.&lt;/p&gt;
&lt;p&gt;So here they are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Feb 2024&lt;/strong&gt;: Tried the &lt;a href=&#34;https://12daysofweb.dev/2023/popover-api/&#34;&gt;popover API&lt;/a&gt; for the first time today, and was quite impressed as to how easy it was to use. I needed to add a new modal for Photo Bucket&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, and to be able to do so using only HTML is great.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feb 2024&lt;/strong&gt;: B-movie idea: Two mystical titans — Gozilla and Kong — team up to fight the biggest villain of them all: humanity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mar 2024&lt;/strong&gt;: I read a blog post about travel tips, and the poster recommend &amp;ldquo;tak[ing] one week trips. Turns out, two weeks is just too long.&amp;rdquo; This is where the tannery of distance places a role. Being ask to travel half-way round the world for five or six days at a time is not a great feeling. By the time I recover from jet-lag it&amp;rsquo;s time to head back home again. So I think a week is too short a time for me. Experience has taught me that I can probably go up to three weeks before I start feeling homesick, so I think 2-3 weeks would do it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apr 2024&lt;/strong&gt;: Forgot how much of a pain configuring Linux audio using the command line actually is. Got there in the end with some old hardware that I know works with Ubuntu.&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;May 2024&lt;/strong&gt;: I think the secret to sustainable mocking is to avoid trying to litter your tests with hard-coded inputs and outputs, and instead implement mocks which satisfies the contract with the function under test with naive, in-memory implementations of dependent services.&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sept 2024&lt;/strong&gt;: I don&amp;rsquo;t know how this came about, but there seems like there&amp;rsquo;s an approach to Go code which shuns writing a lot of little private functions that in favour of big ones that inline all the logic. The problem is that this results in a lot of noise. Go&amp;rsquo;s naturally a boiler-plate heavy language, and if a large routine contains both the business logic and all the low-level mechanics of, say, trying get a unique list of things in a slice, it&amp;rsquo;s hard to work out whether that if statement is  handling control logic, business logic, or a mixture of the two. It becomes difficult trying to follow what the routine&amp;rsquo;s trying to accomplish. That&amp;rsquo;s why I still prefer to write a lot of small methods that break up these large routines. It means a deeper stack and more jumping around a file, which does make it easier to loose your place, but what it gives me is the ability to abstract things out so that the business logic is clearer to others.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sept 2024&lt;/strong&gt;: Sometimes I wonder if I should work towards something that can be a good enough showcase of my professional self that can replace my LinkedIn profile. To have &lt;a href=&#34;https://pca.st/upv34u7h?t=5m7s&#34;&gt;something akin to inessential.com&lt;/a&gt;. Not sure what that could be, but I don&amp;rsquo;t feel like I&amp;rsquo;ve got that something just yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sept 2024&lt;/strong&gt;: I may have found a potential use for GitHub Copilot after all. It&amp;rsquo;s not to give insight or ask questions about my own code. After all, I like to think I know my own code. No, it&amp;rsquo;s to provide insight or ask questions about some other open-source project, especially when the documentation is unclear or incomplete.&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oct 2024&lt;/strong&gt;: I&amp;rsquo;m not a blogger, but I play one on the Internet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oct 2024&lt;/strong&gt;: Upgraded Bike to the latest release which has a caret &amp;ldquo;bounce&amp;rdquo; animation when you deselect something, probably to indicate where the carat is at any point. And I absolutely do not like it.&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feb 2025&lt;/strong&gt;: How much did the Vic government pay to host the NFL for a showcase game at the MCG? If they paid more than $0.00, they paid too much.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feb 2025&lt;/strong&gt;: Someone at worked asked if I missed working in Java. I don&amp;rsquo;t think I&amp;rsquo;d say I hate working in Java. I think the language itself is pretty decent. What got me frustrated working it it was all the non-Java aspects of working on enterprise applications intended for application containers. Many of these technologies involved a lot of configuration — usually XML — that provided no easy way to troubleshoot should applications fail to deploy, an almost near certainly when spinning up a new project.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mar 2025&lt;/strong&gt;: Complaining about excessive pop-overs and chat assistants on websites is a perennial topic, but good grief… do these site owners ever use these sites themselves?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mar 2025&lt;/strong&gt;: It seems to me like people are expecting too much from LLMs. I see take-down posts from people using them to get suggestions on how to do something, mocking the suggestions, then concluding that LLMs lack the nuance decision making that comes from an expert. Yeah, of course they do. They&amp;rsquo;re statistics-based averaging machines. They&amp;rsquo;re not following the same thought process that a human will go through.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that&amp;rsquo;s it. Hope this wasn&amp;rsquo;t a significant waste of time.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Since abandoned.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I forget what the hardware was, but I got there, apparently.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;I&amp;rsquo;ve got a whole draft post about mocking that I&amp;rsquo;ve yet to publish, and I&amp;rsquo;m not certain that I will since I don&amp;rsquo;t want to be talking about mocking on this site all the time.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;I&amp;rsquo;ve yet to verify this.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;I haven&amp;rsquo;t used Bike recently, but I probably will still find this distracting.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/03/30/til-cr-button-batteries-are.html</link>
      <pubDate>Sun, 30 Mar 2025 12:47:15 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/03/30/til-cr-button-batteries-are.html</guid>
      <description>&lt;p&gt;TIL: CR2420 button batteries are not the same as CR2032, no matter what your eyes say to you.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Idea for UCL: Methods </title>
      <link>https://lmika.org/2025/02/02/idea-for-ucl-methods.html</link>
      <pubDate>Sun, 02 Feb 2025 14:46:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/02/idea-for-ucl-methods.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;m toying with the idea of adding methods to UCL. This will be similar to the methods that exist in Lua, in that they&amp;rsquo;re essentially functions that pass in the receiver as the first argument, although methods would only be definable by the native layer for the first version.&lt;/p&gt;
&lt;p&gt;Much like Lua though, methods would be invokable using the &lt;code&gt;:&lt;/code&gt; &amp;ldquo;pair&amp;rdquo; operator.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;strs:to-upper &amp;#34;Hello&amp;#34;
--&amp;gt; HELLO
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The idea is to make some of these methods on the types themselves, allowing their use on literals and the result of pipelines, as well as variables:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set h &amp;#34;Hello&amp;#34;
$hello:to-upper
--&amp;gt; HELLO

&amp;#34;Hello&amp;#34;:to-upper
--&amp;gt; HELLO

(cat &amp;#34;Hello &amp;#34; &amp;#34;world&amp;#34;):to-upper
--&amp;gt; HELLO WORLD
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The use of methods would be purely conveience. One could conceive of a type, like a CSV table, where there&amp;rsquo;s a need to perform a series of operations over it.&lt;/p&gt;
&lt;p&gt;The potential downside of using &lt;code&gt;:&lt;/code&gt; is that it may make defining dictionaries more ambiguous. When the parser sees something that could either be a list or a dictionary, it does a scan to search for any pairs that may exist. If so, it treats the literal as a dictionary. But would this work with using &lt;code&gt;:&lt;/code&gt; as the method separator?&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[&amp;#34;Hello&amp;#34;:to-upper]
--&amp;gt; Is this a dictionary {&amp;#34;Hello&amp;#34;:&amp;#34;to-upper&amp;#34;}, or the list [&amp;#34;HELLO&amp;#34;]?
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So that would require something. Might be that I need to require method invocations to occur within parenthesis for list literals.&lt;/p&gt;
&lt;p&gt;Ambiguities like this aside, I&amp;rsquo;m planning to keep it simple for now. Methods will not be user definable within UCL out of the gate, but would be effectively another interface available to native types. For the builtin ones that exist now, it&amp;rsquo;ll most likely be little more than syntactic sugar over the standard library functions:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$hello:to-upper

# equivalent to

strs:to-upper $hello
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Speaking of the standard library, the use of &lt;code&gt;:&lt;/code&gt; as a module-function separator may need some changes. A the moment it&amp;rsquo;s a bit of a hack: when a module is loaded, any procs defined within that module is stored in the environment with the operator: &lt;code&gt;strs:to-upper&lt;/code&gt; for example. The parser is sophisticated enough to recognised &lt;code&gt;:&lt;/code&gt; as a token, but when it parses two or more identifiers separated with &lt;code&gt;:&lt;/code&gt;, it just joins them up into a single identifier.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s needed is something else, maybe using something based on methods. The current idea is to define modules as being some special form of object, where the &amp;ldquo;methods&amp;rdquo; are simply the names of the exported symbol.&lt;/p&gt;
&lt;p&gt;I was curious to know whether the language was capable of doing something similar now. It&amp;rsquo;s conceivable that a similar concept could be drafted with procs returning dictionaries of procs, effectively acting as a namespace for a collection of functions.  So a bit of time in the playground resulted in this experiment:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc fns {
  return [
    upper: (proc { |x| strs:to-upper $x })
    lower: (proc { |x| strs:to-lower $x })
  ]
}

(fns).upper &amp;#34;Hello&amp;#34;
--&amp;gt; HELLO

(fns).lower &amp;#34;Hello&amp;#34;
--&amp;gt; hello
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A good first start. This is theoretically possible in the language that exists at the moment. It&amp;rsquo;s not perfect thought. For one thing, the call to &lt;code&gt;fns&lt;/code&gt; needs to be enclosed in parenthesis in order to invoke it. Leaving them out results in an error:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fns.upper &amp;#34;Hello&amp;#34;
--&amp;gt; error: command is not invokable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The same is true when using variables instead of procs. I tried this experiment again using variables and it came to the same limitations:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set fns [
  upper: (proc { |x| strs:to-upper $x })
  lower: (proc { |x| strs:to-lower $x })
]

($fns).upper &amp;#34;Hello&amp;#34;
--&amp;gt; HELLO

$fns.upper &amp;#34;Hello&amp;#34;
--&amp;gt; error: command is not invokable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Obviously the parser needs to be changed to add additional support for the &lt;code&gt;:&lt;/code&gt; operator, but I also need to fix how strong &lt;code&gt;.&lt;/code&gt; binds to values too.  But I think this may have legs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/01/new-post-on-til-computer.html</link>
      <pubDate>Sat, 01 Feb 2025 08:55:11 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/01/new-post-on-til-computer.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/local-values-in-fiber&#34;&gt;Local Values In Fiber&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/01/07/new-post-on-til-computer.html</link>
      <pubDate>Tue, 07 Jan 2025 13:33:20 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/01/07/new-post-on-til-computer.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/a-way-to-resolve-redelivered-messages-stuck-in-a-nats-jetstream&#34;&gt;A Way To Resolve Redelivered Messages Stuck In A NATS Jetstream&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>2024 Year In Review</title>
      <link>https://lmika.org/2025/01/01/year-in-review.html</link>
      <pubDate>Wed, 01 Jan 2025 10:55:48 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/01/01/year-in-review.html</guid>
      <description>&lt;p&gt;It’s a few minutes to 12:00 PM on the 1st January 2025 when I published this. Thanks to time-zones, that means it’s just about to turn 12:00 AM one hour to the west of Greenwich, meaning that it’s still 2024 in much to the west of the prime meridian. So I’m &lt;em&gt;technically&lt;/em&gt; still within the window of time where I could say I got a year in review post out for 2024.&lt;/p&gt;
&lt;p&gt;Turns out it’s not the first time I’ve used this excuse. Looking at other posts I&amp;rsquo;ve published on the 1st of January, I’ve done this &lt;a href=&#34;https://lmika.org/2023/12/27/year-in-review.html&#34;&gt;twice&lt;/a&gt; &lt;a href=&#34;https://lmika.org/2021/01/01/a-quick-review.html&#34;&gt;before&lt;/a&gt;. And I guess this pattern of posting a year in review on the first of the next year makes some sense: it’s usually a quiet day, with nothing open, and I’m usually a little tired and listless&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;That means there’s usually a large block of time available to me, and despite &lt;a href=&#34;https://lmika.org/2024/12/31/oh-no-what-a-shame.html&#34;&gt;what I wrote yesterday&lt;/a&gt;, it is a good practice to do some reflecting, however brief it may be.&lt;/p&gt;
&lt;p&gt;So I’d figured I’d might as well drag iA Writer out and scribble  out a brief review of the year that was.&lt;/p&gt;
&lt;h2 id=&#34;online-presence&#34;&gt;Online Presence&lt;/h2&gt;
&lt;p&gt;I made a point of wanting to cut down the number of domains I acquire in my &lt;a href=&#34;https://lmika.org/on-this-day/#:~:text=Ultimately%20I%E2%80%99d%20like%20to%20continue%20cutting%20down%20the%20number%20of%20new%20domains%20I%20register.%20It%E2%80%99s%20getting%20to%20be%20an%20expensive%20hobby.&#34;&gt;year in review for 2023&lt;/a&gt;. This is still an ongoing progress, but year-on-year, I’m down 2 domains on net, which is an improvement. 2024 saw the acquisition of 7 new domains, of which 2 I’m using for something, and 1 I plan to keep around:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Domains&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;2024&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;2023&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Registered&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;23&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;25&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;With auto-renew turned on&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;17&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;16&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Currently used for something&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;15&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;13&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Not currently for something but worth keeping&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Want to remove but stuck with it because it’s been shared by others&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;0&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;I’m still trying to keep this blog alive by posting regularly here. I’ve must’ve felt more comfortable with doing so as it’s been a record breaking year, &lt;a href=&#34;https://lmika.org/stats/&#34;&gt;with 840 posts&lt;/a&gt;, beating the previous record by 594 posts. The initial fear of falling out the practice has subsided to one where I find joy in posting here. That’s probably why the post count is so much higher.&lt;/p&gt;
&lt;p&gt;Of course the quality of a blog doesn’t correlate with one’s ability to “post the most”, and I do feel like there have been times where I felt a little blasé about what I write here. I do want to be better here, or at least be a little more conscious about it. But not at the expense of turning this into solely a soapbox/marking/punditry site: there’s plenty of those out there already. So you’ll probably continue to see the cringey, irrelevant, lame, and potentially disposable posts here. I’ll just try to make sure that it’s balanced out with posts that are actually good.&lt;/p&gt;
&lt;p&gt;Some notable posts of the year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/01/05/for-reasons-that.html&#34;&gt;Detecting A Point In a Convex Polygon&lt;/a&gt;: the subject matter is a little dry, but one thing that’s notable about this one was the interactive elements. This took a few weeks to get right and I’m quite happy with how they turned out.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/02/06/golang-debugger-not.html&#34;&gt;Goland Debugger Not Working? Try Upgrading All The Things&lt;/a&gt;: notable as it seems to be the post that got the most traffic from Google.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/05/11/poking-through-some.html&#34;&gt;BASIC.HTM&lt;/a&gt;: notable as it was the first post of mine that appeared on Hacker News.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/07/09/a-tour-of.html&#34;&gt;A Tour Of My New Self-Hosted Code Setup&lt;/a&gt;: longest post to date, with probably the longest bit of spoken audio I’ve published on this site. Getting my hands dirty with editing the narration was an interesting experience.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/09/20/microfiction-get-a.html&#34;&gt;Micro-fiction: Get A Horse&lt;/a&gt;: notable in that this was my first post that was a work of fiction.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One other thing about blogs: I still have that wandering eye for other blogging CMSs. I did start three other blogs, of which two I shut-down and rolled into this one. That just leaves &lt;a href=&#34;https://til.computer/&#34;&gt;one new blog created this year&lt;/a&gt; that I’m planning to keep separate, mainly because I feel the subject matter warrants a dedicated site.&lt;/p&gt;
&lt;h2 id=&#34;projects&#34;&gt;Projects&lt;/h2&gt;
&lt;p&gt;2024 didn’t feel like a big project year, probably because most of the projects I’ve started I kept to myself. But I did manage to release a couple this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://sidebar-for-tiny-theme.lmika.dev/&#34;&gt;Sidebar For Tiny Theme&lt;/a&gt;: This came with the additions for recommendations to Micro.blog, and the addition of sidebars listing those recommendations in a couple of the themes. I use Tiny Theme, which didn’t have a way to do this, so what &lt;a href=&#34;https://lmika.org/2024/03/14/adding-a-sidebar.html&#34;&gt;started as a blog-post&lt;/a&gt; eventually became a Micro.blog plugin. It’s been good seeing this adopted by other bloggers.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cyberburger.lmika.app/&#34;&gt;Cyber Burger&lt;/a&gt;: A Pico-8 game, which I hoped would’ve only taken a few weeks to build. Overall it took 3 months, largely because I spent large stretches of time not working on it. But I’m glad I actually got this finished and released.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The other things I’ve worked on that I built mainly for myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ucl.lmika.dev&#34;&gt;UCL&lt;/a&gt;: A tool-command language, similar to TCL, that I’ve built for work. The state of this is smack-bang in the middle of “sort-of-usable” and I’ll need to spend some effort cleaning this up and documenting this if I ever want this to see wide release. I’m not sure that I want that though. at least not yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blogging Tools&lt;/strong&gt;: A set of tools that help me post here. What started as something to assist with &lt;a href=&#34;https://lmika.org/2024/06/13/blogging-gallery-tool.html&#34;&gt;making photo galleries&lt;/a&gt; has grown to a &lt;a href=&#34;https://lmika.org/2024/12/28/more-fun-today-working-on.html&#34;&gt;suite of tools&lt;/a&gt; dealing with images, audio and video. Really useful for my needs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/05/05/tape-playback-site.html&#34;&gt;Tape Playback Site&lt;/a&gt;: A private site for browsing old cassette tapes that have been digitised. I still have a pile of tapes I need to digitise though (are you getting a sense that I find it hard to finish things? 😀).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/08/22/i-enjoyed-reading.html&#34;&gt;Nano-Journal&lt;/a&gt;: My version of Kev Quirk’s web-based journalling app. After adding Git synchronisation and attachment support, I’ve use this now for all my journalling. It doesn’t do everything that Day One does (off-line support’s a big one) but it does enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, some of the projects that have been abandoned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Photo Bucket&lt;/strong&gt;: My third attempt at making something to publish image galleries online. I think the need for this has been made somewhat redundant with Blogging Tools.&lt;/li&gt;
&lt;li&gt;I also started two interactive fiction stories in &lt;a href=&#34;https://evergreen.ink/&#34;&gt;Evergreen&lt;/a&gt; that I haven’t finished yet. One is close, and I probably should get it done. The other is about halfway finished and probably won’t see the light of day.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;books-and-media&#34;&gt;Books And Media&lt;/h2&gt;
&lt;p&gt;Given that I exceeded my reading goal for 2023, I thought I could push myself a bit more for 2024 and go for finishing 10 books. Sadly, I was nowhere near meeting it. I only got to finishing 4 this year:&lt;/p&gt;
&lt;div class=&#34;bookgoals&#34;&gt;&lt;a href=&#34;https://micro.blog/books/9780473453053&#34;&gt;&lt;img src=&#34;https://cdn.micro.blog/photos/300x/https%3A%2F%2Flmika.org%2Fuploads%2F2024%2Fimg-0157.jpeg&#34; alt=&#34;Useful Not True&#34; width=&#34;100&#34; height=&#34;120&#34; class=&#34;cover&#34;&gt;&lt;/a&gt;&lt;a href=&#34;https://micro.blog/books/9781988575971&#34;&gt;&lt;img src=&#34;https://cdn.micro.blog/photos/300x/https%3A%2F%2Fbooks.google.com%2Fbooks%2Fcontent%3Fid%3DfeWfzgEACAAJ%26printsec%3Dfrontcover%26img%3D1%26zoom%3D5%26source%3Dgbs_api&#34; alt=&#34;Hell Yeah or No&#34; width=&#34;100&#34; height=&#34;120&#34; class=&#34;cover&#34;&gt;&lt;/a&gt;&lt;a href=&#34;https://micro.blog/books/9780007381432&#34;&gt;&lt;img src=&#34;https://cdn.micro.blog/photos/300x/https%3A%2F%2Fbooks.google.com%2Fbooks%2Fcontent%3Fid%3D7notgaTVUFAC%26printsec%3Dfrontcover%26img%3D1%26zoom%3D5%26source%3Dgbs_api&#34; alt=&#34;Magician (The Riftwar Saga, Book 1)&#34; width=&#34;100&#34; height=&#34;120&#34; class=&#34;cover&#34;&gt;&lt;/a&gt;&lt;a href=&#34;https://micro.blog/books/9798218058517&#34;&gt;&lt;img src=&#34;https://cdn.micro.blog/photos/300x/https%3A%2F%2Fimages.isbndb.com%2Fcovers%2F15242713488674.jpg&#34; alt=&#34;Twenty Bits I Learned about Making Websites&#34; width=&#34;100&#34; height=&#34;120&#34; class=&#34;cover&#34;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;(not pictured: Twenty Bits I Learned about Making Websites)&lt;/p&gt;
&lt;p&gt;I think I probably started more books than I’ve finished. Not that I have to finish every book I’ve started, but I think my problem is one of focus. The books I have started could be interesting, and I have plans to finish some of them. I just need to spend more time reading.&lt;/p&gt;
&lt;p&gt;I’m not a movie person but I did manage to watch a few this year. Here are the ones I’ve posted reviews for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/03/24/072940.html&#34;&gt;Dune: Part One&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/09/20/dune-part.html&#34;&gt;Dune: Part Two&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/04/28/mission-impossible-fallout.html&#34;&gt;Mission: Impossible — Fallout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/09/26/office-space.html&#34;&gt;Office Space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/11/06/howls-moving-castle.html&#34;&gt;Howl’s Moving Castle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There was a period of time where I felt burnt out by scripted TV shows, favouring YouTube over much else. I eventually got back into watching a few “high production value” shows, some of which I enjoyed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/11/23/house-of-the.html&#34;&gt;House of the Dragon: Season 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/12/12/house-of-the.html&#34;&gt;House of the Dragon: Season 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/04/04/andor-series.html&#34;&gt;Andor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reacher: Season 2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And some that I enjoyed far less:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/04/28/sugar-season.html&#34;&gt;Sugar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lmika.org/2024/06/25/fallout-season.html&#34;&gt;Fallout&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;onwards-to-2025&#34;&gt;Onwards To 2025&lt;/h2&gt;
&lt;p&gt;I know it’s cliché to look back on the last year and feel pretty crappy about it. And yeah, not every day of your life is going to be great. They’ve been some rotten days in 2024 that I haven’t included in this review (I have written about them so check out the archive if your curious).&lt;/p&gt;
&lt;p&gt;So, was 2024 a good year? Well, I’ll start by saying that it hasn’t been wholly a remarkable year. There’s no one event that I can point to and say “this is what made 2024 great.” Maybe this past year was like that to others, but such events didn’t happen to me&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. And recency bias has made it difficult for me to say there were more good days then bad (the last few months have been rough).&lt;/p&gt;
&lt;p&gt;But I wouldn’t say 2024 was a bad year. Certainly a busy one, with a lot going on. But on balance, I’d say it’s been one of the better ones.&lt;/p&gt;
&lt;p&gt;So that’s it, year in review for 2024 done. Have a happy new year and onwards to a great 2025.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I don’t do much on New Years Eve, electing to go to bed early. Yet, I usually get awaken at midnight for various reasons: fireworks, messages from people wising me a Happy New Year. Last night was no exception.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Well, that’s not entirely true. Becoming an uncle was an example of such an event. But again, such personal news, is currently outside the scope of this post.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/29/we-might-be.html</link>
      <pubDate>Fri, 29 Nov 2024 12:37:31 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/29/we-might-be.html</guid>
      <description>&lt;p&gt;We might be seeing the end of the tunnel with our performance woes at work. I did some profiling with pprof this morning, and saw that a large amount of time was spent in &lt;code&gt;context.Value()&lt;/code&gt;. Which is strange, given that this is just a way of retreving values being carried alongside context instances.&lt;/p&gt;
&lt;p&gt;My initial suspicion was that tracing may have been involved. The tracing library we’re using carries spans — like method calls — in the context. These spans eventually get offloaded to a a service like Jaeger for us to browse.&lt;/p&gt;
&lt;p&gt;We never got tracing working for this service, so I suspect all these spans were building up somewhere. The service wasn’t memory starved, but maybe the library was adding more and more values to the context — which acts like a linked list — and the service was just spending time traversing the list, looking for a values.&lt;/p&gt;
&lt;p&gt;This is just speculation, and warrents further investigation, maybe (might be easier just to spend that effort getting tracing). But after we turned off tracing, we no longer saw the CPU rise to 100%. When we applied load, the CPU remained pretty constant at around 7%.&lt;/p&gt;
&lt;p&gt;So it’s a pretty large signal that tracing not being offloaded is somewhat involved.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/27/new-post-on.html</link>
      <pubDate>Wed, 27 Nov 2024 08:05:30 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/27/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/link-probably-avoid-relying-on-error-codes-to-optimistically-insert-in-postgres&#34;&gt;Link: Probably Avoid Relying On Error Codes To Optimistically Insert In Postgres&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/25/new-post-on.html</link>
      <pubDate>Mon, 25 Nov 2024 07:24:23 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/25/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/dont-use-t-rds-instance-types-for-production&#34;&gt;Don’t Use ‘T’ RDS Instance Types For Production&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/20/new-post-on.html</link>
      <pubDate>Wed, 20 Nov 2024 20:51:16 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/20/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/feedback-of-conditional-updates-in-postgresql&#34;&gt;Feedback Of Conditional Updates In PostgreSQL&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/10/29/new-post-on.html</link>
      <pubDate>Tue, 29 Oct 2024 13:21:36 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/10/29/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/slow-nats-go-subscribers&#34;&gt;Slow NATS Go Subscribers&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/10/26/new-post-on.html</link>
      <pubDate>Sat, 26 Oct 2024 08:00:23 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/10/26/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/psql-techniques&#34;&gt;psql Techniques&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Weekly Update - 20 Oct 2024</title>
      <link>https://lmika.org/2024/10/20/weekly-update-oct.html</link>
      <pubDate>Sun, 20 Oct 2024 20:57:17 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/10/20/weekly-update-oct.html</guid>
      <description>&lt;p&gt;Yeah, I know, it&amp;rsquo;s been a while… again. A lot has been happening in
life and there&amp;rsquo;ve been many days that I haven&amp;rsquo;t done any work on
anything. Things are starting to settle down now, although I am
expecting a few more bumpy days ahead, so we&amp;rsquo;ll see how we go with
project work.&lt;/p&gt;
&lt;h2 id=&#34;cyber-burger&#34;&gt;Cyber Burger&lt;/h2&gt;
&lt;p&gt;Yeah, I&amp;rsquo;m getting pretty tired of this one. I&amp;rsquo;m right in the trough of
despair here, where the initial excitement has worn off and I just want
to finish it. All the remaining work for it has been defined, which I
think helps, and now it&amp;rsquo;s just a matter of plowing through the tasks.&lt;/p&gt;
&lt;p&gt;Recent work done on this is the addition of power-ups and power-downs,
which does things like bump the remain time remaining, give the player a
&amp;ldquo;tractor beam&amp;rdquo; weapon, and clearing the play-area of items, amongst
other things. I&amp;rsquo;m about 2/3 through this one: most of the these
power-ups have been implemented, including the tractor beam. After that,
the remaining work on this project is adjusting the difficulty curve,
improving the main menu, and finally finishing off the website.&lt;/p&gt;
&lt;p&gt;Despite how fatigued I feel about this, it has been fun learning how to
build for the Pico-8. The expect fidelity of the pixel art is within my
skillset, and it&amp;rsquo;s quite impressive what it offers in terms of audio
effects. I haven&amp;rsquo;t explored the music options, and I probably won&amp;rsquo;t
for this game, but something to look at for the next one (if there will
be a next one).&lt;/p&gt;
&lt;h2 id=&#34;coasters&#34;&gt;Coasters&lt;/h2&gt;
&lt;p&gt;This was a bit of a side tangent to get my mind off working on Cyber
Burger. It was a long weekend, and I was passively scrolling through the
sample of Vintage Logos when I thought about recreating a game that was
published in the weekend newspaper we read while I was growing up.
You&amp;rsquo;ll be presented with two images and a clue, and you&amp;rsquo;d have to
guess the word or phrase these alluded to.  For example, if the clue was
&amp;ldquo;insect&amp;rdquo; and the images were:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/a893a53f97.jpg&#34;&gt;
&lt;p&gt;Then one possible answer would be &amp;ldquo;butterfly&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The newspaper used stock photos, like the example above, but I was
hoping to creates logos for fake companies as they would appear as if
printed on cardboard coasters you&amp;rsquo;d find in pubs. The idea is that a
new puzzle would be shown to the user a day, much like the word games
you find online.&lt;/p&gt;
&lt;p&gt;I coded up most of this in a single day and had a working version by the
end of the weekend. I had a very simple Go server which served up a new
puzzle every day at 00:00 UTC. The web frontend was mainly HTML, with
some JavaScript for handling the player&amp;rsquo;s guesses. The puzzles
themselves were defined in a CSV file which was imported into a Sqlite
DB on server startup. This was a strange way of doing things, and was
more of an accident as I was deploying this as a Docker container and I
didn&amp;rsquo;t setup a persistent volume that survived restarts. I had plans of
adding an admin section to the Go server so that I could design puzzles
in advanced.&lt;/p&gt;
&lt;p&gt;Fortunately I resisted this as I ended up only producing twelve puzzles.
Once the original run was completed, I basically bundled them all on a
static site. I was able to keep most of the original HTML and JavaScript
as it was, with only the Go backend being junked. &lt;a href=&#34;https://coasters.lmika.app/&#34;&gt;It&amp;rsquo;s still
online&lt;/a&gt;, and maybe I&amp;rsquo;ll come back to it in the future, maybe using
stock images in place of logos I have to create myself.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/a5bdd76798.jpg&#34;&gt;
&lt;figcaption&gt;The new home page, made after the daily puzzles were at an end.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/a01808911e.jpg&#34;&gt;
&lt;figcaption&gt;Example of one of the puzzles.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So although this was not a long lived side tangent, it was good to be
able to get something finished. I was feeling quite dispirited with
projects that I was just not finishing or releasing. Doing something
small like this, and seeing it through, helped a lot. Maybe that&amp;rsquo;s the
secret in how I can see through something from conception to completion:
get the bulk of it done quickly, deploy it as soon as you can, and keep
it small. That would limit the types of project I can deliver, but hey,
at least I would deliver them.&lt;/p&gt;
&lt;h2 id=&#34;other-stuff&#34;&gt;Other Stuff&lt;/h2&gt;
&lt;p&gt;I added a few things to Ted, my terminal CSV editor, this past week.
Like many of the other features of this project, this was driven mainly
by needs that arise at work. I finally bit the bullet and embraced the
support for headers. The first row of the CSV file is now treated as a
header and is now fixed above the column, instead of the column numbers
which were much less helpful. It should, in theory, be possible to read
a CSV file without headers, but I hardly deal with those files that
it&amp;rsquo;s probably just better to make headers the default.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/b8d691581b.jpg&#34;&gt;
&lt;figcaption&gt;TED with a very simple CSV file showing the headers.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I am also exploring ways to do more actions in bulk, such as add columns
which are derived from the value of other columns. These are all quite
experimental at the moment, and are more or less added in a quick and
dirty fashion; just the bare minimum for what I&amp;rsquo;m trying to achieve. So
not much to say here. A few other changes to other projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nano Journal now keeps the current draft post in browser local
storage, so that it&amp;rsquo;ll no longer get clobbered when you&amp;rsquo;re
redirected to the login screen when trying to post an entry. This was
a source of anxiety for me and meant I was less likely to write
something off the cuff, so I&amp;rsquo;m glad this is now fixed.&lt;/li&gt;
&lt;li&gt;Blogging Tool now has a new app which takes a clip videos produced by
Pocketcasts — which is currently generated in an Instagram-style
vertical video — and crops it as either a square or a letterbox.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/e61945c4f7.jpg&#34;&gt;
&lt;figcaption&gt;The new &#34;Post Podcast Clip&#34; app in Blogging Tools.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/6975b1efac.jpg&#34;&gt;
&lt;figcaption&gt;Also, the app list has been styled a little better. Much more interesting than the bulleted list.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So, a lot of little things done this past month. Nothing worthy of a
report on it&amp;rsquo;s own, but still, it&amp;rsquo;s something.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/10/08/new-post-on.html</link>
      <pubDate>Tue, 08 Oct 2024 13:00:22 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/10/08/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/exporting-a-query-as-a-csv-file-from-postgresql&#34;&gt;Exporting a Query as a CSV File From PostgreSQL&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/09/23/new-post-on.html</link>
      <pubDate>Mon, 23 Sep 2024 20:53:21 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/09/23/new-post-on.html</guid>
      <description>&lt;p&gt;🧑‍💻 New post on TIL Computer: &lt;a href=&#34;https://til.computer/posts/htmx-and-post-redirects&#34;&gt;HTMX And POST Redirects&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Updates</title>
      <link>https://lmika.org/2024/09/08/project-updates.html</link>
      <pubDate>Sun, 08 Sep 2024 17:14:51 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/09/08/project-updates.html</guid>
      <description>&lt;p&gt;Well, it&amp;rsquo;s been three weeks since my last post here, and as hard as it
was to write this update, not writing it would&amp;rsquo;ve been harder. So
let&amp;rsquo;s just skip the preamble and go straight to the update.&lt;/p&gt;
&lt;h2 id=&#34;cyber-burger-that-pico-8-game&#34;&gt;Cyber Burger (That Pico-8 Game)&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m terrible at being coy, I&amp;rsquo;ll just spill the beens. That game I&amp;rsquo;ve
been working on is call Cyber Burger. It&amp;rsquo;s based on a DOS game I saw on
YouTube, and it seemed like a fun project to try and work on, with some
tweaks to the gameplay that I think would make it more forgiving.&lt;/p&gt;
&lt;p&gt;In the weeks since my last update, I finished with the prototypes and
started working on the game itself. The initial set of art is done and a
very simple &amp;ldquo;Game A&amp;rdquo; mode has been implemented. In this mode, you are
shown a burger you&amp;rsquo;ll need to make in your basket. You do so by
shooting down the items flying across the screen and catching them in
order. When you do, you get a &amp;ldquo;tip&amp;rdquo;, which basically amounts to
points. If you make a mistake, you&amp;rsquo;re given a demerit. There are five
rounds in total, and once the round is complete, you move on to the next
one, with maybe slightly different items, or different item speeds,
etc.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/9041d44143.jpg&#34;&gt;
&lt;figcaption&gt;An example play session, with the new graphics.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I managed to make a HTML version of this which plays through round 1. I
gave it to someone at work to play test and the results were… well, they
weren&amp;rsquo;t bad but it didn&amp;rsquo;t set the world on fire.&lt;/p&gt;
&lt;p&gt;I think I&amp;rsquo;m okay with that, but I do need to keep working on it. I
think one thing that would help is adding sound. And I think it might
help me deliver this earlier if I abandoned Mode A and start working on
Mode B, which is closer to an arcade style of game that would allow for
continuous play. These two things, I&amp;rsquo;ll aim to work on this next week.&lt;/p&gt;
&lt;p&gt;Oh, and I&amp;rsquo;ll need to fix the item spawner. Waiting ages for an item you
need is no good.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in giving it a try, you can do so by &lt;a href=&#34;https://cyberger.lmika.app&#34;&gt;following
this link&lt;/a&gt; (it runs in the browser). Feel free to &lt;a href=&#34;https://letterbird.co/lmika&#34;&gt;send any
feedback&lt;/a&gt; you may have.&lt;/p&gt;
&lt;h2 id=&#34;ucl&#34;&gt;UCL&lt;/h2&gt;
&lt;p&gt;The other thing I&amp;rsquo;ve been spending some time on over the last week or
so was UCL. I&amp;rsquo;ve been using that work tool which has this language
quite often recently and I&amp;rsquo;ve been running against a number of bugs and
areas where quality of life changes could be made. Just small things,
such as allowing the &lt;code&gt;foreach&lt;/code&gt; command to be called with a proc name
instead of requiring a block, much like the &lt;code&gt;map&lt;/code&gt; function. Those have
been addressed.&lt;/p&gt;
&lt;p&gt;But the biggest thing I&amp;rsquo;ve been worked on was building out the core
library. I added the following functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The `seq` function, used for generating a sequence of integers. I
like how I built this: it&amp;rsquo;s effectively a virtual list — that can be
indexed, iterated over, or calculated the length of — but does not
take up linear space.&lt;/li&gt;
&lt;li&gt;Comparator functions, like `eq`, `ne`, `gt`, etc. plus settling
on a type system much like Python, where values are strongly type
(can&amp;rsquo;t compare ints to strings) but are also dynamic.&lt;/li&gt;
&lt;li&gt;Arithmetic functions, like `add`, `sub`, etc. which operate on
integers, and the `cat` function use to concatenate strings (these
functions do try to cohere values to the correct type)&lt;/li&gt;
&lt;li&gt;Logical functions, like `and`, `or`, and `not`.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with this, I&amp;rsquo;ve started working through the strings package,
which would add the various string functions you see, like trimming
whitespace, splitting, joining, etc. I&amp;rsquo;ve got trimming and converting
to upper and lower case, and my goal for next week is to add splitting
to and joining from string lists. Once that&amp;rsquo;s done I&amp;rsquo;ll probably put
this on the back-burner again so I can finish off Cyber Burger or work
on something else.&lt;/p&gt;
&lt;p&gt;Just a reminder that there&amp;rsquo;s also a &lt;a href=&#34;https://ucl.lmika.dev&#34;&gt;playground for this too&lt;/a&gt;,
although I apologise for the lack of documentation. I&amp;rsquo;ll need to get
onto that as well.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simplifying UCL</title>
      <link>https://lmika.org/2024/04/23/simplifying-ucl.html</link>
      <pubDate>Tue, 23 Apr 2024 08:21:44 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/22/simplifying-ucl.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been using UCL for several days now in that work tool I mentioned,
and I&amp;rsquo;m wondering if the technical challenge that comes of making a
featureful language is crowding out what I set out to do: making a
useful command language that is easy to embed.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m thinking of making some simplifications.&lt;/p&gt;
&lt;p&gt;The first is to expand the possible use of pipes. To date, the only
thing that can travel through pipes are streams. But many of the
commands I&amp;rsquo;ve been adding simply return slices. This is probably
because there&amp;rsquo;s currently no &amp;ldquo;stream&amp;rdquo; type available to the embedder,
but even if there was, I&amp;rsquo;m wondering if it make sense to allow the
embedder to pass slices, and other types, through pipes as well.&lt;/p&gt;
&lt;p&gt;So, I think I&amp;rsquo;m going to take a page out of Go&amp;rsquo;s template book and
simply have pipes act as syntactic sugar over sequential calls. The goal
is to make the construct &lt;code&gt;a | b&lt;/code&gt; essentially be the same as &lt;code&gt;b (a)&lt;/code&gt;,
where the first argument of &lt;code&gt;b&lt;/code&gt; will be the result of &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As for streams, I&amp;rsquo;m thinking of removing them as a dedicated object
type. Embedders could certainly make analogous types if they need to,
and the language should support that, but the language will no longer
offer first class support for them out of the box. &lt;/p&gt;
&lt;p&gt;The second is to remove any sense of &amp;ldquo;purity&amp;rdquo; of the builtins. You may
recall the indecision I had regarding using anonymous procs with the
&lt;code&gt;map&lt;/code&gt; command:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;I&amp;rsquo;m not sure how I can improve this. I don&amp;rsquo;t really want to add
automatic dereferencing of identities: they&amp;rsquo;re very useful as
unquoted string arguments. I suppose I could add another construct
that would support dereferencing, maybe by enclosing the identifier in
parenthesis.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;I think this is the wrong way to think of this. Again, I&amp;rsquo;m not here to
design a pure implementation of the language. The language is meant to
be easy to use, first and foremost, in an interactive shell, and if that
means sacrificing purity for a &lt;code&gt;map&lt;/code&gt; command that supports blocks,
anonymous procs, and automatic dereferencing of commands just to make it
easier for the user, then I think that&amp;rsquo;s a trade work taking.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s the current thinking as of now.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Imports And The New Model</title>
      <link>https://lmika.org/2024/04/20/imports-and-the.html</link>
      <pubDate>Sat, 20 Apr 2024 15:53:06 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/20/imports-and-the.html</guid>
      <description>&lt;p&gt;Well, I dragged Photo Bucket out today to work on it a bit.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s fallen by the wayside a little, and I&amp;rsquo;ve been wondering if it&amp;rsquo;s
worth continuing work on it. So many things about it that need to be
looked at: the public site looks ugly, as does the admin section;
working with more than a single image is a pain; backup and restore
needs to be added; etc.&lt;/p&gt;
&lt;p&gt;I guess every project goes through this &amp;ldquo;trough of discontent&amp;rdquo; where
the initial excitement has warn off and all you see is a huge laundry
list of things to do.  Not to mention the wandering eye &lt;a href=&#34;https://blog.jim-nielsen.com/2024/netlify-image-cdn/&#34;&gt;looking at the
alternatives&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I do have to stop myself from completely junking it, since it&amp;rsquo;s
actually being used to host the &lt;a href=&#34;https://gallery.folio.red/&#34;&gt;Folio Red Gallery&lt;/a&gt;.  I guess my push
to deploy it has entrapped me (well, that was the idea of pushing it out
there in the first place).&lt;/p&gt;
&lt;p&gt;Anyway, it&amp;rsquo;s been a while (last update &lt;a href=&#34;https://lmika.org/2024/03/09/photo-bucket-update.html&#34;&gt;is here&lt;/a&gt;) and the move to
the new model is progressing. And it&amp;rsquo;s occurred to me that I haven&amp;rsquo;t
actually talked about the new model (well, maybe I have but I forgot
about it).&lt;/p&gt;
&lt;p&gt;Previously, the root model of this data structure is the &lt;code&gt;Store&lt;/code&gt;. All
images belong to a &lt;code&gt;Store&lt;/code&gt;, which is responsible for managing the
physical storage and retrieval of them. These stores can have
sub-stores, which are usually used to hold the images optimised for a
specific use (serving on the web, showing as a thumbnails, etc).
Separate to this was the public site &lt;code&gt;Design&lt;/code&gt; which handed properties of
the public site: how it should look, what the title, and description is,
etc.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/1355eacebd.jpg&#34;&gt;
&lt;figcaption&gt;The &#34;Store&#34; model&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There were some serious issues with this approach: images were owned by
stores, and two images can belong to two different stores, but they all
belonged to the same site. This made uploading confusing: which store
should the image live on? I worked around this by adding the notion of a
&amp;ldquo;primary store&amp;rdquo; but this was just ignoring the problem and defeated
the whole multiple-store approach.&lt;/p&gt;
&lt;p&gt;This is made even worse when one considers which store to use for
serving the images. Down the line I was hoping to support virtual domain
hosting, where one could setup different image sites on different
domains that all pointed to the same instance. So imagine how that would
work: one wanted to view images from &lt;code&gt;alpha.example.com&lt;/code&gt; and another
wanted to view images from &lt;code&gt;beta.example.com&lt;/code&gt;. Should the domains live
on the store? What about the site designs? Where should they live?&lt;/p&gt;
&lt;p&gt;The result was that this model could only really ever support one site
per Photo Bucket instance, requiring multiple deployments for different
sites if one wanted to use a single host for separate photo sites.&lt;/p&gt;
&lt;p&gt;So I re-engineered the model to simplify this dramatically.  Now, the
route object is the &lt;code&gt;Site&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/a927075635.jpg&#34;&gt;
&lt;figcaption&gt;The &#34;Site&#34; model&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Here, the Site owns everything. The images are associated with sites,
not stores. Stores still exist, but their role is now more in-line with
what the sub-stores did. When an image is uploaded, it is stored in
every Store of the site, and each Store will be responsible for
optimising it for a specific use-case. The logic used to determine which
Store to use to fetch the image is still in place but now it can be
assumed that any Store associated with a site will have the image.&lt;/p&gt;
&lt;p&gt;Now the question of which Store an image should be added to is easy: all
the them.&lt;/p&gt;
&lt;p&gt;Non-image data, such as Galleries and Designs now live off the Site as
well, and if virtual hosting is added, so would the domain that serves
that Site.&lt;/p&gt;
&lt;p&gt;At least one site needs to be present at all time, and it&amp;rsquo;s likely most
instances will simply have a single Site for now. But this assumption
solves the upload and hosting resolution issues listed above. And if
multiple site support is needed, a simple site picker can be added to
the admin page (the public pages can will rely on the request hostname).&lt;/p&gt;
&lt;p&gt;This has been added a while ago, and as of today, has been merged to
&lt;code&gt;main&lt;/code&gt;. But I didn&amp;rsquo;t want to deal with writing the data migration logic
for this, so my plan is to simply junk the existing instance and replace
it with the brand new one. But in order to do so, I needed to export the
photos from the old instance, and import them into the new one.&lt;/p&gt;
&lt;p&gt;The export logic has been deployed and I&amp;rsquo;ve made an export it this
morning. Today, the import logic was finished and merged.  Nothing
fancy: like the &lt;code&gt;export&lt;/code&gt; it&amp;rsquo;s only invokable from the command line. But
it&amp;rsquo;ll do the job for now.&lt;/p&gt;
&lt;p&gt;Next steps is to actually deploy this, which I guess will be the
ultimate test. Then, I&amp;rsquo;m hoping to add support for galleries in the
public page so I can separate images on the Folio Red Gallery into
projects. There&amp;rsquo;s still no way to add images in bulk to a gallery.
Maybe this will give me an incentive to do that next.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UCL: First Embed, and Optional Arguments</title>
      <link>https://lmika.org/2024/04/18/ucl-first-embed.html</link>
      <pubDate>Thu, 18 Apr 2024 08:39:12 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/17/ucl-first-embed.html</guid>
      <description>&lt;p&gt;Came up with a name: Universal Control Language: UCL. See, you have TCL;
but what if instead of being used for tools, it can be more universal?
Sounds so much more… universal, am I right? 😀&lt;/p&gt;
&lt;p&gt;Yeah, okay. It&amp;rsquo;s not a great name. But it&amp;rsquo;ll do for now.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;rsquo;ve started integrating this language with the admin tool I&amp;rsquo;m
using at work. This tool I use is the impetus for this whole endeavour.
Up until now, this tool was just a standard CLI command usable from the
shell. But it&amp;rsquo;s not uncommon for me to have to invoke the tool multiple
times in quick succession, and each time I invoke it, it needs to
connect to backend systems, which can take a few seconds. Hence the
reason why I&amp;rsquo;m converting it into a REPL.&lt;/p&gt;
&lt;p&gt;Anyway, I added UCL to the tool, along with a &lt;a href=&#34;https://github.com/chzyer/readline&#34;&gt;readline library&lt;/a&gt;, and
wow, did it feel good to use. So much better than the simple quote-aware
string splitter I&amp;rsquo;d would&amp;rsquo;ve used. And just after I added it, I got a
flurry of requests from my boss to gather some information, and although
the language couldn&amp;rsquo;t quite handle the task due to missing or
unfinished features, I can definitely see the potential there.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m trying my best to only use what will eventually be the public API
to add the tool-specific bindings. The biggest issue is that these
&amp;ldquo;user bindings&amp;rdquo; (i.e. the non-builtins) desperately need support for
producing and consuming streams. They&amp;rsquo;re currently producing Go slices,
which are being passed around as opaque &amp;ldquo;proxy objects&amp;rdquo;, but these
can&amp;rsquo;t be piped into other commands to, say, filter or map. Some other
major limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No commands to actually filter or map. In fact, the whole standard
library needs to be built out.&lt;/li&gt;
&lt;li&gt;No ability to get fields from hashes or lists, including proxy objects
which can act as lists or hashes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One last thing that would be nice is the ability to define optional
arguments. I actually started work on that last night, seeing that it&amp;rsquo;s
relatively easy to build. I&amp;rsquo;m opting for a style that looks like the
switches you&amp;rsquo;d find on the command line, with option names starting
with dashes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;join &amp;quot;a&amp;quot; &amp;quot;b&amp;quot; -separator &amp;quot;,&amp;quot; -reverse
--&amp;gt; b, a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each option can have zero or more arguments, and boolean options can be
represented as just having the switch. This does mean that they&amp;rsquo;d have
to come after the positional arguments, but I think I can live with
that.  Oh, and no syntactic sugar for single-character options: each
option must be separated by whitespace (the grammar actually treats them
as identifiers). In fact, I&amp;rsquo;d like to discourage the use of
single-character option names for these: I prefer the clarity that comes
from having the name written out in full (that said, I wouldn&amp;rsquo;t rule
out support for aliases). This eliminates the need for double dashes, to
distinguish long option names from a cluster of single-character
options, so only the single dash will be used.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll talk more about how the Go bindings look later, after I&amp;rsquo;ve used
them a little more and they&amp;rsquo;re a little more refined.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adding A Sidebar To A Tiny Theme Micro.blog</title>
      <link>https://lmika.org/2024/03/14/adding-a-sidebar.html</link>
      <pubDate>Thu, 14 Mar 2024 07:27:45 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/03/14/adding-a-sidebar.html</guid>
      <description>&lt;p class=&#34;callout&#34;&gt;This is now a standalone Micro.blog Plugin called &lt;a href=&#34;https://sidebar-for-tiny-theme.lmika.dev/&#34;&gt;Sidebar For Tiny Theme&lt;/a&gt; which adds support for this out of the box. The method documented below no longer works, but I&#39;m keeping it here for posterity reason.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d though I&amp;rsquo;d write a little about how I added a sidebar with recommendations to my Tiny Theme&amp;rsquo;ed Micro.blog, for anyone else interested in doing likewise. For an example on how this looks, please &lt;a href=&#34;https://lmika.org/2024/03/13/blogroll-ported-to.html&#34;&gt;see this post&lt;/a&gt;, or just go to the home page of this site.&lt;/p&gt;
&lt;p&gt;I should say that I wrote this in the form of a Micro.blog plugin, just so that I can use a proper text editor. It&amp;rsquo;s not published at the time of this post, but you can find all the code &lt;a href=&#34;https://github.com/lmika/sidebar-for-tinytheme&#34;&gt;on Github&lt;/a&gt;, and although the steps here are slightly different, they should still work using Micro.blog&amp;rsquo;s template designer.&lt;/p&gt;
&lt;p&gt;I started by defining a new Hugo partial for the sidebar. This means that I can choose which page I want it to appear on without any copy-and-paste. You can do so by adding a new template with the name &lt;code&gt;layouts/partials/sidebar.html&lt;/code&gt;, and pasting the following template:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sidebar&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sidebar-cell&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;header&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt;&amp;gt;Recommendations&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;header&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blogroll&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {{ range .Site.Data.blogrolls.recommendations }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ .url }}&amp;#34;&lt;/span&gt;&amp;gt;{{ .name }}: &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;span&lt;/span&gt;&amp;gt;{{ (urls.Parse .url).Hostname }}&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;span&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {{ else }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;p&lt;/span&gt;&amp;gt;No recommendations yet.&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates a sidebar with a single cell containing your Micro.blog recommendations. Down the line I&amp;rsquo;m hoping to add additional cells with things like shoutouts, etc. The styling is not defined for this yet though.&lt;/p&gt;
&lt;p&gt;The sidebar is added to the page using Tiny Theme&amp;rsquo;s &lt;a href=&#34;https://tiny.micro.blog/microhooks/&#34;&gt;microhooks&lt;/a&gt; customisation feature. I set the &lt;code&gt;microhook-after-post-list.html&lt;/code&gt; hook to the following HTML to include the sidebar on the post list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ partial &amp;#34;sidebar.html&amp;#34; . }}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In theory it should be possible to add it to the other pages just by adding the same HTML snippet to the other microhooks (go for the &amp;ldquo;after&amp;rdquo; ones). I haven&amp;rsquo;t tried it myself though so I&amp;rsquo;m not sure how this will look.&lt;/p&gt;
&lt;p&gt;Finally, there&amp;rsquo;s the styling. I added the following CSS which will make the page slightly wider and place the sidebar to the right side of the page:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@&lt;span style=&#34;color:#66d9ef&#34;&gt;media&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;min-width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;776px&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;has&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sidebar&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;max-width&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;em&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;wrapper&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;has&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sidebar&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;grid&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;grid-template-columns&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;minmax&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;em&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;35&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;em&lt;/span&gt;) &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;em&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;column-gap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sidebar&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;font-size&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0.9&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;em&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;line-height&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1.8&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@&lt;span style=&#34;color:#66d9ef&#34;&gt;media&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;max-width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;775px&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sidebar&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sidebar&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;header&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;margin-bottom&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sidebar&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;font-size&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;em&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;var&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;accent1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;blogroll&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;padding-inline&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;blogroll&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;list-style-type&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;none&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;!important&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;blogroll&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;text-decoration&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;var&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;text&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;blogroll&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;span&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;var&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;accent2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This CSS uses the style variables defined by Tiny Theme so they should match the colour scheme of your blog. A page with a sidebar is also wider than one without it. It doesn&amp;rsquo;t change with width of pages that don&amp;rsquo;t have the sidebar (if this isn&amp;rsquo;t your cup of tea, you can remove the &lt;code&gt;:has(div.sidebar)&lt;/code&gt; selector off the &lt;code&gt;body&lt;/code&gt; tag) and the sidebar will not appear on small screens, like a phone in portrait orientation. I&amp;rsquo;m not entirely sure if I like this, and I may eventually make changes. But it&amp;rsquo;s fine for now.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s how the sidebar was added. More to come as I tinker with this down the line.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Photo Bucket Galleries and Using the HTML Popover API</title>
      <link>https://lmika.org/2024/02/19/spent-a-bit.html</link>
      <pubDate>Mon, 19 Feb 2024 22:05:48 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/02/19/spent-a-bit.html</guid>
      <description>&lt;p&gt;Spent a bit more on Photo Bucket this evening. Tonight I started working on galleries, which&amp;rsquo;ll work more or less like albums.&lt;/p&gt;
&lt;p&gt;At the moment you can create a gallery and add a photo to it. Most of the work so far has been backend so the UI is pretty rough. Eventually you&amp;rsquo;ll be able to do things like rearrange photos within galleries, but for the moment they&amp;rsquo;ll just be added to the end.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/galleries.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I did need to add some modals to the UI, such as the New Gallery model that&amp;rsquo;s shown for the gallery name. This gave me the opportunity to try out the new &lt;a href=&#34;https://12daysofweb.dev/2023/popover-api/&#34;&gt;popover API&lt;/a&gt;. And yeah, it does exactly what it says on the tin: add the &lt;code&gt;popover&lt;/code&gt; attribute to an element and it becomes a working popover (at least in the latest version of Vivaldi). Must say it&amp;rsquo;s impressive that this is now possible with HTML alone.&lt;/p&gt;
&lt;p&gt;The initial version of the modals used a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for the popover target. And while that worked, there were some small annoyances. First was that the form within the popover didn&amp;rsquo;t get focus when the popover was displayed. It would be nice to click &amp;ldquo;New&amp;rdquo; and start typing out the gallery name. But this is a small thing that&amp;rsquo;s easily solvable with JavaScript, so it&amp;rsquo;s no big deal.&lt;/p&gt;
&lt;p&gt;The second, slightly larger one, was that dismissing the popover by clicking outside of it will not eat the input. If you were to click a sidebar link while the New Gallery model is opened, you&amp;rsquo;ll end up on that newly selected page. I&amp;rsquo;m not a fan of this. Dismissing the popover feels like its own user gesture, and I fear the user accidentally activating things when all they&amp;rsquo;re trying to do is dismiss the popover (it&amp;rsquo;s not in place now, but I am planning to dim the background when the Create Gallery modal is visible).&lt;/p&gt;
&lt;p&gt;Fortunately, there&amp;rsquo;s a simple solution to this. It turns out that replacing the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element with a &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element would solves both problems. It works seamlessly with the new popover attributes, yet showing the dialog will give focus to the form, and will eat the click when the user dismisses it.&lt;/p&gt;
&lt;p&gt;Perfect. Looks like I&amp;rsquo;ve delayed the need for JavaScript a little longer (it will come eventually; it always will).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/27/apple-watch-series.html</link>
      <pubDate>Wed, 27 Dec 2023 06:33:20 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/27/apple-watch-series.html</guid>
      <description>&lt;p&gt;🔗 &lt;a href=&#34;https://www.macstories.net/linked/apple-watch-series-9-and-ultra-2-ban-takes-effect-apple-appeals/&#34;&gt;Apple Watch Series 9 and Ultra 2 Ban Takes Effect; Apple Appeals&lt;/a&gt;&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;The ITC’s ruling was subject to a potential veto by U.S. President Biden by December 25th, but today, the Office of the U.S. Trade Representative issued a statement that it has decided against vetoing the ITC ruling, meaning that the ruling is now final.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;It seems odd to me that Apple was expecting a reprieve from the White House over this patient dispute with Masimo. Issuing a veto looks like choosing one US company over another. Doesn’t seem like good political optics to me. Maybe it seemed to Apple it was worth a shot. 🤷‍♂️&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/04/03/overhead-someone-say.html</link>
      <pubDate>Mon, 03 Apr 2023 16:35:07 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/04/03/overhead-someone-say.html</guid>
      <description>&lt;p&gt;Overhead someone say, in not so many words, that my UI design for something was sub-par. 😔 Sad, but can&amp;rsquo;t deny that it&amp;rsquo;s true to a degree. Acknowledged area of potential development, I guess.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/03/13/its-amazing-what.html</link>
      <pubDate>Mon, 13 Mar 2023 15:26:26 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/03/13/its-amazing-what.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s amazing what a difference going to the gym can make. This afternoon I was feeling so lethargic, like all I wanted to do was crawl into bed. But I decided to crawl to the gym instead. I really didn&amp;rsquo;t want to, and I usually don&amp;rsquo;t go Mondays so I had an excuse not to. But I&amp;rsquo;m so glad I did because afterwards I got my energy back and I was eager to just do stuff.&lt;/p&gt;
&lt;p&gt;Partial credit goes to coffee. It also helped with getting over the slump.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>To Wordpress Or Not To Wordpress</title>
      <link>https://lmika.org/2023/03/04/im-facing-a.html</link>
      <pubDate>Sat, 04 Mar 2023 09:52:55 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/03/04/im-facing-a.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;m facing a bit of a dilemma.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been asked to setup a new website for someone who wants to stand up a new business. In therory this is something that I can do quite easily. I know HTML and CSS. I&amp;rsquo;ve made a living building backends for web-apps. I do have an undeveloped eye for design, but I like to think I have an idea of the principal of good website usability; and as long as I&amp;rsquo;m not too ambitious, and aim for a &lt;a href=&#34;https://www.patrickrhone.net/how-i-build-websites-a-loose-manifesto/&#34;&gt;minimal usable site&lt;/a&gt;, I can probably put together a simple static website.&lt;/p&gt;
&lt;p&gt;The only problem is that this may not work for the person that I&amp;rsquo;m building a site for. This is someone that has no experience with putting together websites, and if I were to go down the static HTML road, I&amp;rsquo;d probably be on the hook to make changes going forward.&lt;/p&gt;
&lt;p&gt;So the alternative is to use a CRM like Wordpress. That way, once I hand ownership of the site to the client, he could either contract someone else to maintain it going forward or even learn to do it himself.&lt;/p&gt;
&lt;p&gt;Only problem with that is that my experience with Wordpress is quite minimal. I can get around the dashboard no problem, but when it comes to designing or customising themes or (sigh) using the Block editor, I&amp;rsquo;m just as much as a novice as he is. And I&amp;rsquo;m not sure to what degree I can leverage my HTML and CSS skills to style the site. I may be able to change a few things but I&amp;rsquo;d have to do so within the confines of the block templating system.&lt;/p&gt;
&lt;p&gt;So, what to do?&lt;/p&gt;
&lt;p&gt;Maybe the best way forward is to get a sense of how often this person would need the site changed. That&amp;rsquo;s by far the biggest variable here. I only know what he wants at a very superficial sense at this moment. I don&amp;rsquo;t believe it&amp;rsquo;ll need any sort of blog or product catalogue; just a simple landing page with contact details.&lt;/p&gt;
&lt;p&gt;In that case, I&amp;rsquo;m wondering if a static site with just plain HTML and CSS would be enough. That&amp;rsquo;ll be easy enough to put together. It can probably scale with some basic dynamic aspects as well, maybe powered with a simple backend that can regenerate the site.  Maybe something like &lt;a href=&#34;https://carrd.co&#34;&gt;Carrd&lt;/a&gt; could work here as well.&lt;/p&gt;
&lt;p&gt;But the danger is that he&amp;rsquo;ll be locked into using a static site. Any changes would require someone who&amp;rsquo;s versed in HTML and CSS.  Even worse would be a static site with a bit of backend &amp;ldquo;sprinkled in&amp;rdquo;. Then he&amp;rsquo;d be locked into using me. Not sure I like that for his sake or for mine. You read about those developers in &lt;a href=&#34;https://thedailywtf.com&#34;&gt;The Daily WTF&lt;/a&gt; who&amp;rsquo;ve put together a custom backend for a &amp;ldquo;simple website&amp;rdquo; that has grown unwieldily and become a huge mess that someone who inherits it needs to cleanup or take responsibility for. The prospect of being such a developer is not a great one.&lt;/p&gt;
&lt;p&gt;Which is why I&amp;rsquo;m looking at Wordpress, and wondering the pain of learning how to work with it is worth it. I guess it&amp;rsquo;s offsetting the potential future pain (and embarrassment) of transitioning a static site to a proper CRM later.&lt;/p&gt;
&lt;p&gt;So, Leon, which pain is worse?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/03/02/i-was-listening.html</link>
      <pubDate>Thu, 02 Mar 2023 07:41:03 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/03/02/i-was-listening.html</guid>
      <description>&lt;p&gt;I was listening to an episode of &lt;a href=&#34;https://sharptech.fm/&#34;&gt;Sharp Tech&lt;/a&gt; the other day. When the conversation moved on to AI and Ben Thompson&amp;rsquo;s experience with Sydney, an idea for a game came to me.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;ll essentially be a text adventure, but the goal is to try to get a GPT AI to play it. The AI would give you a description of what it &amp;ldquo;sees&amp;rdquo; on their screen, and you have to tell it how to proceed.  You can&amp;rsquo;t enter the commands yourself. Except, you have to use natural language to guide the AI through the game.&lt;/p&gt;
&lt;p&gt;Maybe in the harder difficulty levels the AI could disagree with you and you&amp;rsquo;ll need to convince it to do what you say. Or maybe it&amp;rsquo;ll give you partial information about what it &amp;ldquo;sees&amp;rdquo;. It can say that it sees a castle, but doesn&amp;rsquo;t explain that there&amp;rsquo;s a gate-house as well, and you have to tease this information out of it in order to move forward.&lt;/p&gt;
&lt;p&gt;This sort of harkens back to the time when you&amp;rsquo;re playing a game for the first time with someone that&amp;rsquo;s experienced, and they&amp;rsquo;re telling you what to do&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. Here, you&amp;rsquo;re that experienced player giving assistance, even though you&amp;rsquo;ve never played the game yourself.&lt;/p&gt;
&lt;p&gt;Anyway, free idea for anyone who wants it.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Or maybe those times when you&amp;rsquo;re trying to give tech support over the phone. Those are fun, right? Well, what better way to spend your downtime than playing a simulation of that. 😛&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Spotify Video Follow-up</title>
      <link>https://lmika.org/2023/02/12/spotify-video-followup.html</link>
      <pubDate>Sun, 12 Feb 2023 06:27:37 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/02/12/spotify-video-followup.html</guid>
      <description>&lt;p&gt;Some follow-up from my &lt;a href=&#34;https://lmika.org/2023/02/10/toying-with-the.html&#34;&gt;post about Spotify videos&lt;/a&gt;. I looked into this a little and from what I understand they&amp;rsquo;re not full videos but &amp;ldquo;short looping video clips that play during certain songs,&amp;rdquo; at least according to &lt;a href=&#34;https://www.wikihow.com/Watch-a-Music-Video-on-Spotify&#34;&gt;this website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I guess my initial belief is incorrect. Spotify might have music videos (they&amp;rsquo;re a bunch of articles about them thinking about it in 2020-21) but this looks to be completely different.&lt;/p&gt;
&lt;p&gt;Furthermore, you can turn them off. They&amp;rsquo;re called &amp;ldquo;Canvas Video Clips&amp;rdquo;, and if you go into the preferences of the Android mobile app, sure enough there&amp;rsquo;s a switch for them.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/209b9da92e.png&#34; width=&#34;600&#34; height=&#34;600&#34; alt=&#34;Spotify preference screen with the toggle for Canvas visualisations enabled&#34; /&gt;
&lt;p&gt;Not sure why I missed that when I was looking for that option earlier. I guess because I was looking for a preference with the name &amp;ldquo;video&amp;rdquo; in the label. But this switch seems to work and after I turned it off, this visuals stopped.&lt;/p&gt;
&lt;p&gt;Still toying with the idea of cancelling my subscription for other reasons but at least this is one less concern I have for using the service.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/01/14/finally-bit-the.html</link>
      <pubDate>Sat, 14 Jan 2023 08:21:55 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/01/13/finally-bit-the.html</guid>
      <description>&lt;p&gt;Finally bit the bullet and got scripting working in Dynamo-Browse.  It&amp;rsquo;s officially in the tool, at least in the latest development version. It&amp;rsquo;s finally good to see this feature implemented. I&amp;rsquo;ve been waffling on this for a while, as the last several posts can attest, and it&amp;rsquo;s good to see some decisions made.&lt;/p&gt;
&lt;p&gt;In the end I went with &lt;a href=&#34;https://cloudcmds.github.io/tamarin/&#34;&gt;Tamarin&lt;/a&gt; as the scripting language.  It was fortunate that the maintainer released version 1.0 just as I was about to merge the scripting feature branch into &lt;code&gt;main&lt;/code&gt;.  I&amp;rsquo;ve been trying out the scripting feature at work and so far I&amp;rsquo;ve been finding it to work pretty well. It helps that the language syntax is quite close to Go, but I also think that the room to hide long-running tasks from the user (i.e. no promises everywhere) dramatically simplifies how scripts are written.&lt;/p&gt;
&lt;p&gt;As for the runtime, I decided to have scripts run in a separate go-routine. This means they don&amp;rsquo;t block the main thread and the user can still interact with the tool.  This does mean that the script will need to indicate when a long running process is occurring — which they can do by displaying a message in the status line — but I think this is a good enough tradeoff to avoid having a running script lock-up the app. I still need to add a way for the user to kill long-running scripts (writing a GitHub ticket to do this now).&lt;/p&gt;
&lt;p&gt;At the moment, only one script can run at any one time, sort of like how JavaScript in the browser works.  This is also intentional, as it will prevent a whole bunch of scripts launching go-routines and slowing down the user experience. I think it will help in not introducing any potential synchronisation issues with parallel running scripts accessing the same memory space. No need to build methods in the API to handle this. Will this mean that script performance will be a problem?  Not sure at this stage.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also keeping the API intentionally small at this stage. There are methods to query a DynamoDB table, get access to the result set and the items, and do some basic UI and OS things. I&amp;rsquo;m hoping it&amp;rsquo;s small enough to be useful, at least at the start, without overwhelming script authors or locking me into an API design. I hope to add methods to the API over time.&lt;/p&gt;
&lt;p&gt;Anyway, good to see this committed to.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/01/01/first-post-of.html</link>
      <pubDate>Sun, 01 Jan 2023 07:57:42 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/01/01/first-post-of.html</guid>
      <description>&lt;p&gt;First post of 2023.  If current &lt;a href=&#34;https://xkcd.com/605/&#34;&gt;trends&lt;/a&gt; are to be maintained, I better get posting right away. 😉&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2022/de49e59c97.png&#34; width=&#34;600&#34; height=&#34;543&#34; alt=&#34;Graph of posts on lmika.org per year, trending at an exponential rate&#34; /&gt;
&lt;p&gt;Happy new year.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Audax Toolset Version 0.1.0</title>
      <link>https://lmika.org/2022/10/22/audax-toolset-version.html</link>
      <pubDate>Sat, 22 Oct 2022 10:20:36 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/10/22/audax-toolset-version.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/lmika/audax/releases/tag/v0.1.0&#34;&gt;Audax Toolset version 0.1.0&lt;/a&gt; is finally released and is available on GitHub. This version contains updates to Dynamo-Browse, which is still the only tool in the toolset so far.&lt;/p&gt;
&lt;p&gt;Here are some of the headline features.&lt;/p&gt;
&lt;h2 id=&#34;adjusting-the-displayed-columns&#34;&gt;Adjusting The Displayed Columns&lt;/h2&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/80871cfb0d.jpg&#34; width=&#34;600&#34; height=&#34;436&#34; alt=&#34;The Fields Popup&#34; /&gt;
&lt;p&gt;Consider a table full of items that look like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pk           S    00cae3cc-a9c0-4679-9e3a-032f75c2b506
sk           S    00cae3cc-a9c0-4679-9e3a-032f75c2b506
address      S    3473 Ville stad, Jersey , Mississippi 41540
city         S    Columbus
colors       M    (2 items)
  door       S    MintCream
  front      S    Tan
name         S    Creola Konopelski
officeOpened BOOL False
phone        N    9974834360
ratings      L    (3 items)
  0          N    4
  1          N    3
  2          N    4
web          S    http://www.investorgranular.net/proactive/integrate/open-source
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;rsquo;s say you&amp;rsquo;re interested in seeing the city, the door colour and the website in the main table which, by default, would look something like this:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/cb7da879b6.jpg&#34; width=&#34;600&#34; height=&#34;436&#34; alt=&#34;The before table layout&#34; /&gt;
&lt;p&gt;There are a few reasons why the table is laid out this way. The partition and sort key are always the first two columns, followed by any declared fields that may be used for indices.  This is followed by all the other top-level fields sorted in alphabetical order.  Nested fields are not included as columns, and maps and list fields are summarised with the number of items they hold, e.g. &lt;code&gt;(2 items)&lt;/code&gt;.  This makes it impossible to only view the columns you&amp;rsquo;re interested in.&lt;/p&gt;
&lt;p&gt;Version 0.1.0 now allows you to adjust the columns of the table.  This is done using the &lt;a href=&#34;https://audax.tools/docs/dynamo-browse/getting-around/#adjusting-the-displayed-columns&#34;&gt;Fields Popup&lt;/a&gt;, which can be opened by pressing &lt;kbd&gt;f&lt;/kbd&gt;.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/549d22fab0.jpg&#34; width=&#34;600&#34; height=&#34;436&#34; alt=&#34;Adjusting the columns in the table&#34; /&gt;
&lt;p&gt;While this popup is visible you can show columns, hide them, or move them left or right. You can also add new columns by entering a &lt;a href=&#34;https://audax.tools/docs/dynamo-browse/reference/query-expressions/&#34;&gt;Query Expression&lt;/a&gt;, which can be used to reveal the value of nested fields within the main table.  It&amp;rsquo;s now possible to change the columns of the table to be exactly what you&amp;rsquo;re interested in:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/4a02eb72c8.jpg&#34; width=&#34;600&#34; height=&#34;436&#34; alt=&#34;The after table layout&#34; /&gt;
&lt;h2 id=&#34;read-only-mode-and-result-limits&#34;&gt;Read-only Mode And Result Limits&lt;/h2&gt;
&lt;p&gt;Version 0.1.0 also contains some niceties for reducing the impact of working on production tables.  Dynamo-Browse can now be started in read-only mode using the &lt;code&gt;-ro&lt;/code&gt; flag, which will disable all write operations — a useful feature if you&amp;rsquo;re paranoid about accidentally modifying data on production databases.&lt;/p&gt;
&lt;p&gt;Another new flag is &lt;code&gt;-default-limit&lt;/code&gt; which will change the default number of items returned from scans and queries from 1000 to whatever you want.  This is useful to cut down on the number of read capacity units Dynamo-Browse will use on the initial scans of production tables.&lt;/p&gt;
&lt;p&gt;These settings are also changeable from while Dynamo-Browse using the new &lt;a href=&#34;https://audax.tools/docs/dynamo-browse/reference/commands/#set&#34;&gt;set command&lt;/a&gt;:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/1afbded2a3.jpg&#34; width=&#34;600&#34; height=&#34;436&#34; alt=&#34;Using the set command in Dynamo-Browse&#34; /&gt;
&lt;h2 id=&#34;progress-indicators-and-cancelation&#34;&gt;Progress Indicators And Cancelation&lt;/h2&gt;
&lt;p&gt;Dynamo-Browse now indicates running operations, like scans or queries, with a spinner.  This improves the user experience of prior versions of Dynamo-Browse, which gave no feedback of running operations whatsoever and would simply &amp;ldquo;pop-up&amp;rdquo; the result of such operations in a rather jarring way.&lt;/p&gt;
&lt;p&gt;With this spinner visible in the status bar, it is also now possible to cancel an operation by pressing &lt;kbd&gt;Ctrl-C&lt;/kbd&gt;.  You have the option to view any partial results that were already retrieved at the time.&lt;/p&gt;
&lt;h2 id=&#34;other-changes&#34;&gt;Other Changes&lt;/h2&gt;
&lt;p&gt;Here are some of the other bug-fix and improvements that are also included in this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Audax toolset is now distributed via Homebrew.  Check out the &lt;a href=&#34;https://audax.tools/download/&#34;&gt;Downloads&lt;/a&gt; page for instructions.&lt;/li&gt;
&lt;li&gt;A new &lt;a href=&#34;https://audax.tools/docs/dynamo-browse/reference/commands/#mark&#34;&gt;mark command&lt;/a&gt; to mark all, unmark all, or toggle marked rows.  The &lt;code&gt;unmark&lt;/code&gt; command is now an alias to &lt;code&gt;mark none&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Query expressions involving the partition and sort key of the main table are now executed as a DynamoDB queries, instead of scans.&lt;/li&gt;
&lt;li&gt;The query expression language now supports conjunction, disjunction, and dot references.&lt;/li&gt;
&lt;li&gt;Fixed a bug which was not properly detecting whether MacOS was in light mode.  This was making some highlighted colours hard to see while in dark mode.&lt;/li&gt;
&lt;li&gt;Fixed the table-selection filter, which was never properly working since the initial release.&lt;/li&gt;
&lt;li&gt;Fixed the back-stack service to prevent duplicate views from being pushed.&lt;/li&gt;
&lt;li&gt;Fixed some conditions which were causing seg. faults.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full details of the changes can be &lt;a href=&#34;https://github.com/lmika/audax/releases/tag/v0.1.0&#34;&gt;found on GitHub&lt;/a&gt;.  Details about the various features can also be found in the &lt;a href=&#34;https://audax.tools/docs/dynamo-browse/&#34;&gt;user manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, although it does not touch on any of the features described above, I recorded a introduction video on the basics of using Dynamo-Browse to view items of a DynamoDB table:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/cQnTIg1_tfg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;No promises, but I may record further videos touching on other aspects of the tool in the future.  If that happens, I&amp;rsquo;ll make sure to mention them here.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Or you can like, comment or subscribe on YouTube if that&amp;rsquo;s your thing 😛.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2022/08/25/heres-todays-instalment.html</link>
      <pubDate>Thu, 25 Aug 2022 15:32:40 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/08/25/heres-todays-instalment.html</guid>
      <description>&lt;p&gt;Here&amp;rsquo;s today&amp;rsquo;s instalment of &lt;em&gt;Why Didn&amp;rsquo;t I Think of This Sooner™.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got into the habit of squashing commits before I push them as part of a pull request.  In order to run the command I use to do this — &lt;code&gt;git rebase -i HEAD~n&lt;/code&gt; — I need to know the number of commits I want to squash (this will be the value of &lt;em&gt;n&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Fortunately, I&amp;rsquo;ve got into the habit of prefixing each commit message with the Jira task number.  For example, I may write a commit message with the first line being &lt;code&gt;ABC-123: fixed a bug in the thing&lt;/code&gt;, followed by a more detailed list of changes.  I do for every commit, even for those &amp;ldquo;checkpoint commits&amp;rdquo; I make before changing branches.&lt;/p&gt;
&lt;p&gt;So all I need to do to get the number of commits I need to squash is to simply count up all the commits that start with the Jira task number.  For all this time, the way I do this is to run &lt;code&gt;git log&lt;/code&gt; to open up the history in Vim, and manually count the number of commit messages that began with the particular Jira task number.&lt;/p&gt;
&lt;p&gt;Today, I remembered that I could use a shell pipeline to do the same thing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git log | grep ABC-123 | wc -l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which would save me stack-loads of time and potential mistakes.&lt;/p&gt;
&lt;p&gt;Wish I thought of this sooner. 🤦&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adding A Back-Stack To Dynamo-Browse</title>
      <link>https://lmika.org/2022/08/14/adding-a-backstack.html</link>
      <pubDate>Sun, 14 Aug 2022 10:21:47 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/08/14/adding-a-backstack.html</guid>
      <description>&lt;p&gt;Spent some more time working on dynamo-browse, this time adding a back-stack.  This can be used to go back to the previously viewed table, query or filter by pressing the &lt;kbd&gt;Backspace&lt;/kbd&gt; key, kind of like how a browser back button works.&lt;/p&gt;
&lt;p&gt;This is the first feature that makes use of a workspace, which is a concept that I&amp;rsquo;ve been thinking about since the start of the project.  A workspace is basically a file storing various bits of state  that could be recalled in future launches of the tool.  A workspace is always created, even if one is not explicitly specified by the user.  The workspace filename be set by using the &lt;code&gt;-w&lt;/code&gt; switch on launch, or if one is not specified, then a new workspace filename within the temp directory is generated.  The workspace file itself is a &lt;a href=&#34;https://github.com/coreos/bbolt&#34;&gt;Bolt&lt;/a&gt; database, which is a very simple, embeddable key/value store that uses B-Trees and memory-mapped data access.  I&amp;rsquo;m actually using &lt;a href=&#34;https://github.com/asdine/storm&#34;&gt;StormDB&lt;/a&gt; to access this file, since it provides a nice interface for storing and querying Go structs without having to worry about marshalling or unmarshalling.&lt;/p&gt;
&lt;p&gt;The back-stack consist of view-snapshots, which are essentially records of the currently view table, filter, and query.  The view-snapshots are stored as a linked list, and the back-stack simply pushes new snapshots as the view changes (because this is stored on file, the backlinks are actually ID references and not physical pointers).  I had a bit of trouble getting this right at first.  The initial version actually pushed a snapshot of the previous view before it changed (i.e. a new table was selected or the filter was changed).  But this resulted in a bit of messy implementation, with push calls copied and pasted across the various controllers with various special cases, etc.&lt;/p&gt;
&lt;p&gt;So I went back and reimplemented it so that the top of the back-stack is actually a snapshot of the current view.  Pressing the Backspace key will actually pop the current snapshot, then read the head of the stack and use that to update the view.  This means that there will always be one item in the stack, which bothered me a little at first, but that did make the code easier to implement.&lt;/p&gt;
&lt;p&gt;There is another benefit to this arrangement which just came to me while I was writing this.  Since the current state of the view is always at the top of the stack, I could add the ability to restore the last view when launching dynamo-browse with an existing workspace, saving the user from selecting a table and running their last query.  This will come a bit later.  For the meantime, I need to get this back-stack working with user scripts, so that when a script changes the view, the user can still go back.&lt;/p&gt;
&lt;p&gt;Finally, a shoutout to &lt;a href=&#34;https://github.com/spacewander/boltcli&#34;&gt;boltcli&lt;/a&gt; which is a useful CLI tool for browsing a Bolt database.  This tool has come in handy for debugging this feature.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Release Preparation &amp; Next Steps</title>
      <link>https://lmika.org/2022/07/30/release-preparation-next.html</link>
      <pubDate>Sat, 30 Jul 2022 10:19:56 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/07/30/release-preparation-next.html</guid>
      <description>&lt;p&gt;Finally finished the website for the &lt;a href=&#34;https://audax.tools&#34;&gt;Audax toolset&lt;/a&gt; and cut an initial release (v0.0.2).  I&amp;rsquo;ve also managed to get binary releases for Linux and Windows made. I&amp;rsquo;ve started to work on binary releases for MacOS with the intention of distributing it via Homebrew.  This is completely new to me so I&amp;rsquo;m not sure what progress I&amp;rsquo;ve made so far: probably nothing.  For one thing, I&amp;rsquo;ll need a separate machine to test with, since I&amp;rsquo;ve just been installing them from source on the machine&amp;rsquo;s I&amp;rsquo;ve been using.  Code signing is going to be another thing that will be fun to deal with.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll slip that into a bit of a background task for the moment.  For now, I&amp;rsquo;d like to start work on a feature for &amp;ldquo;dynamo-browse&amp;rdquo; that I&amp;rsquo;ve been thinking of for a while: the ability for users to extend it with scripts.&lt;/p&gt;
&lt;p&gt;Some might argue that it may be a little early for this feature, but I&amp;rsquo;m motivated to do it now as I have a personal need for this, which is navigating amongst a bunch of DynamoDB tables that all store related data.  This is all work related, so can&amp;rsquo;t say too much here.  But if I were just to say that doing this now is a little annoying.  It involves copying and pasting keys, changing tables, and running filters and queries manually: all possible, but very time consuming.  Having the ability to do all this with a single command or keybinding would be so much better.  And since this is all work related, I can&amp;rsquo;t simply modify the source code directly as it will give too much away.  Perfect candidate for using an embedded scripting language.&lt;/p&gt;
&lt;p&gt;So I think that&amp;rsquo;s what I&amp;rsquo;ll start work on next.&lt;/p&gt;
&lt;p&gt;I also need to think about starting work on &amp;ldquo;sqs-browse&amp;rdquo;.  This would be a complete rewrite of what is currently there: which is something that can be used for polling SQS queues and viewing the messages there.  I&amp;rsquo;m hoping for something a little more sophisticated, involving a workspace for writing and pushing messages to queues, along with pulling, saving and routing them from queues.  I haven&amp;rsquo;t got an immediate need for this yet, but I&amp;rsquo;ve come close on occasion so I can&amp;rsquo;t leave this too late.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Time and Money</title>
      <link>https://lmika.org/2022/03/02/time-and-money.html</link>
      <pubDate>Wed, 02 Mar 2022 09:36:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/03/02/time-and-money.html</guid>
      <description>&lt;p&gt;Spending a lot of time in Stripe recently.  It&amp;rsquo;s a fantastic payment gateway and a pleasure to use, compared to something like PayPal which really does show its age.&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s so stressful and confusing dealing with money and subscriptions.  The biggest uncertainty is dealing with anything that takes time.  The problem I&amp;rsquo;m facing now is if the customer chooses to buy something like a database, which is billed a flat fee every month, and then they choose to buy another database during the billing period, can I track that with a single subscription and simply adjust the quantity amount?  My current research suggests that I can, and that Stripe will handle the prorating of partial payments and credits.  They even have a nice API to &lt;a href=&#34;https://stripe.com/docs/billing/subscriptions/prorations#preview-proration&#34;&gt;preview the next invoice&lt;/a&gt; which can be used to show the customer how much they will be paying for.&lt;/p&gt;
&lt;p&gt;But despite all the documentation, test environments, and simulations, I still can&amp;rsquo;t be sure that it will happen in real life, when real money is exchanged in real time.  I guess some real life testing would be required. 💸&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>On Apple&#39;s Media Release Gymnastics</title>
      <link>https://lmika.org/2021/09/06/on-apples-media.html</link>
      <pubDate>Mon, 06 Sep 2021 08:02:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2021/09/06/on-apples-media.html</guid>
      <description>&lt;p&gt;I started listening to &lt;a href=&#34;https://daringfireball.net/thetalkshow/2021/09/01/ep-321&#34;&gt;the latest Talk Show&lt;/a&gt;, where John Gruber and MG Siegler discuss Apple&amp;rsquo;s media release of the class action settlement.  Releasing it to the major media outlets in such a way as to spin the guideline clarification as a concession to developers, even though nothing has actually change, is genius if true.  I imagine that&amp;rsquo;s why Apple&amp;rsquo;s PR department get the big bucks.&lt;/p&gt;
&lt;p&gt;But I wonder if Apple has considered the potential blowback of this approach.  I might be naive here, but I can&amp;rsquo;t help wonder whether these media outlets publishing that Apple hasn&amp;rsquo;t actually conceded  anything will eventually realised that they have been had.  Would that affect the relationship between the two in any way?  Say Apple wants to publish some good news and expect these outlets to maintain the favourable air of their release.  Would they do it?&lt;/p&gt;
&lt;p&gt;Then again, it&amp;rsquo;s most likely that nothing will really change.  There&amp;rsquo;s little trust lost between the two anyway, and if this gymnastics actually happened, Apple knows it.  Also, it sounds like Apple&amp;rsquo;s media release has had the desired effect of reaching those in the US government applying anti-trust pressure on the company.  They probably think it&amp;rsquo;s worth the credibility they have burned with these outlets, if any&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;One thing that seems clear though: this is doing no favours in addressing the trust lost between Apple and their developers, no matter how much clarifying this release does.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I realise that I&amp;rsquo;m probably so far removed from how much the general zeitgeist knows or cares about the relationship between Apple and their developers, so even expecting that these outlets know that they have been had is a huge assumption.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Seeking Out Bad News</title>
      <link>https://lmika.org/2021/07/22/seeking-out-bad.html</link>
      <pubDate>Thu, 22 Jul 2021 09:59:16 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2021/07/22/seeking-out-bad.html</guid>
      <description>&lt;p&gt;Sometimes I wonder if I’m just going out of the way to seek bad news.  Maybe it’s because I think that if I don’t, then a problem will go unaddressed as no-one else is aware of it.&lt;/p&gt;
&lt;p&gt;There’s probably some evolutionary trait to this.  Being the one that hears a predator, and reacts to it before anyone else, is an advantage.  But in this day and age, many of the problems that I have anxiety about is pretty much known by everyone, and addressing it in any meaningful way is beyond my direct control.&lt;/p&gt;
&lt;p&gt;So in the interest for my own mental health, I should cut down on seeking out these stories, do what I can to help with the problem, and just hope that someone who does have the ability to do something substantial knows about it, and can address it in some way.&lt;/p&gt;
&lt;p&gt;While total ignorance is probably not ideal, being up to speed with the woes of the world is probably not healthy either.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2021/02/28/the-interesting-thing.html</link>
      <pubDate>Sun, 28 Feb 2021 12:42:38 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2021/02/28/the-interesting-thing.html</guid>
      <description>&lt;p&gt;The interesting thing about technology breakthroughs is how quickly the shift from the impossible to the banal actually is.  An example of this is machine learning.  This was something that was being researched on since the 1950s, with very little to show for it in terms of practical applications.  This changed very recently, thanks to the growth of computing power.  Now, many of these same techniques are used in many things that are taken for granted, like language translation, image recognition, and surfacing content in algorithmic timelines of social networks (not all utilisation of this technology is good).&lt;/p&gt;
&lt;p&gt;This was one of the first thoughts I had when I heard about the announcement of a &lt;a href=&#34;https://academictimes.com/first-vaccine-to-fully-immunize-against-malaria-builds-on-pandemic-driven-rna-tech/&#34;&gt;potential vaccine for malaria&lt;/a&gt;, which uses very similar technology to the mRNA Covid-19 vaccines.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Empty HTTP Headers in Go</title>
      <link>https://lmika.org/2021/02/09/empty-http-headers.html</link>
      <pubDate>Tue, 09 Feb 2021 20:00:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2021/02/09/empty-http-headers.html</guid>
      <description>&lt;p&gt;Here is a technique for checking for the presence of a HTTP header in a Go request, even if the header has no value.&lt;/p&gt;
&lt;p&gt;If there&amp;rsquo;s a header in a HTTP request that has no value, the parser used by Go will store the header against an empty string value.  This string value is available using the &lt;code&gt;Values()&lt;/code&gt; method: using the &lt;code&gt;Get()&lt;/code&gt; method will not work as that will return an empty string if the header is not present in the request, make it ambiguous for existential tests if empty header values are allowed.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Values()&lt;/code&gt; method can be used to return all the values of a header.  This is useful for cases when a header appears multiple times in a request, but it&amp;rsquo;s also useful here as an empty slice is returned if the header does not appear.  In which case, the way to test for the presence of a header can be done using the following line of code:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;len(req.Header.Values(&amp;#34;My-Header&amp;#34;)) &amp;gt; 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where &amp;ldquo;My-Header&amp;rdquo; is the header you are looking for.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dealing With Errors in Go</title>
      <link>https://lmika.org/2020/12/16/dealing-with-errors.html</link>
      <pubDate>Wed, 16 Dec 2020 13:24:42 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2020/12/16/dealing-with-errors.html</guid>
      <description>&lt;p&gt;There&amp;rsquo;s a lot to like about Go, and I&amp;rsquo;ll happily admit being a huge fan of the language.  But it will be
dishonest of me not to acknowledge that some aspects of programming in Go results in
more code than the equivalent in another language.  My guess is that the best example of this is how Go programs deal with errors.&lt;/p&gt;
&lt;p&gt;For those unfamiliar with how errors work in Go, the short version is that they are just like any other type that you deal with &amp;mdash; like strings and integers &amp;mdash; and they have no special control structure to handle them in any specific way.  This means that, unlike languages that have exceptions,  there is nothing like &lt;em&gt;try/catch&lt;/em&gt; blocks; you are left with the standard control statements that are available.&lt;/p&gt;
&lt;p&gt;The result; you will fall into the practice of having a lot of code that looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doStuff&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doFirstThing&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doOneLastThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;processResult&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is not bad in-and-of-itself, but it does have some shortcomings over the equivalent in languages that use exceptions.  The use of an &lt;em&gt;if&lt;/em&gt; block after every call to a &amp;ldquo;do function&amp;rdquo;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; adds a bit of noise making it harder to separate the happy path from the error handling.  And although the code is technically correct &amp;mdash; whereby the errors are being handled appropriately &amp;mdash; you may come to wonder whether this could be done in a nicer way.&lt;/p&gt;
&lt;p&gt;This post explores some alternatives for dealing with Go errors.  It is by no means exhaustive; it&amp;rsquo;s
just a few patterns I&amp;rsquo;ve found works for me.  It is also by no means suggestive that you even &lt;em&gt;should&lt;/em&gt; use one of the alternatives.  Each use case is different; and one alternative might be a better solution in a particular case, but dramatically worse in another.  Everything in coding, much like life itself, is a tradeoff, and I would suggest being mindful of the potential costs of adopting any one of these options alongside the benefits they may bring.&lt;/p&gt;
&lt;p&gt;With that said, let&amp;rsquo;s look at some alternatives.&lt;/p&gt;
&lt;h2 id=&#34;option-0-keep-it-as-it-is&#34;&gt;Option 0: Keep It As It Is&lt;/h2&gt;
&lt;p&gt;This is probably not an option that you&amp;rsquo;d like to hear, but it is one worth considering if the function is small enough, and you don&amp;rsquo;t have the ability to change the functions you are calling.  As ugly as the code looks, it does have some advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It makes the erroneous path crystal clear: it indicates that any one of these operations can fail with an error, and that it is the job of the function to handle it in some way, even if it is simply returning it as &lt;em&gt;it&amp;rsquo;s&lt;/em&gt; error.&lt;/li&gt;
&lt;li&gt;It makes it reasonably easy to move things around or change how the error is to be handled: if &lt;code&gt;doSecondThing&lt;/code&gt; returns an error that no longer blocks the call to &lt;code&gt;doOneLastThing&lt;/code&gt;, you only need to adjust one &lt;em&gt;if&lt;/em&gt; statements.  This is harder to do in any generic solution you may adapt.&lt;/li&gt;
&lt;li&gt;It provides an incentive to keep functions small: for example, if there is a need to expand the number of operations from 4 to 30, and each operation returns an error that needs to be handled, then that would impart a large enough pressure to refactor the code, and break it up across multiple functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I&amp;rsquo;d recommend considering this as a viable option first, if only briefly.  Spending effort on a solution that may look neater can actually have the opposite effect of making the code less understandable, while also making it harder to maintain.&lt;/p&gt;
&lt;h2 id=&#34;option-1-dont-handle-the-error&#34;&gt;Option 1: Don&amp;rsquo;t Handle The Error&lt;/h2&gt;
&lt;p&gt;No, don&amp;rsquo;t go.  Let me explain.&lt;/p&gt;
&lt;p&gt;This is not a viable option if you are writing code intended for a production setting.  Arguably, if something
can fail in some way, you should handle it.  But I&amp;rsquo;m listing this option here as it is an alternative to the
&lt;em&gt;if&lt;/em&gt; statements above if one of the following scenarios is true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The functions don&amp;rsquo;t return errors: they may be required to implement a type that does, but if it is clear within
the public documentation that they never do, then there is no real need to handle the error.  Some care will need to be
observed in this case though: public documentation is not the the same as an API, and depending on who&amp;rsquo;s maintaining these functions,
it is very possible that, down the line, the implementor takes advantage of the error return type, and starts returning them.&lt;/li&gt;
&lt;li&gt;The error can be safely ignored: this might be test code, or code that is written once, then thrown away.  In these case, it may not be worth your
while adding support for error handling if it provides no real value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adopting this option may make the function look like the following.  It may not be possible to simplify further unless you can actually change the return type of the &amp;ldquo;do functions&amp;rdquo;; in which case, there are no errors that need handling.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doStuff&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doFirstThing&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doOneLastThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// You can probably ignore this error as well, but it&amp;#39;s simpler to just return it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;processResult&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;option-2-use-panic&#34;&gt;Option 2: Use Panic&lt;/h2&gt;
&lt;p&gt;The second option is to use panic to throw the error, and handle it in a single &lt;em&gt;defer&lt;/em&gt; and &lt;em&gt;recover&lt;/em&gt; handler.&lt;/p&gt;
&lt;p&gt;A first draft of this solution may look something like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doStuff&lt;/span&gt;() (&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;isErr&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; recover().(&lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;isErr&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doFirstThing&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doOneLastThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;processResult&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;)	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which is not much better than what we had to begin with.  However, if we can modify the &amp;ldquo;do functions&amp;rdquo; themselves,
we can replace them with versions that panic instead of return an error.  These new &amp;ldquo;must do functions&amp;rdquo; &amp;mdash; so named as
the &lt;code&gt;must&lt;/code&gt; prefix is used to indicate that they will panic if things go wrong &amp;mdash; can bring out the happy path quite clearly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doStuff&lt;/span&gt;() (&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;isErr&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; recover().(&lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;isErr&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mustDoFirstThing&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mustDoSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mustDoOneLastThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;mustProcessResult&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be improved further if the &amp;ldquo;do functions&amp;rdquo; actually return values of the same type.  For that, we
don&amp;rsquo;t actually need to replace the function.  Instead, we can build a function that simply takes the result
and error, and either return the result or panic depending on whether an error was returned&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; { &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;must&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doStuff&lt;/span&gt;() (&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;isErr&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; recover().(&lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;isErr&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;must&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doFirstThing&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;must&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;must&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doOneLastThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;processResult&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will work, but I&amp;rsquo;d argue it&amp;rsquo;s not the best use of panic.  Go panics should be reserved for unexpected errors, instead of as a poor substitute for exceptions.  Instead, I suggest the following option, which provides a nicer API while maintaining the principal of errors as values.&lt;/p&gt;
&lt;h2 id=&#34;option-3-encapsulate-the-error-handling-using-a-dedicated-type&#34;&gt;Option 3: Encapsulate The Error Handling Using A Dedicated Type&lt;/h2&gt;
&lt;p&gt;This is probably my preferred option of the three.  Basically, the idea to track the state of the error using a dedicated type, and wrapping the functions that return errors within methods that don&amp;rsquo;t.  The methods will be defined on the type that is maintaining the error state, and each one will check whether an error has been raised before invoking the wrapped function.  Finally, the struct will offer a way to get the error, so that it can be logged or returned.&lt;/p&gt;
&lt;p&gt;The way this looks in code would be the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DoOperations&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;doOperations&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;DoFirstThing&lt;/span&gt;() (&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;doFirstThing&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;doOperations&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;DoSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;op&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doResult&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;doSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;op&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Likewise for doOneLastThing and processResult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;doOperations&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, the our new function will simply become:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doStuff&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ops&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#a6e22e&#34;&gt;doOperations&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ops&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DoFirstThing&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ops&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DoSecondThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;firstResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ops&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DoOneLastThing&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;secondResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ops&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ProcessResult&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ops&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives us the ability to write a function with the happy-path clearly shown while still maintaining best practices around error handling.&lt;/p&gt;
&lt;p&gt;As nice as this is, the one downside is that this type is specific to the set of operations that we need to deal with.  If this is the only function that needs to perform these operations, then the additional maintenance overhead might not offset the nicer API that this gives you.  But if you find yourself writing out this sequence of operations in a variety of different ways, it may be worth your while to consider this approach.&lt;/p&gt;
&lt;h2 id=&#34;to-be-continued&#34;&gt;To Be Continued&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s very likely that this topic may be revisited as the Go language evolves.  With the design of type parameters imminent, and discussions around adding language features to make error handling nicer in general, additional options may become possible down the line.  But for now, these are the options that seem like current viable alternatives to the function-call-then-if-block pattern seen in a lot of Go code.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;For brevity, I&amp;rsquo;ll be referring to the functions &lt;code&gt;doFirstThing&lt;/code&gt;, &lt;code&gt;doSecondThing&lt;/code&gt; and &lt;code&gt;doOneLastThing&lt;/code&gt; collectively as the &amp;ldquo;do functions&amp;rdquo;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;An example of this in the standard library is the &lt;a href=&#34;https://golang.org/pkg/text/template/#Must&#34;&gt;template.Must()&lt;/a&gt; function.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2020/10/22/over-the-last.html</link>
      <pubDate>Thu, 22 Oct 2020 08:25:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2020/10/22/over-the-last.html</guid>
      <description>&lt;p&gt;Over the last few weeks, while Melbourne has been under lock-down to drive the Covid-19 cases down, the government has been ramping up it&amp;rsquo;s contact tracing infrastructure.  It&amp;rsquo;s been quite flaky at the start but from what I hear now on &lt;a href=&#34;https://www.abc.net.au/radio/programs/coronacast/&#34;&gt;Coronacast&lt;/a&gt; it&amp;rsquo;s in a pretty decent state.  It has delt with outbreaks in both Kilmore and Shepparton, two regional cities here in Victoria.&lt;/p&gt;
&lt;p&gt;Now the real test comes, with the potential of an outbreak at a school here in the north of Melbourne, a few days before restrictions are lifted.  From what I&amp;rsquo;m reading, it looks like the testing and contact tracing infrastructure has moved in quite rapidly.  The school has closed due to a precaution, popup testing sites have been deployed, and some 300 people have been told to self-isolate.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll see how this goes over the coming days.  If all goes well, then I will have greater confidence that the Vic government will be able to handle these outbreaks and we can move to Covid-normal like the rest of the country.&lt;/p&gt;
&lt;p&gt;P.S. Only 5 cases today.  This is a little higher than the 1 to 2 that we&amp;rsquo;ve been experiencing over the last week or so, but still quite good.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Let&#39;s hold the line, Melbourne.  We&#39;ve got this.</title>
      <link>https://lmika.org/2020/09/23/melbournes-day-daily.html</link>
      <pubDate>Wed, 23 Sep 2020 09:17:56 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2020/09/23/melbournes-day-daily.html</guid>
      <description>&lt;p&gt;Today is a good day.  &lt;a href=&#34;https://www.abc.net.au/news/2020-09-23/victoria-coronavirus-cases-to-15-melbourne-average-falls-again/12688292&#34;&gt;Melbourne&amp;rsquo;s 14 day daily Covid-19 case average is now 29.4&lt;/a&gt;, which is beyond the 30 to 50 band required to move to the next stage of reopening.  Seeing the fruits of our collective sacrifice, bringing the daily case numbers from a peak of around 740 in August down to the 11 we saw on Monday, makes me proud to be a Melburnian.&lt;/p&gt;
&lt;p&gt;As much as I like for things to reopen sooner than planned, I think we should hold the line for as long as we possibly can.  The potential prizes for doing so &amp;ndash; the crushing of the virus, the ability to travel interstate again, the chance to eat at restaurants without fear of infection, the chance for a normalish Christmas and summer &amp;ndash; are within reach.  I know that&amp;rsquo;s easy for me to say as someone who has the ability to work from home, and I completely recognise those of us suffering right now being unable to work at all.  But just like the darkest hour is before the dawn, so too will the sweet taste of victory and accomplishment be when we finally crush this virus and meet the rest of the country where they are.  To rush this, to reopen too early, and see our effort thrown away would be upsetting.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s hold out that little bit longer, Melbourne.  We&amp;rsquo;ve got this.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>On Suppression vs. Elimination</title>
      <link>https://lmika.org/2020/07/21/on-suppression-vs.html</link>
      <pubDate>Tue, 21 Jul 2020 10:04:48 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2020/07/21/on-suppression-vs.html</guid>
      <description>&lt;p&gt;It was around the beginning of June, when the number of new Covid-19 cases for Victoria were around 10-20 a day, that there was a general feeling that suppression was working and that it was time to begin opening up.   I will admit I took advantage of the looser restrictions, but I always wondered whether it would be better to remain closed for a little while longer and go for elimination.  This was not the official strategy though: we have testing and tracing up and running and as long as we know where the virus is, we can continue to roll-back restrictions and achieve some semblance of normalcy.&lt;/p&gt;
&lt;p&gt;Fast-forward to today and the daily number of cases is higher than what it was back in March, Melbourne is back under Stage 3 restrictions and I&amp;rsquo;m shopping on-line for masks.&lt;/p&gt;
&lt;p&gt;It seems obvious to me that suppression as a strategy may not be enough.  We may eventually (hopefully) get the virus tamped down once more, but it&amp;rsquo;s still out there and our efforts to keep it at bay are only as &lt;a href=&#34;https://www.abc.net.au/news/2020-07-20/victoria-coronavirus-hotel-quarantine-inquiry-day-1-in-melbourne/12471916?WT.ac=localnews_melbourne&#34;&gt;strong as our weakest link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s time we go for elimination.  It won&amp;rsquo;t be easy, but there are three reasons why I reckon it&amp;rsquo;s worth a shot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most of the other states in the country have effectively achieved eliminated.  Some of them have gone weeks without any new cases, and are cautiously in the process of opening up once again.  However, this can only hold as long as the state borders remain close to Victorians (and possibly soon to the New South Welsh) and I don&amp;rsquo;t see these states willing throwing away their hard won achievement just because the official strategy is suppression.  If Victoria (and NSW) go for elimination, we can meet the other states where they are, making it a no-brainer to open up interstate travel once again, not to mention the trans-Tasman bubble with New Zealand.&lt;/li&gt;
&lt;li&gt;It seems more economically stable over the long term.  &lt;a href=&#34;https://www.abc.net.au/news/2020-07-21/coronavirus-elimination-or-suppression-economy/12472888&#34;&gt;Economic activity is tied to confidence&lt;/a&gt;: people will only go out and spend money if they believe it&amp;rsquo;s safe to do so.  Even when restrictions are rolled-back, I&amp;rsquo;m doubtful people will be quick to flock to cafes and gyms if there&amp;rsquo;s a risk of another wave.  Compare this with elimination: evidence from New Zealand shows that consumer spending is pretty much back to pre-pandemic levels, despite going harder during the initial lock-down.&lt;/li&gt;
&lt;li&gt;It may be a way to win back the public&amp;rsquo;s confidence in the government.  The &lt;a href=&#34;https://www.abc.net.au/news/2020-07-20/daniel-andrews-brand-damaged-coronavirus-fight-victoria/12470896&#34;&gt;Victorian government&lt;/a&gt; has taken a hit in the polls due to the mistakes that caused the current round of lock-downs.  I can see rallying the public around the goal of elimination a way to win them back.  You can even use the current situation as a unique opportunity to achieve this, maybe by saying, &amp;ldquo;given that we&amp;rsquo;re already going through another round of lock-downs, let&amp;rsquo;s go for broke and remain locked down until we&amp;rsquo;ve eliminated this virus once and for all.&amp;rdquo;  Now you have a something that people can work towards, and the feeling that their current sacrifice is not for nothing if (when?) another wave comes through.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m aware that this a post written by someone who is in a position of relative privilege.  I haven&amp;rsquo;t lost my job, and I remain relatively healthy and financially secure.  I also know that it will be expensive and will cause a fair bit more suffering for those with small businesses that will need to shut their doors.  So I recognised that I don&amp;rsquo;t have all the facts, and this may not be feasible at all.  But I also question the feasibility of maintaining a long-term suppression strategy until treatments or a vaccine become available: this is a tricky virus to handle.&lt;/p&gt;
&lt;p&gt;In the end, I guess I&amp;rsquo;m just a bit disappointed by the lack of abition in attempting this as a goal.  It seems advantageous, especially now, to seize the moment and go for making our second round of lock-downs our last.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Don&#39;t Get it Now</title>
      <link>https://lmika.org/2020/03/22/dont-get-it.html</link>
      <pubDate>Sun, 22 Mar 2020 11:00:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2020/03/22/dont-get-it.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s scary times at the moment.  The Corona Virus (SARS-CoV-2 and Covid-19) is raging through Europe at this moment,
with hundreds of people dying in Italy, Spain and France and most of the those countries, along with the US, in
lock-down.  The hospital system is currently not equipped to be able to handle the peak
number of patients that will require intensive care: doctors from Italy, France and New York are telling stories
about how they have to choose who lives and dies, and I&amp;rsquo;m fearful that we may start hearing stories like that here.
There is currently no cure, nor no treatment.  There&amp;rsquo;s been &lt;a href=&#34;https://www.imperial.ac.uk/media/imperial-college/medicine/sph/ide/gida-fellowships/Imperial-College-COVID19-NPI-modelling-16-03-2020.pdf&#34;&gt;models&lt;/a&gt; indicating that even if we take steps to suppress the virus
now, there will be continuous surges in outbreaks until a vaccine is ready in 12 to 18 months, suggesting that
we may need to be in a state of lock-down or at the very least, rigid social distancing until August 2021 at the
latest.  The WHO reckons that a majority of the worlds population will get infected over the next year.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not an doctor, nor an etymologist.  I cannot begin to suggest what we should do as a society.  But I&amp;rsquo;m going
to give a few thoughts as to how I plan to weather this storm.&lt;/p&gt;
&lt;p&gt;I think at this current stage, our enemy, along with the virus, is time.  I hope I don&amp;rsquo;t have to tell you that the
virus is moving through the worlds population now, even as we speak.  But humanity is not standing still either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We are researching the hell out of this thing.  One such example is on Tuesday we
&lt;a href=&#34;https://www.abc.net.au/news/2020-03-17/research-how-bodys-immune-system-fights-coronavirus-covid-19/12059266&#34;&gt;learnt how the body reacts to the virus&lt;/a&gt;, which could help with understanding how best to treat it.  Along with this, there are still some very important
unanswered questions about the [actual death rate and transmission rate](&lt;a href=&#34;https://www.abc.net.au/news/2020-03-22/covid-19-how-deadly-and-contagious-is&#34;&gt;www.abc.net.au/news/2020&amp;hellip;&lt;/a&gt; coronavirus/12068106), as well as [whether heard immunity will work](&lt;a href=&#34;https://www.abc.net.au/news/2020-03-22/doubt-over-contracting-coronavirus-covid&#34;&gt;www.abc.net.au/news/2020&amp;hellip;&lt;/a&gt; 19-twice/12075878), that we&amp;rsquo;ll hopefully get the answer to soon.&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;re &lt;a href=&#34;https://www.abc.net.au/news/health/2020-03-19/coronavirus--drugs-and-vaccines-to-treat-and-prevent-covid-19/12067496&#34;&gt;started clinical trials&lt;/a&gt; of potential treatments, and a vaccine.  It&amp;rsquo;s still early days at the moment, and we probably won&amp;rsquo;t have anything ready soon, but the early indications of this sounds promising.&lt;/li&gt;
&lt;li&gt;And, if the above should fail, we are (should?) be ramping up our hospital capacity to handle the influx of patients,
meaning that if someone should unfortunately die from this, it won&amp;rsquo;t be because they didn&amp;rsquo;t have a bed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So my mantra for the next few months is &lt;em&gt;&amp;ldquo;don&amp;rsquo;t get it now.&amp;rdquo;&lt;/em&gt;  Wait to get infected for as long as you can.  The ideal case
is not to catch it at all, but if we&amp;rsquo;re destine to get infected, best to get in infected later, when some of the
points above have been addressed, instead of sooner when they have not.  This will obviously mean sacrificing things
like going to the gym, going out for coffee, or seeing friends and family.  But I
believe that this is a price worth paying, especially if the alternative is loosing someone you love, or potentially your
own life.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s my current strategy at this time.  I don&amp;rsquo;t know if it will work, and as things develop it may need refining.
But after thinking about this for the previous few weeks, it&amp;rsquo;s
the best strategy I can think of.  And I think it will help me get through this.&lt;/p&gt;
&lt;p&gt;P.S.  A lot of my thoughts on this came from reading &lt;a href=&#34;https://medium.com/@tomaspueyo/coronavirus-the-hammer-and-the-dance-be9337092b56&#34;&gt;this article by Tomas Pueyo&lt;/a&gt;.  He&amp;rsquo;s obviously more knowledgeable about how we should act on this as a whole.  It is worth your time reading this.&lt;/p&gt;
&lt;p&gt;P.P.S. I spoke quite abstractly about the health system, but it&amp;rsquo;s important to remember that these systems are made
up of people: doctors, nurses and paramedics on the front line, along with the researchers, manufacturers and logistics
who support them.  At this time, they are giving their &lt;em&gt;all&lt;/em&gt;, and then some, to help us through this crisis.
Once this is over, I think we owe every single one of these individuals a beer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update On 4th Dec 2022:&lt;/strong&gt; Almost three years since writing this post, I tested positive for Covid-19 for the first time. My symptoms were that of a pretty rough cold which, given what the possibilities could have been when I wrote this post, meant that I weathered the disease pretty well. I finally caught it at a time when vaccines and treatments were wildly available and I was up to date with my inoculations. So all in all, I&amp;rsquo;m glad the whole &amp;ldquo;don&amp;rsquo;t get it now&amp;rdquo; worked in my favour.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>