<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://podcastindex.org/namespace/1.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<atom:link href="https://lmika.org/podcast.xml" rel="self" type="application/rss+xml" />
		<title>Leon Mika</title>
		<link>https://lmika.org/</link>
		<description>Software Developer and occasional writer of music.  Based in Melbourne, Australia.</description>
		<copyright>Copyright 2026 Leon Mika</copyright>
		<itunes:image href="https://micro.blog/lmika/podcast.png" />
		<itunes:category text="Society &amp; Culture">
			<itunes:category text="Personal Journals"></itunes:category>
		</itunes:category>
		<itunes:author>Leon Mika</itunes:author>
		<itunes:explicit>false</itunes:explicit>
		<itunes:owner>
			<itunes:name>Leon Mika</itunes:name>
			<itunes:email></itunes:email>
		</itunes:owner>
		
			<language>en</language>
		
		<lastBuildDate>Sat, 07 Mar 2026 16:05:49 +1100</lastBuildDate>
			<item>
				<title></title>
				<link>https://lmika.org/2026/02/07/opened-logic-pro-for-the.html</link>
				<pubDate>Sat, 07 Feb 2026 10:35:33 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2026/02/07/opened-logic-pro-for-the.html</guid>
				<description><![CDATA[<p>Opened Logic Pro for the first time in a while the other day, and started poking through some loops. Came across some clips of the numbers one through ten spoken in French, and a song sort of developed from there. Please enjoy <em>How to Count in French:</em></p>
<p><audio src="https://cdn.uploads.micro.blog/25293/2026/how-to-count-in-french.mp3" controls="controls" preload="metadata"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2026/how-to-count-in-french.mp3" type="audio/mpeg" length="5352511"></enclosure>
						<itunes:duration>222</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2025/01/08/spotlight-has-stopped-indexing-my.html</link>
				<pubDate>Wed, 08 Jan 2025 08:00:39 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2025/01/08/spotlight-has-stopped-indexing-my.html</guid>
				<description><![CDATA[<p>Spotlight has stopped indexing my apps again. Not sure what broke between now and <a href="https://lmika.org/2024/12/16/might-need-to.html">the last time I tried to fix it</a>, but I think it&rsquo;s time to move to something else. So I&rsquo;m giving Raycast a try. And yeah, so far so good. At least it lets me launch apps.</p>
<p><audio src="https://cdn.uploads.micro.blog/25293/2025/narration-spotlight.mp3" controls="controls" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2025/narration-spotlight.mp3" type="audio/mpeg" length="163070"></enclosure>
						<itunes:duration>14</itunes:duration>
					
				
			</item>
		
			<item>
				<title>A Summer Theme</title>
				<link>https://lmika.org/2024/12/01/a-summer-theme.html</link>
				<pubDate>Sun, 01 Dec 2024 10:12:07 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/12/01/a-summer-theme.html</guid>
				<description><![CDATA[<p>Made a slight tweak to my blog&rsquo;s theme today, to &ldquo;celebrate&rdquo; the start of summer.</p>
<p>I wanted a colour scheme that felt suitable for the season, which usually means hot, dry conditions. I went with one that uses yellow and brown as the primary colours. I suppose red would&rsquo;ve been a more traditional representation of &ldquo;hot&rdquo;, but yellow felt like a better choice to invoke the sensation of dry vegetation. I did want to make it subtle though: it&rsquo;s easy for a really saturated yellow to be quite garish, especially when used as a background.</p>
<p>My original idea was to use yellow as the link colour, but there wasn&rsquo;t a good shade that worked well with a white background that had a decent contract<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. So I pivoted, making the background yellow instead, and throwing in a brown for the link colour. That improved the contrast dramatically, and helped to make the theme a little more interesting.</p>
<div class="img-gallery">
<figure>
<img src="https://lmika.org/uploads/2024/out-20241201-093302.png"
     
      />

  <figcaption>
  
  Original light theme.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/out-20241201-093316.png"
     
      />

  <figcaption>
  
  Summer light theme.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/out-20241201-093330.png"
     
      />

  <figcaption>
  
  Original dark theme.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/out-20241201-093338.png"
     
      />

  <figcaption>
  
  Summer dark theme.
  </figcaption>

</figure>
</div>
<p>One thing I did do was make it conditional to the <code>data-theme</code> attribute in the <code>html</code> tag, leaving me the option of adding a theme picker in the future. If you&rsquo;re interested in the CSS, here it is:</p>
<pre><code>:root[data-theme=&quot;summer&quot;] {
    --background: #FFFEF5;
    --link: #895238;
    --link_visited: #895238;
}

@media (prefers-color-scheme: dark) {
    :root[data-theme=&quot;summer&quot;] {
        --text: #f8f8f2;
        --link: #fce98a;
        --link_visited: #fce98a;
        --background: #30302a;
    }
}
</code></pre>
<p>I plan to keep this theme for the next three months, then look at changing it again when summer turns into autumn. It&rsquo;s probably not a great colour scheme, as I generally don&rsquo;t have the patience for making minute adjustments to get the style &ldquo;just right&rdquo;. I guess it follows on from my feeling of the season: I generally don&rsquo;t like summer and I just want to get it over with. Perhaps doing something small like this is a way of enjoying it a little more.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-summer-theme.mp3" preload="metadata" style="display: none;"></audio></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>It was much easier for the dark theme.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-summer-theme.mp3" type="audio/mpeg" length="1090910"></enclosure>
						<itunes:duration>106</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Phaedra, The lmika Track Arrangement</title>
				<link>https://lmika.org/2024/10/31/phaedra-the-lmika.html</link>
				<pubDate>Thu, 31 Oct 2024 21:06:14 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/10/31/phaedra-the-lmika.html</guid>
				<description><![CDATA[<p>I recently learnt that the version of <a href="https://albumwhale.com/albums/23166">Phaedra</a> I&rsquo;ve been listening to for the past 15 years had not only the wrong track order, but also the wrong track names. This is not entirely surprising, given how this version was… ah, acquired.</p>
<p>But after learning what the order and names should&rsquo;ve been, I think I still prefer my version. And yes, that&rsquo;s probably because I&rsquo;m use to it, but if the official album were to have these names and this order, I think it would actually work really way. I may go so far as to say that if I got a copy of the official album, I&rsquo;d probably change it to match the version I been listening to.</p>
<p>In case your curious, here&rsquo;s how the tracks are named in my version:</p>
<table>
<thead>
<tr>
<th style="text-align:left">Official Version</th>
<th style="text-align:left">lmika Version</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Phaedra</td>
<td style="text-align:left">Mysterious Semblance At The Strand Of Nightmares</td>
</tr>
<tr>
<td style="text-align:left">Mysterious Semblance At The Strand Of Nightmares</td>
<td style="text-align:left">Phaedra</td>
</tr>
<tr>
<td style="text-align:left">Movements Of A Visionary</td>
<td style="text-align:left">Sequent &lsquo;C&rsquo;</td>
</tr>
<tr>
<td style="text-align:left">Sequent &lsquo;C&rsquo;</td>
<td style="text-align:left">Movements Of A Visionary</td>
</tr>
</tbody>
</table>
<p>I&rsquo;m actually a little surprised that my version of <em>Sequent &lsquo;C&rsquo;</em> is officially called <em>Movements Of A Visionary</em> and visa-versa. The name <em>Movements Of A Visionary</em> gives it a more mysterious feeling, which fits well with the small, soft, reverb-filled piece of music that it is. As for the track with has that name officially… well I just assumed the name <em>Sequent &lsquo;C&rsquo;</em> made the most logical sense for a piece of music with a sequencer in the key of C. I don&rsquo;t have an explanation for <em>Phaedra</em> or <em>Semblance</em> other than &ldquo;long piece == long title,&rdquo; but <em>Phaedra</em> just feels like a title that fits better for a piece of music that predominantly features a mellotron.</p>
<p>The tracks in the version I listen too are arrange in the following order:</p>
<table>
<thead>
  <tr>
    <th style="width:50px">No.</th>
    <th>Official Version Name</th>
    <th>lmika Version Name</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>1.</td>
    <td>Sequent 'C'</td>
    <td>Movements Of A Visionary</td>
  </tr>
  <tr>
    <td>2.</td>
    <td>Phaedra</td>
    <td>Mysterious Semblance At The Strand Of Nightmares</td>
  </tr>
   <tr>
    <td>3.</td>
    <td>Mysterious Semblance At The Strand Of Nightmares</td>
    <td>Phaedra</td>
  </tr>
  <tr>
    <td>4.</td>
    <td>Movements Of A Visionary</td>
    <td>Sequent 'C'</td>
  </tr>
</tbody>
</table>
<p>The fact that <em>Phaedra</em> is the first track in the official version make sense, given that on vinyl it would&rsquo;ve taken up an entire side, but I reckon starting the album with a small, soft piece — acting almost like a prelude — whets the appetite for the heavier stuff. This would be track two, which is 17 minutes long, and is quite dynamic in it&rsquo;s contract across the piece. You then climb down from that into what I thought was the title track which — given that it appears as the third one in my version — gives the artists an opportunity to have a something simpler to act as the centrepiece of the album. Then you end with a relatively lively piece with a driving sequencer, that finishes with a decisive C(7) chord, making it clear that the album is now over.</p>
<p>So that&rsquo;s how I&rsquo;d name and arrange the tracks in this album. I don&rsquo;t want to say that Tangerine Dream got it wrong but… they did get it pretty wrong. 😀</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-phaedra.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-phaedra.mp3" type="audio/mpeg" length="7345792"></enclosure>
						<itunes:duration>305</itunes:duration>
					
				
			</item>
		
			<item>
				<title>My Favourite Watch</title>
				<link>https://lmika.org/2024/10/12/my-favourite-watch.html</link>
				<pubDate>Sat, 12 Oct 2024 10:12:51 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/10/12/my-favourite-watch.html</guid>
				<description><![CDATA[<p>Seeing all the nostalgia for digital watches of the &rsquo;90s and early 2000s, following the release of <a href="https://www.theverge.com/2024/10/9/24265964/casio-digital-watch-desk-a158w-clock-japan-retro-vintage">retroest desk clock shaped like a large Casio digital watch</a>, it got me thinking of the watches I owned growing up. I started off as a Casio person but I eventually moved on to Timex watches. I was pretty happy with all the watches I owned, but my favourite was the <a href="https://en.wikipedia.org/wiki/Timex_Datalink#Timex_Datalink_USB">Timex Datalink USB Sports Edition</a>, which stood head and shoulders about the rest.</p>
<figure>
<img src="https://cdn.uploads.micro.blog/25293/2024/timex-datalink-usb.jpg" width="312" height="500" alt="Auto generated description:  A Timex Ironman digital watch with a black strap displays the time as 3:41 and is water-resistant up to 100 metres" class="block-center x-tiny-img">
<figcaption>Source: <a href="https://sites.google.com/site/hamonoaneraea1144/timex-men-s-t53722-ironman-data-link-usb-watch">Hamonoaneraea</a> (site no longer online)</figcaption>
</figure>
<p>Not only was this watch featureful out of the box — having the usual stopwatch, timers, and alarms — it was also reprogrammable. There was some Windows software that allowed you to install new modes and arrange them in the mode menu. I remember a few of these, such as a mode allowing you to browse data arranged in a tree; a simple note taking mode; and a horizontal game of Tetris.</p>
<p>There was also an SDK, allowing you to build new modes in assembly. I remember building a score keeping mode, where you could track points for a game between two or four competitors, with an optional auxiliary counter used to keep track of things like fouls. I also remember building a dice rolling mode, allowing you to roll up to 6 dice, with each dice having between 2 to 9 sides, and the total automatically being displayed to you.</p>
<p>I never used these modes for anything — I&rsquo;m neither sporty nor much of a gamer to have any real need for tracking scores or rolling multiple dice — but they were super fun to build, and I got a fair bit of experience learning assembly from it. And the SDK was pretty well built, with predefined entry points for the mode, reacting to events like button presses, and displaying things on the LCD. The fact that the SDK came with a random-number generator, which wasn&rsquo;t even used with any of the built-in modes, just showed how well Timex thought about what was possible with this watch.</p>
<p>This was the last watch I regularly wore: I&rsquo;ve moved to using phones to keep track of time. But it was a great watch while it lasted.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-favourite-watch.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-favourite-watch.mp3" type="audio/mpeg" length="2922112"></enclosure>
						<itunes:duration>121</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Why I Keep Multiple Blogs</title>
				<link>https://lmika.org/2024/10/12/why-i-keep.html</link>
				<pubDate>Sat, 12 Oct 2024 09:09:35 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/10/12/why-i-keep.html</guid>
				<description><![CDATA[<p>Kev Quirk <a href="https://kevquirk.com/blog/why-have-multiple-blogs">wrote a post yesterday</a> wondering why people have multiple blogs for different topics:</p>
<blockquote>
<p>A few people I follow have multiple blogs that they use for various topics, but I don&rsquo;t really understand why. […] I personally prefer to have a single place where I can get all your stuff. If you&rsquo;re posting about something I&rsquo;m not interested in, I&rsquo;ll just skip over it in my RSS feed. I don&rsquo;t have to read everything in my feed reader.</p>
</blockquote>
<p>I’ve <a href="https://lmika.org/2024/04/16/yeah-honestly-i.html">written about this before</a>, and after taking a quick look at that post, most of those reasons still stand. So if you’ve read that post, you can probably stop reading this one at reason number two (unless you’re listening to the audio narration of this, in which case, please listen on as that last post predated that feature 🙂).</p>
<p>I’m currently keeping four separate blogs: this one, one for <a href="https://lmika.day/">checkins to places I’ve visited</a>, one for <a href="https://til.computer">remembering how to do something for work</a>, and <a href="https://workpad.dev/">one for projects I’m working on</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. This arrangement came about after a few years of spinning out and combining topics to and from a single blog, generally following the tension I felt after publishing something, wondering if that was the right place for it. As strange as it is to say it, this multi-blogging arrangement gives me the lowest amount of tension for writing online.</p>
<p>There are a few reasons for this. First is that for certain topics, I like an easy way to reference posts quickly. This is the primary reason why I keep that work-related reference blog, so that when I&rsquo;m faced with a software-related problem I know I&rsquo;ve seen in the past, I can quickly lookup how I solved it. I’ve tried keeping those posts here, but it was always difficult finding them again amongst all the frequent, day-to-day stuff.</p>
<p>It mainly comes down to the online reading experience. Categories can only do so much, and that’s if I’m categorising posts rigorously, which is not always the case. Here, the posts are displayed in full, encouraging the reader to browse. But for my reference blog, a list of bare links works better for going directly to the post I need.</p>
<p>The second reason is the writing experience. For me, certain CMSes work better for certain types of posts. Micro.blog works well for micro-posts or mid-sized posts like this one, but for longer ones, I prefer the editors of either Scribbles or Pika. I don’t know why this is. Might be because all the code-blocks I tend to use on those blogs are easier to write using a WYSIWYG editor rather than Markdown.</p>
<p>And finally, it’s a good excuse to try out multiple CMSes. I have no rational explanation for this one: it’s an arrangement that costs me more money and requires learning new software. Might be that I just like the variety.</p>
<p>So that’s why I keep multiple blogs. I do recognise that it does make it harder for others to find my writing online, not to mention following along using RSS. But that’s a tradeoff I’m willing to make for a writing and reading arrangement that works better for me. Of course, like I said in my previous post, this might change in due course.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/nartation-multiple-blogs.mp3" preload="metadata" style="display: none;"></audio></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Actually, I have a fifth blog which is for projects I’m working on that I rather keep private. Oh, and a sixth, which is a travel blog that I really should maintain better. Might be that I have a few too many blogs.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/nartation-multiple-blogs.mp3" type="audio/mpeg" length="4461760"></enclosure>
						<itunes:duration>185</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Tools And Libraries I Use For Building Web-Apps In Go</title>
				<link>https://lmika.org/2024/09/28/tools-and-libraries.html</link>
				<pubDate>Sat, 28 Sep 2024 14:45:21 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/09/28/tools-and-libraries.html</guid>
				<description><![CDATA[<p>I think I&rsquo;ve settled on a goto set of tools and libraries for building web-apps in Go. It used to be that I would turn to Buffalo for these sorts of projects, which is sort of a &ldquo;Ruby on Rails but for Go&rdquo; type of web framework. But I get the sense that Buffalo is no longer being maintained. And although it was easy to get a project up and running, it was a little difficult to go beyond the CRUD-like layouts that it would generate (or it didn&rsquo;t motivate me enough to do so). Plus, all that JavaScript bundling… ugh!</p>
<p>Huge pain to upgrade any of that.Since I&rsquo;ve moved away from Buffalo, I&rsquo;m now left to do more of the work up-front, but I think it helps me to be a little more deliberate in how I build something. And after getting burned with Buffalo shutting down, I think it&rsquo;s was time to consider a mix of tools and libraries that would give me the greatest level of code stability while still being relatively quick to get something up and running.</p>
<p>So, here&rsquo;s my goto list of tools and libraries for building web-apps in Go.</p>
<ul>
<li><strong>HTTP Routing:</strong> For this, I use <a href="https://docs.gofiber.io">Fiber</a>. I suppose using Go&rsquo;s builtin HTTP router is probably the best approach, but I do like the utility Fiber gives for doing a lot of the things that go beyond what the standard library provides, such as session management and template rendering. Speaking of…</li>
<li><strong>Server Side Templating:</strong> Nothing fancy here. I just use <a href="https://pkg.go.dev/html/template">Go&rsquo;s template engine</a> via <a href="https://docs.gofiber.io/template/html/">Fiber&rsquo;s Render integration</a>. It has pretty much all I need, so I don&rsquo;t really look at anything else.</li>
<li><strong>Database:</strong> If I need one, then I&rsquo;ll first take a look at <a href="https://www.sqlite.org/index.html">Sqlite</a>. I use the <a href="https://pkg.go.dev/modernc.org/sqlite">modernc.org</a> Sqlite driver, as it doesn&rsquo;t require CGo, making deployments easier (more on that later).  If I need something a bit larger, I tend to go with <a href="https://postgresql.org/">PostgreSQL</a> using the <a href="https://pkg.go.dev/github.com/jackc/pgx/v5">pgx</a> driver. I would also like to use <a href="https://github.com/asdine/storm">StormDB</a> if I could, but it doesn&rsquo;t play well with how I like to deploy things, so I tend to avoid that nowadays.</li>
<li><strong>Database ORM:</strong> I don&rsquo;t really use an ORM (too much PTSD from using the various Java ORMs), but I do use <a href="https://sqlc.dev">sqlc</a> to generate the Go code that interacts with the database. It&rsquo;s not perfect, and it does require some glue code which is tedious to write. But what it does it does really well, and it&rsquo;s better than writing all that SQL marshalling code from scratch.</li>
<li><strong>Database Migration:</strong> I&rsquo;ve tried using <a href="https://github.com/golang-migrate/migrate">golang-migrate</a> before, and we do use it at work for PostgreSQL databases, but it doesn&rsquo;t work well with the modernc.org Sqlite driver. So I ended up <a href="https://lmika.dev/pkg/litemigrate">writing my own</a>. But if it makes sense to use golang-migrate, I will.</li>
<li><strong>JavaScript:</strong> I try to keep my JavaScript usage to a minimum, favouring vanilla JavaScript if I only need a few things. For anything else, I usually turn to <a href="stimulus.hotwired.dev/">Stimulus.js</a>, which adds just enough &ldquo;magic&rdquo; for the slightly more involved pieces of front-end logic. I&rsquo;m also looking at <a href="https://htmx.org/">HTMX</a>, and have tried it for a few things, but I&rsquo;ve yet to use it for a complete project. I use <a href="https://esbuild.github.io">esbuild</a> if I need to bundle my JavaScript, but I&rsquo;m trying to go &ldquo;builderless&rdquo; for most things nowadays, relying on <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap">import maps</a> and just serving the JavaScript as is.</li>
<li><strong>CSS:</strong> Much like JavaScript, I still prefer to use vanilla CSS served directly for most things. I tend to start new projects by importing <a href="https://simplecss.org/">SimpleCSS</a> by Kev Quirk. It makes the HTML look good right out of the gate, but it does make each project look a little &ldquo;samey&rdquo; but that&rsquo;s up to me to address.</li>
<li><strong>Live Reloading:</strong> I&rsquo;ve only recently been a convert to live reloading. I did use it when I was bundling JavaScript, but since moving away from that, plus doing most things server-side anyway, I needed something that would build the entire app. I&rsquo;ve started using <a href="https://github.com/air-verse/air">Air</a> for this, and it&rsquo;s… fine. There are certain things that I don&rsquo;t like about it — particularly that it tends to favour configuration over convention — but it does the job.</li>
<li><strong>Deployment:</strong> Finally, when I&rsquo;m ready to deploy something, I do so using <a href="https://dokku.com/">Dokku</a> running on a Linux server. I bundle the app in a Docker container, mainly using a Go builder image, and a scratch image for the run-time container (this scratch container has nothing else in it, not even libc, which is why I use the modernc.org Sqlite driver). All I need to do is run <code>git push</code>, and Dokku does the rest. Dokku also makes it easy to provision PostgreSQL databases with automated backups, and HTTPS certificates using Lets Encrypt. Deploying something new does involve logging into the remote server to run some commands, but having been burned by PaaS providers that are either too pricy, or not pricy enough to stay in business, I&rsquo;ve found this setup to be the most stable way to host apps.</li>
</ul>
<p>So, that&rsquo;s my setup. It&rsquo;s a collection that&rsquo;s geared towards keeping the code low maintenance, even if it may come at the cost of scalability. I can&rsquo;t tell you anything about that myself: I&rsquo;m not running anything that has more than a couple of users anyway, and most things I&rsquo;m running are only being used by myself. But I think that&rsquo;s a problem for later, should it ever arise.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-go-web-apps.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-go-web-apps.mp3" type="audio/mpeg" length="7607872"></enclosure>
						<itunes:duration>316</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Micro-fiction: Get A Horse</title>
				<link>https://lmika.org/2024/09/20/microfiction-get-a.html</link>
				<pubDate>Fri, 20 Sep 2024 18:37:27 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/09/20/microfiction-get-a.html</guid>
				<description><![CDATA[<p class="callout">Trying something new here. I came up with the concept of this short-story while riding home on the tram yesterday. The rest of it sort-of fell into place when I woke up at 5AM this morning, unable to get back to sleep. Hope you enjoy it.</p>
<p>Josh was riding the scooter on the city footpath, not trying super hard to avoid the other pedestrians. He was going at a speed that was both unsafe and illegal, but it was the only speed he knew that would prevent that horse from showing up. Besides, he had something that he needed to do, and it was only at such reckless speeds that he knew that that thing would work. Well, he didn’t know; but being at his wits&rsquo; end after trying everything else, he had to try this. He picked his target ahead and sped up towards it. Good thing he was wearing his helmet.</p>
<p>Josh never used these sorts of scooters before the collision two weeks ago. He was walking to work that day, when he saw someone on such a scooter coming towards him, helmet on head. The rider was going a ridiculous speed, and Josh tried to get out of his way as he approached, but the scooter driver turned towards him, not slowing down at all. Josh tried again but was not fast enough. The scooter rider ran straight into him and bowled him over onto the footpath. Before Josh could gather himself, the scooter rider slap his helmet onto Josh&rsquo;s head and shouted, “Get a horse!” He got back onto the scooter and sped away.</p>
<p>Josh got up, fighting the various aching muscles from the fall. He dusted himself down, took the helmet from his head and looked at it. It was very uncharacteristic of those worn by scooter riders. Most of them were plastic things, either green or orange, yet this one was grey, made of solid leather that was slightly fuzzy to the touch. Josh looked inside the rim and found some printed writing: <em>Wilkinsons Equestrian Helmet. One side fits all.</em> The <em>one</em> was underlined with some black marker.</p>
<p>Josh put the helmet in his backpack and was about to resume his commute, when he stopped in place. Several metres away, a white horse stood, staring at him. Or at least it looked like a horse. The vision was misty and slightly transparent, giving the sense that it was not real. Yet after blinking and clearing his eyes, it didn’t go away. Josh started to move towards it, and when he was just within arms reach, it disappeared. Josh shook his head, and starting walking. But when he turned the next corner, there it was again: a horse, standing in the middle of the footpath several metres away, staring at him intently.</p>
<p>Since that day that horse has been haunting Josh. On his walk, at his workplace, in his home, even on the tram. Always staring, always outside of reach. Either standing in his path or following close behind him. The vision will go whenever Josh approached it, only to reappear when he turned to look in another direction. Naturally, no one else could see it. When that horse was in a public place, people seemed to instinctively walk around it. Yet when he asked them if they could see it, they had no idea what he was talking about. But Josh couldn’t do anything to stop seeing it. At every waking hour of the day, from when he got out of bed to when he got back in, there it was, always staring. Never looking away.</p>
<p>And he knew it had something to do with that helmet. He tried a few things to dispel the vision, such as leaving the helmet at  home or trying to give to random strangers (who always refused it). Yet nothing worked to clear the vision. That is, nothing other than what had worked on him. Now was the time to test that theory out.</p>
<p>His target was ahead, a man in a business suit walking at a leisurely pace. He had his back to Josh, so he couldn&rsquo;t see Josh turn his scooter towards him and accelerate. The gap between them rapidly closed, and Josh made contact with the man, slowing a little to avoid significant injury, but still fast enough to knock him over. Josh got off the scooter and stood by the man, sprawled on the footpath. Once again the horse appeared, as he knew it would. He looked down to see the man starting to get up. Josh had to go for it now! He took his helmet from his head, slapped it on the man and shouted, “Get a horse!”</p>
<p>Josh got back on the scooter and sped away for few seconds, then stopped to look behind him. He saw the man back on his feet, helmet in hand, looking at it much like Josh did a fortnight ago. He saw the horse as well, but this time it had its back to Josh, staring intently at the man, yet Josh could see that the man hasn&rsquo;t noticed yet. He could see the man put the helmet by side of the road and walk away, turning a corner. The horse was fading from Josh&rsquo;s eyes, yet it was still visible enough for Josh to see it follow the man around the corner, several metres behind.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-get-a-horse.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-get-a-horse.mp3" type="audio/mpeg" length="6788224"></enclosure>
						<itunes:duration>282</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Select Fun From PostgreSQL</title>
				<link>https://lmika.org/2024/09/11/select-fun-from.html</link>
				<pubDate>Wed, 11 Sep 2024 17:20:50 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/09/11/select-fun-from.html</guid>
				<description><![CDATA[<p>Using PostgreSQL these last few months reminds me of just how much fun it is to work with a relational database. DynamoDB is very capable, but I wouldn&rsquo;t call it fun. It&rsquo;s kinda boring, actually. Not that that&rsquo;s a bad thing: one could argue that &ldquo;boring&rdquo; is what you want from a database.</p>
<p>Working with PostgreSQL, on the other hand, has been fun. There&rsquo;s no better word to describe it. It&rsquo;s been quite enjoyable designing new tables and writing SQL statements.</p>
<p>Not sure why this is, but I&rsquo;m guessing it&rsquo;s got something to do with working with a schema. It exercises the same sort of brain muscles<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> as designing data structures or architecting an application. Much more interesting than dealing with a schemaless database, where someone could simply say &ldquo;ah, just shove this object it a DynamoDB table.&rdquo;</p>
<p>It&rsquo;s either that, or just that PostgreSQL has a more powerful query language than what DynamoDB offers. I mean, DynamoDB&rsquo;s query capabilities need to be pretty restricted, thanks to how it stores it&rsquo;s data. That&rsquo;s the price you pay for scale.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-select-fun-from-postgresql.mp3" preload="metadata" style="display: none;"></audio></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>My brain muscles couldn&rsquo;t come up with a better term here. 😄&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-select-fun-from-postgresql.mp3" type="audio/mpeg" length="778454"></enclosure>
						<itunes:duration>68</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/09/09/tried-to-record.html</link>
				<pubDate>Tue, 10 Sep 2024 09:42:50 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/09/09/tried-to-record.html</guid>
				<description><![CDATA[<p>I didn&rsquo;t record narration for <a href="https://lmika.org/2024/09/10/rubberducking-of-config.html">the previous post</a>. It featured a dialog and I needed a scene partner. So I tried recording one with AWS&rsquo;s text-to-speech engine last night, and ah… yeah, it didn&rsquo;t sound as good as I was hoping. I mean, the tech is getting better, but there&rsquo;s still a way to go: that uncanny valley hasn&rsquo;t been bridged yet.</p>
<p>This is probably the best version of what I was able to make. This was using AWS&rsquo;s new-ish &ldquo;Generative&rdquo; voice model. There are only three voices available of this kind in AWS so far. I chose the US English male voice, since it spoke at a rate which, to my ears, is about as close to a speaking rate that I&rsquo;d consider natural:</p>
<p><audio src="https://lmika.org/uploads/2024/dialogue-new.mp3" controls="controls" preload="metadata"></audio></p>
<p><a href="https://lmika.org/transcripts/2024/09/09/1471.html">Transcript</a></p>
<p>I also tried the same exchange out with the &ldquo;Neural&rdquo; engine, which has been around for several years:</p>
<p><audio src="https://cdn.uploads.micro.blog/25293/2024/dialogue-old.mp3" controls="controls" preload="metadata"></audio></p>
<p>The Generative voice model is decent. Still not good enough to fool anyone that I&rsquo;m speaking with a real person, yet it&rsquo;s a lot better than the Neural engine. There&rsquo;s no mistake with that one that I&rsquo;m speaking with a computer.</p>
<p>So, no recorded dialogue, but it was still an interesting exercise. And it&rsquo;s always a little fun playing around with AWS&rsquo;s text-to-speech engine.</p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/dialogue-old.mp3" type="audio/mpeg" length="341632"></enclosure>
						<itunes:duration>14</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/09/02/since-bringing-home-the-ukulele.html</link>
				<pubDate>Mon, 02 Sep 2024 23:49:00 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/09/02/since-bringing-home-the-ukulele.html</guid>
				<description><![CDATA[<p>Since bringing home the ukulele, all I&rsquo;ve been wanting to play on it is tracks from Mike Oldfield&rsquo;s <em>The Voyager</em>. Here&rsquo;s a test recording of my attempt at playing <a href="https://albumwhale.com/albums/21520">She Moves Through the Fair</a>, which I think is actually an Irish folk song. Also wanted to hear how well my webcam mic performs with music.</p>
<p><audio src="https://cdn.uploads.micro.blog/25293/2024/she-moves-through-the-fair.mp3" controls="controls" preload="metadata"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/she-moves-through-the-fair.mp3" type="audio/mpeg" length="1184896"></enclosure>
						<itunes:duration>49</itunes:duration>
					
				
			</item>
		
			<item>
				<title>About Those STOP Messages</title>
				<link>https://lmika.org/2024/08/29/about-those-stop.html</link>
				<pubDate>Thu, 29 Aug 2024 17:26:32 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/08/29/about-those-stop.html</guid>
				<description><![CDATA[<p>John Gruber, discussing <a href="https://daringfireball.net/linked/2024/08/28/messages-political-spam">political spam text messages</a> on Daring Fireball:</p>
<blockquote>
<p>About a month ago I switched tactics and started responding to all such messages with “STOP”. I usually send it in all caps, just like that, because I’m so annoyed. I resisted doing this until a month ago thinking that sending any reply at all to these messages, including the magic “STOP” keyword, would only serve to confirm to the sender that an actual person was looking at the messages sent to my phone number. But this has actually worked. Election season is heating up but I’m getting way way fewer political spam texts now. Your mileage may vary, but for me, the “STOP” response works.</p>
</blockquote>
<p>As someone who use to work for a company that operated a SMS messaging gateway, allow me to provide some insight into how this works. When you send an opt-out keyword — usually &ldquo;STOP<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>&rdquo; although there are a few others — this would be received by our messaging gateway, and your number would be added to an opt-out list for that sender. From that point on, any attempt by that sender to send a message to your number would fail.</p>
<p>Maintaining these opt-out lists is a legal requirement with some significant penalties, so the company I worked for took this quite seriously. Once, the service maintaining this list went down, and we couldn&rsquo;t know whether someone opted-out or not. We actually stopped all messaging completely until we got that service back up again. I still remember that Friday afternoon (naturally, it happened on a Friday afternoon).</p>
<p>Now, if memory serves, there was a way for a sender to be notified when an opt-out occurred. This was mainly for customers that decided to take on the responsibility — and thus legal accountability — of maintaining the opt-out lists themselves. There were a handful of customers that had this enabled, and it was something that we had to enable for them on the backend, but most customers simply delegated this responsibility to us (I can&rsquo;t remember if customers that had this feature off could still receive opt-out notifications).</p>
<p>Finally, there is a way, a variant of the &ldquo;STOP&rdquo; message, in which someone could opt-out of any message sent from our gateway, basically adding themselves to a global opt-out list which applies to everyone. The only way someone could remove themselves from this list was to call support, so I wouldn&rsquo;t recommend doing this unless you know you would never need another 2FA code via SMS again.</p>
<p><strong>Addendum:</strong> The customer never had access to these opt-out lists but I believe they could find out when a message they tried to send was blocked. This is because they would be charged per message sent, and if a message was blocked, they would receive a credit. There was also an API to return the status of a message, so if you knew the message ID, it was possible to call the API to know whether a message was blocked.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-about-those-stop-messages.mp3" preload="metadata" style="display: none;"></audio></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I can&rsquo;t remember if this is case insensitive, although I think it is.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-about-those-stop-messages.mp3" type="audio/mpeg" length="1878254"></enclosure>
						<itunes:duration>163</itunes:duration>
					
				
			</item>
		
			<item>
				<title>My Home Computer Naming Scheme</title>
				<link>https://lmika.org/2024/08/19/my-home-computer.html</link>
				<pubDate>Mon, 19 Aug 2024 14:29:38 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/08/19/my-home-computer.html</guid>
				<description><![CDATA[<p>I enjoyed <a href="https://www.manton.org/2024/08/18/microblog-servers-for.html">Manton&rsquo;s</a> post about the naming scheme he uses for Micro.blog servers. I see these names pop up in the logs when I go to rebuild my blog, each with a Wikipedia link explaining the origins of the name (that&rsquo;s a really nice touch).</p>
<p>Having a server or desktop naming scheme is one of those fun little things to do when working with computers. Growing up we named our home desktops after major characters of Lord of the Rings, such as Bilbo, or Frodo, but I never devised a scheme for myself when I started buying my own computers. I may have kept it up if we were doing likewise at work, but when AWS came onto the scene, the prevailing train of thought was to treat your servers like cattle rather than pets. Granted, it is probably the correct approach, especially when the lifecycle of a particular EC2 instance could be as short as a few minutes.</p>
<p>But a few years ago, after buying a new desktop and setting up the old one to be a home server, and finding that I need a way to name them, I figured now was the time for a naming scheme. Being a fan of A Game of Thrones, both the book and the TV series, I&rsquo;ve came up with one based on the major houses of Westeros.</p>
<p>So, to date, here are the names I&rsquo;ve chosen:</p>
<ul>
<li><strong>Stark</strong> — the M2 Mac Mini that I use as my desktop</li>
<li><strong>Tully</strong> — the Intel Mac Mini that I use as my home server</li>
<li><strong>Crow</strong> — a very old laptop that I occasionally use when I travel (this one is a reference to the Night&rsquo;s Watch)</li>
</ul>
<p>I think at one point I had an Intel Nuc that was called Ghost, a reference to John Snow&rsquo;s dire wolf, but I haven&rsquo;t used that in a while so I may be misremembering things. I also don&rsquo;t have a name for my work laptop: it&rsquo;s simply called &ldquo;work laptop.&rdquo;</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-home-computer-naming-scheme.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-home-computer-naming-scheme.mp3" type="audio/mpeg" length="1152974"></enclosure>
						<itunes:duration>102</itunes:duration>
					
				
			</item>
		
			<item>
				<title>A Follow-Up To Mockless Unit Testing</title>
				<link>https://lmika.org/2024/07/23/a-followup-to.html</link>
				<pubDate>Tue, 23 Jul 2024 18:53:00 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/07/23/a-followup-to.html</guid>
				<description><![CDATA[<p>I&rsquo;m sure everyone&rsquo;s dying to hear how the <a href="https://lmika.org/2024/06/03/some-more-thoughts.html">mockless unit tests</a> are going. It&rsquo;s been almost two months since we started this service, and we&rsquo;re smack bang in the middle of brownfield iterative development: adding new features to existing ones, fixing bugs, etc. So it seems like now is a good time to reflect on whether this approach is working or not.</p>
<p>And so far, it&rsquo;s been going quite well. The amount of code we have to modify when refactoring or changing existing behaviour is dramatically smaller than before. Previously, when a service introduces a new method call, every single test for that service needed to be changed to handle the new mock assertions. Now, in most circumstances, it&rsquo;s only one or maybe two tests that need to change. This has made maintenance so much easier, and although I&rsquo;m not sure it mades us any faster, it just feels faster. Probably because there&rsquo;s less faffing around unrelated tests that broke due to the updated mocks.</p>
<p>I didn&rsquo;t think of it at the time, but it also made code reviews easer too. The old way meant longer, noisier PRs which — and I know this is a quality of mine that I need to work at — I usually ignore (I know, I know, I really shouldn&rsquo;t). With the reviews being smaller, I&rsquo;m much more likely to keep atop of them, and I attribute this to the way in which the tests are being written.</p>
<p>Code hygiene plays a role here. I got into the habit of adding test helpers to each package I work on. Much like the package is responsible for fulfilling the contract it has with its dependants, so too is it responsible for providing testing facilities for those dependants. I found this to be a great approach. It simplified the level of setup each dependant package needed to do in their tests, reducing the amount of copy and pasted code and, thus, containing the &ldquo;blast radius&rdquo; of logic changes. It&rsquo;s not perfect — there are a few tests where setup and teardown were simply copied-and-pasted from other tests — but it is better.</p>
<p>We didn&rsquo;t quite get rid of all the mocking though. Tests that exercise the database and message bus do so by calling out to these servers running in Docker, but this service also had to make calls to another worker. Since we didn&rsquo;t have a test service available to us, we just implemented this using old-school test mocks. The use of the package test helpers did help here: instead of having each test declare the expected calls on this mock, the helper just made &ldquo;maybe&rdquo; calls to each of the service methods, and provided a way to assert what calls were recorded.</p>
<p>Of course, much like everything, there are trade-offs. The tests run much slower now, thanks to the database setup and teardown, and we had to lock them down to run on a single thread. It&rsquo;s not much of an issue now, but we could probably mitigate this with using random database names, rather than have all the test run against the same one. Something that would be less easy to solve are the tests around the message bus, which do need to wait for messages to be received and handled. There might be a way to simplify this too, but since the tests are verifying the entire message exchange, it&rsquo;d probably be a little more involved.</p>
<p>Another trade-off is that it does feel like you&rsquo;re repeating yourself. We have tests that check that items are written to the database correctly for the database provider, the service layer, <em>and</em> the handler layer. Since we&rsquo;re writing tests that operate over multiple layers at a time, this was somewhat expected, but I didn&rsquo;t expect it to be as annoying as I found it to be. Might be that a compromise is to write the handler tests to use mocks rather than call down to the service layer. Those tests really only validate whether the hander converts the request and response to the models correctly, so best to isolate it there, and leave the tests asserting whether the business rules are correct to the server layer.</p>
<p>So if I were to do this again, that&rsquo;ll be the only thing I change. But, on the whole, it&rsquo;s been really refreshing writing unit tests like this. And this is not just my own opinion; I asked my colleague, who&rsquo;s has told me how difficult it&rsquo;s been maintaining tests with mocks, and he agrees that this new way has been an improvement. I&rsquo;d like to see if it&rsquo;s possible doing this for all other services going forward.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-mockless-unit-test-followup.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-mockless-unit-test-followup.mp3" type="audio/mpeg" length="5005216"></enclosure>
						<itunes:duration>250</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/07/18/had-a-go-at-recreating.html</link>
				<pubDate>Thu, 18 Jul 2024 23:40:00 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/07/18/had-a-go-at-recreating.html</guid>
				<description><![CDATA[<p>Had a go at recreating the last song Anders Enger Jensen wrote for 8 Bit Keys, since it&rsquo;s one that I like quite a bit. <a href="https://www.youtube.com/watch?v=ICX6hK3Se6k&amp;t=798s">Here&rsquo;s a YouTube link</a> to the original. This one was done in Logic Pro, and has a little more of the typical synth leads than the more brassy sound Anders Enger Jensen used.</p>
<p><audio src="https://cdn.uploads.micro.blog/25293/2024/hohner.mp3" controls></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/hohner.mp3" type="audio/mpeg" length="1205056"></enclosure>
						<itunes:duration>60</itunes:duration>
					
				
			</item>
		
			<item>
				<title>On the Easy Pit To Fall Into</title>
				<link>https://lmika.org/2024/07/14/090308.html</link>
				<pubDate>Sun, 14 Jul 2024 10:03:08 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/07/14/090308.html</guid>
				<description><![CDATA[<p>From Matt Bircher’s <a href="https://birchtree.me/blog/the-pit-its-so-easy-to-fall-into/">latest post on Birchtree</a>:</p>
<blockquote>
<p>One of the hard parts about sharing one&rsquo;s opinions online like I do is that it&rsquo;s very easy to fall into the trap of mostly complaining about things.</p>
</blockquote>
<p>This is something I also think about. While I haven’t done anything scientific to know what my ratio of posting about things I like vs. things I don’t, I feel like I’m getting the balance better. It might still be weighted too much on writing about the negatives, but I am trying to write more about things I think are good.</p>
<p>I do wonder, though, why it’s so easy to write about things you hate. Matt has a few theories regarding the dynamics of social media, but I wonder if it more about someone’s personal experience of that thing in question. You hear about something that you&rsquo;d thought would be worth a try. I doubt many people would actually try something they know they&rsquo;re going to dislike. If that&rsquo;s the case, they wouldn&rsquo;t try it at<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. So I&rsquo;m guessing that there&rsquo;s some expectation that you&rsquo;ll like the thing.</p>
<p>So you start experience the thing, and maybe it all goes well at first. Then you encounter something you don’t like about it. You make a note of it and keep going, only to encounter another thing you don’t like, then another. You eventually get to the point where you’ve had enough, and you decided to write about it. And lo, you&rsquo;ve got this list of paper-cuts that can be easily be used as arguments as to why the thing is no good.</p>
<p>Compare this to something that you do end up liking. You can probably come up with a list of things that are good about it, but you’re less likely to encounter them while you’re experiencing the thing. You just experience them, and it flows through you like water. When the time comes to write about it, you can recall liking the plot, or this character, etc., but they’re more nebulous and it takes effort to solidify them into a post. The drive to find the path of least resistance prevails, and you decided that it’s enough to just like it.</p>
<p>Anyway, this is just a hypothesis. I’m not a psychologist and I’ve done zero research to find out if any of this is accurate. In the end, this post might simply describe why my posting seems to be more weighted towards things I find annoying.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-easy-pit-to-fall-into.mp3" preload="metadata" style="display: none;">
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I&rsquo;m ignoring those that come at things with bad faith.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-easy-pit-to-fall-into.mp3" type="audio/mpeg" length="2084992"></enclosure>
						<itunes:duration>130</itunes:duration>
					
				
			</item>
		
			<item>
				<title>A Tour Of My New Self-Hosted Code Setup</title>
				<link>https://lmika.org/2024/07/09/a-tour-of.html</link>
				<pubDate>Tue, 09 Jul 2024 22:50:38 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/07/09/a-tour-of.html</guid>
				<description><![CDATA[<p>While working on the draft for this post, <a href="https://www.youtube.com/watch?v=YzBrI71FC44">a quote from Seinfield</a> came to mind which I thought was a quite apt description of this little project:</p>
<blockquote>
<p>Breaking up is knocking over a Coke machine. You can&rsquo;t do it in one push. You gotta rock it back and forth a few times and then it goes over.</p>
</blockquote>
<p>I&rsquo;ve been thinking about &ldquo;breaking up&rdquo; with Github on and off for a while now. I know I&rsquo;m not the only one: I&rsquo;ve seen a few people online talk about leaving Github too. They have their own reasons for doing so: some because of AI, others are just not fans of Microsoft. For me, it was getting bitten by the indie-web bug and wanting to host my code on my own domain name. I have more than a hundred repositories in Github, and that single <code>github.com/lmika</code> namespace was getting quite crowded. Being able to organise all these repositories into groups, without fear of collisions or setting up new accounts, was the dream.</p>
<p>But much like the Seinfield quote, it took a few rocks of that fabled Coke machine to get going. I dipped my toe in the water a few times: launching Gitea instances in PikaPod, and also spinning up a Gitlab instance in Linode during a hackathon just to see how well it would feel to manage code that way. I knew it wouldn&rsquo;t be easy: not only would I be paying more for doing this, it would involve a lot of effort up front (and on an ongoing basis), and I would be taking on the responsibility of backups, keeping CI/CD workers running, and making sure everything is secured and up-to-date. Not difficult work, but still an ongoing commitment.</p>
<p>Well, if I was going to do this at all, it was time to do it for real. I decided to set up my own code hosting properly this time, complete with CI/CD runners, all hosted under my own domain name. And well, that Coke machine is finally on the floor. I&rsquo;m striking out on my own.</p>
<p>Let me give you a tour of what I have so far.</p>
<h2 id="infrastructure">Infrastructure</h2>
<p>My goal was to have a setup with the following properties:</p>
<ul>
<li>A self-hosted SCM (source code management) system that can be bound to my own domain name.</li>
<li>A place to store Git repositories and LFS objects that can be scaled up as my needs for storage grow.</li>
<li>A CI/CD runner of some sort that can be used for automated builds, ideally something that supports Linux and MacOS.</li>
</ul>
<p>For the SCM, I settled on <a href="https://forgejo.org">Forgejo</a>, which is a fork of Gitea, as it seemed like the one that required the least amount of resources to run. When I briefly looked at doing this a while back, Forgejo didn&rsquo;t have anything resembling GitHub Actions, which was a non-starter for me. But they&rsquo;re now in Forgejo as an alpha, preview, don&rsquo;t-use-it-for-anything-resembling-production level of support, and I was curious to know how well they worked, so it was worth trying it out.</p>
<p>I did briefly look at Gitea&rsquo;s hosted solution, but it was relatively new and I wasn&rsquo;t sure how long their operations would last. At least with self-hosting, I can choose to exit on my own terms.</p>
<p>It was difficult thinking about how much I was willing to budget for this, considering that it&rsquo;ll be more than what I&rsquo;m currently paying for GitHub now, which is about $9 USD /month ($13.34 AUD /month). I settled for a budget of around $20.00 AUD /month, which is a bit much, but I think would give me something that I&rsquo;d be happy with without breaking the bank.</p>
<p>I first had a go at seeing what Linode had to offer for that kind of money. A single virtual CPU, with 2 GB RAM and 50 GB storage costs around $12.00 USD /month ($17.79 AUD /month). This would be fine if it was just the SCM, but I also want something to run CI/CD jobs. So I then took a look at Hetzner. Not only do they charge in Euro&rsquo;s, which works in my favour as far as currency conversions go, but their shared-CPU virtual servers were much cheaper. A server with the same specs could be had for only a few euro.</p>
<p>So after a bit of looking around, I settled for the following bill of materials:</p>
<ul>
<li>2x vCPU (CX22) instances, each with 4 GB RAM and 40 GB storage</li>
<li>A virtual network which houses these two instances</li>
<li>One public IP address</li>
<li>One 50 GB volume which can be resized</li>
</ul>
<p>This came to €10.21, which was around $16.38 AUD /month. Better infrastructure for a cheaper price is great in my books. The only downside is that they don&rsquo;t have a data-centre presences in Australia. I settled for the default placement of Falkenstein, Germany and just hoped that the latency wasn&rsquo;t too slow as to be annoying.</p>
<img src="https://cdn.uploads.micro.blog/25293/2024/code-architecture.png" width="600" height="292" alt="Architecture drawing of my coding setup, showing two CX22 virtual hosts, within a virtual network, with one connected to the internet, and one 50 GB volume">
<h2 id="installing-forgejo">Installing Forgejo</h2>
<p>The next step was setting up Forgejo. This can be done using official channels by either downloading a binary, or by installing a Docker image. But there&rsquo;s also a <a href="https://codeberg.org/forgejo-contrib/delightful-forgejo#packaging">forgejo-contrib</a> repository that distributes it via common package types, with Systemd configurations that launch Forgejo on startup. Since I was using Ubuntu, I downloaded and installed <a href="https://codeberg.org/forgejo-contrib/forgejo-deb">the Debian package</a>.</p>
<p>Probably the easiest way to get started with Forgejo is to use the version that comes with Sqlite, but since this is something that I&rsquo;d rather keep for a while, I elected to use Postgre for my database. I installed the latest Ubuntu distribution of Postgres, and setup the database <a href="https://forgejo.org/docs/latest/admin/installation-binary/#optional-set-up-database">as per the instructions</a>. I also made sure the mount point for the volume was ready, and created a new directory with the necessary owner and permissions so that Forgejo can write to it.</p>
<p>At this point I was able to launch Forgejo and go through the first launch experience. This is where I configured the database connection details, and set the location of the repository and LFS data (I didn&rsquo;t take a screenshot at the time, sorry). Once that was done, I shut the server down again as I needed to make some changes within the config file itself:</p>
<ul>
<li>I turned off the ability for others to register themselves as users, an important first step.</li>
<li>I changed the bind address of Forgejo. It listens to <code>0.0.0.0:3000</code> by default, but I wanted to put this behind a reverse proxy, so I changed it to <code>127.0.0.1:3000</code>.</li>
<li>I also reduced the minimum size of SSH RSA keys. The default was 3,072, but I still have keys of length 2,048 that I wanted to use. There was also an option to turn off this verification.</li>
</ul>
<p>After that, it was a matter of setting up the reverse proxy. I decided to use <a href="https://caddyserver.com">Caddy</a> for this, as it comes with HTTPS out of the box. This I installed as a Debian package also. <a href="https://caddyserver.com/docs/quick-starts/reverse-proxy#https-from-client-to-proxy">Configuring the reverse proxy</a> by changing the Caddyfile deployed in <code>/etc</code> was a breeze and after making the changes and starting Caddy, I was able to access Forgejo via the domain I setup.</p>
<p>One quick note about performance: although logging in via SSH was a little slow, I had no issues with the speed of accessing Forgejo via the browser.</p>
<h2 id="the-runners">The Runners</h2>
<p>The next job was setting the runners. I thought this was going to be easier than setting up Forgejo itself, but I did run into a few snags which slowed me down.</p>
<p>The first was finding out that a Hetzner VM running without a public IP address actually doesn&rsquo;t have any route to the internet, only the local network. The way to fix this is to setup one of the hosts which did have a public IP address to act as a NAT gateway. <a href="https://community.hetzner.com/tutorials/how-to-set-up-nat-for-cloud-networks">Hetzner has instructions</a> on how to do this, and after performing a hybrid approach of following both the Ubuntu 20.04 instructions and Ubuntu 22.04 instructions, I was able to get the runner host online via the Forgejo host. Kinda wish I knew about this before I started this.</p>
<p>For the runners, I elected to go with the Docker-based setup. Forgejo has pretty straightforward instructions for <a href="https://forgejo.org/docs/next/admin/actions/#installation-of-the-oci-image">setting them up using Docker Compose</a>, and I changed it a bit so that I could have two runners running on the same host.</p>
<p>Setting up the runners took multiple attempts. The first attempts failed when Forgejo couldn&rsquo;t locate any runners for an organisation to use. I&rsquo;m not entirely sure why this was, as the runners were active and were properly registered with the Forgejo instance. It could be magical thinking, but my guess is that it was because I didn&rsquo;t register the runners with an instance URL that ended with a slash. It seems like it&rsquo;s possible to register runners that are only available to certain organisations or users. Might be that there&rsquo;s some bit of code deep within Forgejo that&rsquo;s expecting a slash to make the runners available to everyone? Not sure. In either case, after registering the runners with the trailing slash, the organisations started to recognise them.</p>
<p>The other error was seeing runs fail with the error message <code>cannot find: node in PATH</code>. This resolved itself after I changed the <code>run-on</code> label within the action YAML file itself from <code>linux</code> to <code>docker</code>. I wasn&rsquo;t expecting this to be an issue — I though the <code>run-on</code> field was used to select a runner based on their published labels, and that <code>docker</code> was just one such label. The Forgejo documentation was not super clear on this, but I got the sense that the <code>docker</code> label was special in some way. I don&rsquo;t know. But whatever, I can use <code>docker</code> in my workflows.</p>
<p>Once these battles were won, the runners were ready, and I was able to build and test a Go package successfully. One last annoying thing is that Forgejo doesn&rsquo;t enable runners by default for new repositories — I guess because they&rsquo;re still considered an alpha release. I can live with that in the short term, or maybe there&rsquo;s some configuration I can enable to always have them turned on. But in either case, I&rsquo;ve now got two Linux runners working.</p>
<figure>
<img src="https://cdn.uploads.micro.blog/25293/2024/out-20240704-084448.png" width="600" height="461" alt="Screenshot of a completed CI/CD run within Forgejo">
<figcaption>The first successful CI/CD run using these Linux runners.</figcaption>
</figure>
<h2 id="macos-runner-and-repository-backup">MacOS Runner And Repository Backup</h2>
<p>The last piece of the puzzle was to setup a MacOS runner. This is for the occasional MacOS application I&rsquo;d like to build, but it&rsquo;s also to run the nightly repository backups. For this, I&rsquo;m using a Mac Mini currently being used as a home server. This has an external hard drive connect, with online backups enabled, which makes it a perfect target for a local backup of Forgejo and all the repository data should the worse come to pass.</p>
<p>Forgejo does&rsquo;t have an official release of a MacOS runner, but Gitea does, and I managed to <a href="https://gitea.com/gitea/act_runner">download a MacOS build of act_runner</a> and deploy it onto the Mac Mini. Registration and performing a quick test with the runner running in the foreground went smoothly. I then went through the process of setting it up as a MacOS launch agent. This was a pain, and it took me a couple of hours to get this working. I won&rsquo;t go through every issue I encountered, mainly because I couldn&rsquo;t remember half of them, but here&rsquo;s a small breakdown of the big ones:</p>
<ul>
<li>I was unable to register the launch agent definition within the user domain. I had to use the <code>gui</code> domain instead, which requires the user to be logged in. I&rsquo;ve got the Mac Mini setup to login on startup, so this isn&rsquo;t a huge issue, but it&rsquo;s not quite what I was hoping for.</li>
<li>Half the commands in <code>launchctl</code> are deprecated and not fully working. Apples documentation on the command is sparse, and many of the Stack Exchange answers are old. So a lot of effort was spent fumbling through unfinished and outdated documentation trying to install and enable the launch service.</li>
<li>The actual runner is launch using a shell script, but when I tried the backup job, Bash couldn&rsquo;t access the external drive. I had to explicitly add Bash to Privacy &amp; Security → Full Disk Access within the Settings app.</li>
<li>Once I finally got the runner up and running as a launch agent, jobs were failing because <code>.bash_profile</code> wasn&rsquo;t been loaded. I had to adjust the launch script to include this explicitly, so that the PATH to Node and Go were set properly.</li>
<li>This was further exacerbated by two runners running at the same time. The foreground runner I was using to test with was configured correctly, while the one running as a launch agent wasn&rsquo;t fully working yet. This manifested as the back-up job randomly failing with the same <code>cannot find: node in PATH</code> error half the time.</li>
</ul>
<p>It took me most of Saturday morning, but in the end I managed to get this MacOS runner working properly. I&rsquo;ve not done anything MacOS-specific yet, so I suspect I may have some XCode related stuff to do, but the backup job is running now and I can see it write stuff to the external hard drive.</p>
<p>The backup routine itself is a simple Go application that&rsquo;s kicked off daily by a scheduled Forgejo Action (it&rsquo;s not in the documentation yet, but the version of Forgejo I deployed does support scheduled actions). It makes a backup of the Forgejo instance, the PostgreSQL database, and all the repository data using SSH and Rsync.</p>
<p>I won&rsquo;t share these repositories as they contain references to paths and such that I consider sensitive; but if you&rsquo;re curious about what I&rsquo;m using for the launch agent settings, here&rsquo;s the plist file I&rsquo;ve made:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;!-- dev.lmika.repo-admin.macos-runner.plist --&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;!DOCTYPE plist PUBLIC &#34;-//Apple//DTD PLIST 1.0//EN&#34; &#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&#34;&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;plist</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.0&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;dict&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;key&gt;</span>Label<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;string&gt;</span>dev.lmika.repo-admin.macos-runner<span style="color:#f92672">&lt;/string&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;key&gt;</span>ProgramArguments<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;array&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;string&gt;</span>/Users/lmika/opt/macos-runner/scripts/run-runner.sh<span style="color:#f92672">&lt;/string&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/array&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;key&gt;</span>KeepAlive<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;true/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;key&gt;</span>RunAtLoad<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;true/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;key&gt;</span>StandardErrorPath<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;string&gt;</span>/tmp/runner-logs.err<span style="color:#f92672">&lt;/string&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;key&gt;</span>StandardOutPath<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;string&gt;</span>/tmp/runner-logs.out<span style="color:#f92672">&lt;/string&gt;</span> 
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dict&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/plist&gt;</span>
</span></span></code></pre></div><p>This is deployed by copying it to <code>$HOME/Library/LaunchAgents/dev.lmika.repo-admin.macos-runner.plist</code>, and then installed and enabled by running these commands:</p>
<pre tabindex="0"><code>launchctl bootstrap gui/$UID &#34;Library/LaunchAgents/dev.lmika.repo-admin.macos-runner.plist&#34;
launchctl kickstart gui/$UID/dev.lmika.repo-admin.macos-runner
</code></pre><h2 id="the-price-of-a-name">The Price Of A Name</h2>
<p>One might see this endeavour, when viewed from a pure numbers and effort perspective, as a bit of a crazy thing to do. Saying &ldquo;no&rdquo; to all this cheap code hosting, complete with the backing of a large cooperation, just for the sake of a name? I can&rsquo;t deny that this may seem a little unusual, even a little crazy. After all, it&rsquo;s more work and more money. And I&rsquo;m not going to suggest that others follow me into this realm of a self-hosted SCM.</p>
<p>But I think my code deserves it&rsquo;s own name now. After all, my code is my work; and much like we encourage writers to write under their own domain name, or for artists and photographers to move away from the likes of Instagram and other such services, so too should my work be under a name I own and control. The code I write may not be much, but it is my own.</p>
<p>Of course, I&rsquo;m not going to end this without my usual &ldquo;we&rsquo;ll see how we go&rdquo; hedge against myself. I can only hope I got enough safeguards in place to save me from my own decisions, or to easily move back to a hosted service, when things go wrong or when it all becomes just a bit much. More on that in the future, I&rsquo;m sure.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-tour-of-self-hosted-code-setup.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-tour-of-self-hosted-code-setup.mp3" type="audio/mpeg" length="13949056"></enclosure>
						<itunes:duration>871</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/07/06/woke-up-with-this-tune.html</link>
				<pubDate>Sat, 06 Jul 2024 19:00:00 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/07/06/woke-up-with-this-tune.html</guid>
				<description><![CDATA[<p>Woke up with this tune in my head this morning. Managed to record it before I forgot it, then I added some accompaniments. I&rsquo;ve called it <em>Prophet</em>, after the synth. It&rsquo;s a decent start but I&rsquo;m not sure how to continue it from this point on.</p>
<p><audio src="https://cdn.uploads.micro.blog/25293/2024/prophet.mp3" controls="controls"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/prophet.mp3" type="audio/mpeg" length="1579598"></enclosure>
						<itunes:duration>73</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Asciidoc, Markdown, And Having It All</title>
				<link>https://lmika.org/2024/06/21/asciidoc-markdown-and.html</link>
				<pubDate>Fri, 21 Jun 2024 13:07:30 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/21/asciidoc-markdown-and.html</guid>
				<description><![CDATA[<p>Took a brief look at <a href="https://asciidoc.org/">Asciidoc</a> this morning.</p>
<p>This is for that Markdown document I&rsquo;ve been writing in Obsidian. I&rsquo;ve been sharing it with others using PDF exports, but it&rsquo;s importance has grown to a point where I need to start properly maintaining a change log. And also… sharing via PDF exports? What is this? Microsoft Word in the 2000s?</p>
<p>So I&rsquo;m hoping to move it to a Gitlab repo. Gitlab does support Markdown with integrated Mermaid diagrams, but not Obsidian&rsquo;s extension for callouts. I&rsquo;d like to be able to keep these callouts as I used them in quite a few places.</p>
<p>While browsing through Gitlabs&rsquo;s help guide on Markdown extensions, I came across their support for Asciidoc. I&rsquo;ve haven&rsquo;t tried Asciidoc before, and after taking a brief look at it, it seemed like a format better suited for the type of document I&rsquo;m working on. It has things like auto-generated table of contents, builtin support for callouts, proper title and heading separations; just features that work better than Markdown for long, technical documents. The language syntax also supports a number of text-based diagram formats, including Mermaid.</p>
<p>However, as soon as I started porting the document over to Asciidoc, I found it to be no Markdown in terms of mind share. Tool support is quite limited, in fact it&rsquo;s pretty bad. There&rsquo;s nothing like iA Writer for Asciidoc, with the split-screen source text and live preview that updates when you make changes. There&rsquo;s loads of these tools for Markdown, so many that I can&rsquo;t keep track of them (the name of the iA Writer alternative always eludes me).</p>
<p>Code editors should work, but they&rsquo;re not perfect either. GoLand supports Asciidoc, but not with embedded Mermaid diagrams. At least not out of the box: I had to get a separate JAR which took around 10 minutes to download. Even now I&rsquo;m fighting with the IDE, trying to get it to find the Mermaid CLI tool so it can render the diagrams. I encountered none of these headaches when using Markdown: GoLand supports embedded Mermaid diagrams just fine. I guess I could try VS Code, but to download it just for this one document? Hmm.</p>
<p>In theory the <a href="https://asciidoctor.org">de-facto CLI tool</a> should work, but in order to get Mermaid diagrams working there I need to download a Ruby gem and bundle it with the CLI tool (this is in addition to the same Mermaid command-line tool GoLand needs). Why this isn&rsquo;t bundled by default in the Homebrew distribution is beyond me.</p>
<p>So for now I&rsquo;m abandoning my wish for callouts and just sticking with Markdown. This is probably the best option, even if you set tooling aside. After all, everyone knows Markdown, a characteristic of the format that I shouldn&rsquo;t simply ignore. Especially for these technical documents, where others are expected to contribute changes as well.</p>
<p>It&rsquo;s a bit of a shame though. I still think Asciidoc could be better for this form of writing. If only those that make writing tools would agree.</p>
<p>Addendum: after drafting this post, I found that Gitlab actually supports auto-generated table of contents in Markdown too. So while I may not have it all with Markdown — such as callouts — I can still have a lot.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-asciidoc-markdown.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-asciidoc-markdown.mp3" type="audio/mpeg" length="2122670"></enclosure>
						<itunes:duration>186</itunes:duration>
					
				
			</item>
		
			<item>
				<title>My Position On Blocking AI Web Crawlers</title>
				<link>https://lmika.org/2024/06/18/183404.html</link>
				<pubDate>Tue, 18 Jun 2024 19:34:04 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/18/183404.html</guid>
				<description><![CDATA[<p>I&rsquo;m seeing a lot of posts online about sites and hosting platforms blocking web crawlers used for AI training. I can completely understand their position, and fully support them: it&rsquo;s their site and they can do what they want.</p>
<p>Allow me to lay my cards on the table. My current position is to allow these crawlers to access my content. I&rsquo;m choosing to opt in, or rather, not to opt out. I&rsquo;m probably in the minority here (well, the minority of those I follow), but I do have a few reasons for this, with the principal one being that I use services like ChatGTP and get value from them. So to prevent them from training their models on my posts feels personally hypocritical to me. It&rsquo;s the same reason why I don&rsquo;t opt out of Github Copilot crawling my open source projects (although that&rsquo;s a little more theoretical, as I&rsquo;m not a huge user of Copilot). To some, this position might sound weird, and when you consider the gulf between what value these AI companies get from scraping the web verses what value I get from them as a user, it may seem downright stupid. And if you approach it from a logical perspective, it probably is. But hey, we&rsquo;re in the realm of feelings, and right now this is just how I feel. Of course, if I were to make a living out of this site, it would be a different story. But I don&rsquo;t.</p>
<p>And this leads to the tension I see between site owners making decisions regarding their own content, and services making decisions on behalf of their users. This site lives on Micro.blog, so I&rsquo;m governed by what Manton chooses to do or not do regarding these crawlers. I&rsquo;m generally in favour of what Micro.blog has chosen so far: allowing people to block these scrapers via &ldquo;robots.txt&rdquo; but not yet blocking requests based on their IP address. I&rsquo;m aware that others may not agree, and I can&rsquo;t, in principal, reject the notion of a hosting provider choosing to block this crawlers at the network layer. I am, and will continue to be, a customer of such services.</p>
<p>But I do think some care should be considered, especially when it comes to customers (and non-customer) asking these services to add these network blocks. You may have good reason to demand this, but just remember there are users of these services that have opinions that may differ. I personally would prefer a mechanism where you opt into these crawlers, and this would be an option I&rsquo;ll probably take (or probably not; my position is not <em>that</em> strong). I know that&rsquo;s not possible under all circumstances so I&rsquo;m not going to cry too much if this was not offered to me in lieu of a blanket ban.</p>
<p>I will make a point on some comments that I&rsquo;ve seen that, if taken in an uncharitable way, imply that creators that have no problem with these crawlers do not care about their content. I think such opinions should be worded carefully. I know how polarising the use of AI currently is, and making such remarks, particularly within posts that are already heated due to the author&rsquo;s feelings regarding these crawlers, risks spreading this heat to those that read it. The tone gives the impression that creators okay with these crawlers don&rsquo;t care about what they push online, or should care more than they do. That might be true for some — might even be true for me once in a while — but to make such blanket assumptions can come off as a little insulting. And look, I know that&rsquo;s not what they&rsquo;re saying, but it can come across that way at times.</p>
<p>Anyway, that&rsquo;s my position as of today. Like most things here, this may change over time, and if I become disenfranchised with these companies, I&rsquo;ll join the blockade. But for the moment, I&rsquo;m okay with sitting this one out.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-ai-web-crawlers.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-ai-web-crawlers.mp3" type="audio/mpeg" length="3364864"></enclosure>
						<itunes:duration>210</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/06/17/sometimes-i-wonder.html</link>
				<pubDate>Mon, 17 Jun 2024 10:00:53 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/17/sometimes-i-wonder.html</guid>
				<description><![CDATA[<p>Sometimes I wonder how and why my work email address got onto various B2B marketing email lists. “Want to buy some network gear, or setup a meeting with our account manager?” What? No! Even if I wanted to, that’s not a decision I’m authorised to make.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-b2b-email-lists.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-b2b-email-lists.mp3" type="audio/mpeg" length="174014"></enclosure>
						<itunes:duration>15</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Thinking About Plugins In Go</title>
				<link>https://lmika.org/2024/06/12/thinking-about-plugins.html</link>
				<pubDate>Wed, 12 Jun 2024 16:14:49 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/12/thinking-about-plugins.html</guid>
				<description><![CDATA[<p>Thought I&rsquo;d give Go&rsquo;s plugin package a try for something. Seems to works fine for the absolutely simple things. But start importing any dependencies and it becomes a non-starter. You start seeing these sorts of error messages when you try to load the plugin:</p>
<pre tabindex="0"><code>plugin was built with a different version of package golang.org/x/sys/unix
</code></pre><p>Looks like the host and plugins need to have exactly the same dependencies. To be fair, the package documentation says as much, and also states that the best use of plugins is for dynamically loaded modules build from the same source. But that doesn&rsquo;t help me and what I&rsquo;m trying to do, which is encoding a bunch of private struct types as Protobuf messages.</p>
<p>So might be that I&rsquo;ll need to find another approach. I wonder how others would do this. An embedded scripting language would probably not be suitable for this, since I&rsquo;m dealing with Protobuf and byte slices. Maybe building the plugin as a C shared object? That could work, but then I&rsquo;d loose all the niceties that come from using Go&rsquo;s type system.</p>
<p>Another option would be something like WASM. It&rsquo;s interesting seeing WASM modules becoming a bit of a thing for plugin architectures. There&rsquo;s even a <a href="https://github.com/wasmerio/wasmer-go">Go runtime</a> to host them. The only question is whether they would have the same facilities as regular process would have, like network access; or whether they&rsquo;re completely sandboxed, and you as the plugin host would need to add support for these facilities.</p>
<p>I guess I&rsquo;d find out if I were to spend any more time looking at this. But this has been a big enough distraction already. Building a process to shell-out to would work just fine, so that&rsquo;s probably what I&rsquo;ll ultimately do.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-thinking-about-go-plugins.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-thinking-about-go-plugins.mp3" type="audio/mpeg" length="1111934"></enclosure>
						<itunes:duration>105</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/06/11/one-of-these.html</link>
				<pubDate>Tue, 11 Jun 2024 18:39:10 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/11/one-of-these.html</guid>
				<description><![CDATA[<p>One of these days, I&rsquo;m going to write a long form post, and do the narration in a single take.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-one-of-these-days.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-one-of-these-days.mp3" type="audio/mpeg" length="72830"></enclosure>
						<itunes:duration>6</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Word Cloud</title>
				<link>https://lmika.org/2024/06/11/word-cloud.html</link>
				<pubDate>Tue, 11 Jun 2024 18:36:48 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/11/word-cloud.html</guid>
				<description><![CDATA[<p>From <a href="https://seths.blog/2024/06/an-overlooked-and-powerful-editing-tool/">Seth&rsquo;s blog</a>:</p>
<blockquote>
<p>Consider building a word cloud of your writing.</p>
</blockquote>
<p>Seems like a good idea so that&rsquo;s what I did, taking the contents of the first page of this blog. Here it is:</p>
<img src="https://cdn.uploads.micro.blog/25293/2024/wordcloud.jpg" width="600" height="600" alt="A word cloud containing the words of the first page of this blog">
<p>Some observations:</p>
<ul>
<li>One of the most prominent words is &ldquo;just&rdquo;, with &ldquo;it&rsquo;s&rdquo; not far behind. I though it&rsquo;s because I started a lot of sentences with &ldquo;it&rsquo;s just&rdquo;, but it turns out I&rsquo;ve only used that phrase once, while the individual words show up around 10 times each. I guess I use &ldquo;just&rdquo; a lot (apparently, so does Seth). I am surprise to see the word &ldquo;anyway&rdquo; only showing up twice.</li>
<li>Lots of first-person pronouns and articles, like &ldquo;I&rsquo;m&rdquo;, &ldquo;I&rsquo;ve&rdquo;, and &ldquo;mine&rdquo;. That&rsquo;s probably not going to change either. This is just<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> the tonal choice I&rsquo;ve made. I read many blogs that mainly speak in the second person and I don&rsquo;t think it&rsquo;s a style that works for me. Although I consciously know that they&rsquo;re not speaking to me directly, or even to the audience as a whole, I don&rsquo;t want to give that impression myself, unless that&rsquo;s my intention. So it&rsquo;ll be first person for the foreseeable future I&rsquo;m sure.</li>
<li>Because it&rsquo;s only the first page, many of the more prominent words are from recent posts. So lots about testing, OS/2, and Bundanoon. I would like to cut down on how much I write about testing. A lot of it is little more than venting, which I guess is what one does on their blog, but I don&rsquo;t want to make a habit of it.</li>
<li>I see the word &ldquo;good&rdquo; is prominent. That&rsquo;s good: not a lot of negative writing (although, <a href="https://lmika.org/2024/05/12/manuel-moreale-wrote.html">this is a choice too</a>).</li>
<li>I see the word &ldquo;video&rdquo; is also prominent. That&rsquo;s probably not as good. Might be a sign I&rsquo;m talking a little too much about the videos I&rsquo;ve been watching.</li>
</ul>
<p>Anyway, I thought these findings were quite interesting. One day, I&rsquo;ll have to make another word cloud across all the posts on this blog.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-word-cloud.mp3" preload="metadata" style="display: none;">
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>One more &ldquo;just&rdquo;&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-word-cloud.mp3" type="audio/mpeg" length="1284518"></enclosure>
						<itunes:duration>117</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Day Trip to Bundanoon</title>
				<link>https://lmika.org/2024/06/10/day-trip-to-bundanoon.html</link>
				<pubDate>Mon, 10 Jun 2024 00:26:00 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/10/day-trip-to-bundanoon.html</guid>
				<description><![CDATA[<p>Decided to go on a day trip to Bundanoon today. It&rsquo;s been five years since I last visited and I remember liking the town enough that I thought it&rsquo;d be worth visiting again. It&rsquo;s not close, around 1 hour and 40 minutes from Canberra, but it not far either and I thought it would be a nice way to spend the day. Naturally, others agreed, which I guess explains why it was busier than I expected, what with the long weekend and all. Fortunately, it wasn&rsquo;t too crowded, and I still had a wonderful time.</p>
<p>The goal was to go on a bush-walk first. I chose to do the Erith Coal Mine track, for no particular reason other than it sounded interesting. This circuit track was meant to take you to a waterfall by an old coal mine. However, the track leading to the actual mine was closed, thanks to the recent rain. In fact, if I could describe the bush-walks in one word, it would be &ldquo;wet&rdquo;. The ground was soaked, as were the paths, and although conditions were lovely, the paths were still very slippery.</p>
<div class="img-gallery">
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-010511518.jpg"
     
        alt="Auto-generated description: A narrow, rocky trail winds through thick, bushy vegetation and trees under a clear blue sky." 
     
      />

  <figcaption>
  
  Eirth Coal Mine track starting off pretty well, if a little wet.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-011050785.jpg"
     
        alt="Auto-generated description: A narrow, winding trail with wooden steps descends through a dense forest of tall trees and thick vegetation." 
     
      />

  <figcaption>
  
  Starting our desent into the vally.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-011536112.jpg"
     
        alt="Auto-generated description: A metal railing pathway leads through a wooded area with numerous trees and plants under a clear blue sky." 
     
      />

  <figcaption>
  
  Continuing our desent via these elevated platforms. The stairs here were very narrow.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-012326198.jpg"
     
        alt="Auto-generated description: A fenced-off construction site with Danger Construction Site signs is located next to a flowing waterway amidst surrounding greenery." 
     
      />

  <figcaption>
  
  I assume the path is meant to cross this flat stone, which I&#39;m guessing is either dry, or has a small stream. But all the recent rain has turned it into a torrent.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-012638908.jpg"
     
        alt="Auto-generated description: A weathered picnic table and bench set is situated in a natural, wooded area with a signpost nearby." 
     
      />

  <figcaption>
  
  My make shift walking staff, which prooved useful getting through the slippery parts of the trail.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-012854757.jpg"
     
        alt="Auto-generated description: A winding gravel road curves through a dense forested area under a clear blue sky." 
     
      />

  <figcaption>
  
  View behind me as a start climbing back to road level.
  </figcaption>

</figure>
</div>
<figure>
<video src="https://cdn.uploads.micro.blog/25293/2024/bundanoon-walk-1.mov" controls="controls" preload="metadata"></video>
<figcaption>I assume the mine was across these rocks, but there was no way I was going to cross it.</figcaption>
</figure>
<p>After completing that circuit in probably 45 minutes, my appetite for bush-walking was still unsatisfied, so I tried the Fairy Bower Falls walk next. This was not as steep as the first one, but it turned to be a much harder track due to how wet and slippery everything was.</p>
<div class="img-gallery">
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-015027509.jpg"
     
        alt="Auto-generated description: A dirt pathway in a forested area is marked by a sign indicating Fairy Beaver Walk and features another small signpost further along the path." 
     
      />

  <figcaption>
  
  Enterance to Fairy Bower Falls walk.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-015716731.jpg"
     
        alt="Auto-generated description: A narrow, rocky trail winds through a dense, wooded area with sunlight filtering through the trees." 
     
      />

  <figcaption>
  
  This track wet and very slippery. Much of it was barely walkable if you wanted to keep your shoes dry.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-020820102.jpg"
     
        alt="Auto-generated description: A dense thicket of bushes and trees with varying shades of green foliage." 
     
      />

  <figcaption>
  
  This was the best shot I have of the waterfall, which is pretty bad, but I can assure you, it was there amongst the trees.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/pxl-20240609-021321005.jpg"
     
        alt="Auto-generated description: A muddy forest trail is flanked by greenery with wooden planks placed sporadically for stability." 
     
      />

  <figcaption>
  
  The walk back to the road. This was much easier, partly because it was uphill but also because I know I already walked this part once.
  </figcaption>

</figure>
</div>
<p>I stopped short of the end of this one too, as it seems the path was washed away. But I did manage to get a glimpse of the waterfall, so I&rsquo;m considering that a win.</p>
<p>After that, I returned to the town for lunch and some train spotting. The train line to Goulburn runs through Bundanoon, and the last time I was there, there was probably a freight train every hour or so. So I was hoping to get a good view of a lot of freight traffic. Maybe shoot a video of a train passing through the station I could share here.</p>
<figure>
<img src="https://cdn.uploads.micro.blog/25293/2024/pxl-20240609-034857614.jpg" width="600" height="451" alt="Auto-generated description: A quaint train station platform with a sign that reads Bundanoon is shown, surrounded by trees and blue skies.">
<figcaption>Bundanoon train station.</figcaption>
</figure>
<p>I had lunch outside and walked around the town a little, always within sight of the railway line, hoping for at least one train to pass through. But luck wasn&rsquo;t on my side, and it wasn&rsquo;t until I was on my way home that I saw what I think was a grain train passing through Wingello. I pulled over to take a video, and while I miss the locomotive, I got a reasonable enough recording of the wagons.</p>
<figure>
<video src="https://cdn.uploads.micro.blog/25293/2024/bundanoon-freight-3.mov" controls="controls" preload="metadata"></video>
<figcaption>Stopping by the side of the road to film these grain wagons passing by.</figcaption>
</figure>
<p>Being a little more hopeful, I stopped at Tallong, the next town along the road. I bought a coffee and went to the station to drink it and hopefully see a train pass through. Sadly, it was not to be. So I decided to head back home.</p>
<figure>
<img src="https://cdn.uploads.micro.blog/25293/2024/pxl-20240609-043946516.jpg" width="600" height="451" alt="Auto-generated description: A quiet train station platform is shown with tracks stretching into the distance and surrounded by trees.">
<figcaption>Tallong train station.</figcaption>
</figure>
<p>So the train spotting was a bust, and the bush-walks were difficult, but all in all it was quite a nice day. I look forward to my next visit to Bundanoon. Lets hope the trains are running a little more frequently then.</p>
<p><audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/day-trip-to-bundanoon.mp3" preload="metadata" style="display: none;"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/day-trip-to-bundanoon.mp3" type="audio/mpeg" length="1840934"></enclosure>
						<itunes:duration>167</itunes:duration>
					
				
			</item>
		
			<item>
				<title>An Unfair Critique Of OS/2 UI Design From 30 Years Ago</title>
				<link>https://lmika.org/2024/06/06/173723.html</link>
				<pubDate>Thu, 06 Jun 2024 18:37:23 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/06/173723.html</guid>
				<description><![CDATA[<p>A favourite YouTube channel of mine is <a href="https://www.youtube.com/@MichaelMJD">Michael MJD</a>, who likes to explore retro PC products and software from the 90s and early 2000s. Examples of these include videos on Windows 95, Windows 98, and the various consumer tech products designed to get people online. Can I just say how interesting those times were, where phrases such as &ldquo;surfing the net&rdquo; were thrown about, and where shopping centres were always used to explain visiting websites. I guess it was the best analogy one could use at the time.</p>
<p>A staple of Michael MJD&rsquo;s channel is when he installs an old operating systems onto old hardware<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. Yesterday, I watched the one where he <a href="https://www.youtube.com/watch?v=Q6R1DK4BdmQ">installed OS/2 Warp 4</a> onto a 98 PC. We were an OS/2 household back when I was growing up, thanks to my dad using it for work, and I can remember using OS/2 2.1 and thinking it was actually pretty good. Better than Windows 95, in fact. I can&rsquo;t remember if I ever used Warp 4, though.</p>
<p>Anyway, while watching this video, and I was taken aback on how bad the UI design of OS/2 Warp 4 was. And really, I probably shouldn&rsquo;t be throwing stones here: I&rsquo;m not a great UI designer myself. But I guess my exposure to later versions of Windows and macOS matured my tastes somewhat; where I got exposed to the idea of interaction systems and user experience design (and generally just growing up). Obviously given how new the GUI was back then, many of these concepts were still in their infancy, although if you were to compare these UIs to the classic Mac or even Windows 3.1, I do think there was something missing in IBM&rsquo;s design acumen. Was it ability? Interest? Care? Not sure. But given that it&rsquo;s been 30 years, I&rsquo;m not expecting the OS/2 devs  to be able to defend themselves now. That&rsquo;s what makes this critique wholly unfair.</p>
<p>Anyway, I&rsquo;d thought I share some of the stills from this video that I thought contained some of the more cringeworthy UI designs<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, along with my remarks. Enjoy.</p>
<div class="img-gallery">
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-1.jpg"
     
        alt="Auto-generated description: A computer monitor displays a system configuration screen for hardware and devices, including details such as locale settings, display types, peripheral devices, and the absence of a printer connection." 
     
      />

  <figcaption>
  
  First still is not too bad, except for how close the text is to the top of the window. Their vertical alignment by the icons is not great either. Also, what&#39;s with the button placement at the bottom?
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-2.jpg"
     
        alt="Auto-generated description: A computer screen displays a software installation menu with options for various components, including Assistance Center, Fonts, System Utilities, and more, with an indication of available and needed disk space." 
     
      />

  <figcaption>
  
  Ah, okay. So the addition of the Previous button explains why Next is in the middle. I wouldn&#39;t say that&#39;s my preferred styling, but it does make sense in a way.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-3.jpg"
     
        alt="Auto-generated description: A computer screen displays the setup and installation process for OS/2 Warp Version 4, prompting the user for personal information." 
     
      />

  <figcaption>
  
  When I first saw this still, I thought the labels were missaligned, but it seems to me now that it&#39;s actually the text fields. Looks like they&#39;ve been positioned too far down to the bottom left. Also, is that font different? Not sure I like it.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-4.jpg"
     
        alt="Auto-generated description: A computer screen displays an installation window offering additional software options for installation, including Java versions, IBM Web Browser, OS/2 Toolkit, and Macromedia Flash Player, with system information along the bottom." 
     
      />

  <figcaption>
  
  Spacing and alignment are reoccurring issues with these dialogs. Seeing the left margin of controls and all that wasted space on the bottom is amusing. One thing I also learnt from these videos is that IBM loves to be verbose on their UIs, which I pretty sure people will just skip past.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-5.jpg"
     
        alt="Auto-generated description: A computer screen displays a password setup window over a Windows desktop background with various program icons, indicating instructions to enter a password in two fields." 
     
      />

  <figcaption>
  
  More bad alignment of labels and controls. A bit more space for that verification password label would&#39;ve been nicer.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-6.jpg"
     
        alt="Auto-generated description: A computer screen displays the IBM OS/2 Program Manager version 3.1 running on a system with 65,093 KB of total memory and 832 KB free." 
     
      />

  <figcaption>
  
  Microsoft is not known for their great UI design skills, but this still just shows that, compared to OS/2, they are SO much better. At least everything is aligned, and buttons always tend to appear on the right (although this one is a bit close to the margin).
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-7.jpg"
     
        alt="Auto-generated description: A computer screen displays the Volume - Properties window from an older operating system interface." 
     
      />

  <figcaption>
  
  So much empty space; although to be fair to the designs, I wouldn&#39;t know how to lay this dialog out any better.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-8.jpg"
     
        alt="Auto-generated description: A computer screen displays an OS/2 Window with a prompt asking if the user wants to close the session without saving data." 
     
      />

  <figcaption>
  
  Spacing and alignment, and now we&#39;re mixing center and left justified buttons in our dialog.
  </figcaption>

</figure>
<figure>
<img src="https://lmika.org/uploads/2024/michael-mjd-frame-9.jpg"
     
        alt="A computer screen displays a Netscape profile creation window with a profile named &#39;default&#39; highlighted." 
     
      />

  <figcaption>
  
  This dialog&#39;s from Netscape and it&#39;s still not great, but at least it&#39;s better. I&#39;m wondering if the bad layout of the text within the input fields themselves is just a result of the UI toolkit.
  </figcaption>

</figure>
</div>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/narration-unfair-cretique-os2.mp3" preload="metadata" style="display: none;">
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>When I first visited the channel, I said to myself: &ldquo;who would want to watch videos of someone installing old software onto old hardware?&rdquo; Well, apparently I do. 😀&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>All stills taken from the video <a href="https://www.youtube.com/watch?v=Q6R1DK4BdmQ">Installing the Last Version of IBM OS/2 on the $5 Windows 98 PC</a>, by Michael MJD, release 21 Dec 2019.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/narration-unfair-cretique-os2.mp3" type="audio/mpeg" length="1700078"></enclosure>
						<itunes:duration>149</itunes:duration>
					
				
			</item>
		
			<item>
				<title>Some More Thoughts On Unit Testing</title>
				<link>https://lmika.org/2024/06/03/some-more-thoughts.html</link>
				<pubDate>Mon, 03 Jun 2024 13:32:50 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/06/03/some-more-thoughts.html</guid>
				<description><![CDATA[<p>Kinda want to avoid this blog descending into a series of &ldquo;this is wrong with unit testing&rdquo; posts, but something did occur to me this morning. We&rsquo;ve kicked off a new service at work recently. It&rsquo;s just me and this other developer working on it at the moment, and it&rsquo;s given us the opportunity to try out this &ldquo;mockless&rdquo; approach to testing, of which I ranted about a <a href="https://lmika.org/2024/05/17/had-a-great.html">couple of weeks ago</a> (in fact, the other developer is the person I had that discussion with). And it&rsquo;s probably no surprise, but I&rsquo;m finding writing tests this way to be a much nicer experience already.</p>
<p>And I think I&rsquo;ve come to the realisation that the issue is not so much with mocking itself. Rather, it&rsquo;s the style of testing that it encourages. When you&rsquo;re testing against &ldquo;real&rdquo; services, you&rsquo;ll left with treating them as a black box. There&rsquo;s no real way to verify  your code is working correctly other than letting it interact with these services as it would, and then &ldquo;probing&rdquo; them in some way — running queries, waiting for messages to arrive at topics, etc. — to know whether the interaction worked. You can&rsquo;t just verify this by intercepting the various calls made by the service (well you can, but it would be difficult to do).</p>
<p>There&rsquo;s nothing about mocking that inhibits this style of testing. You can use mocks to simulate a message broker by storing the messages in an in-memory list, for example. What it does do, however, is make it easier to write tests that simply intercept the calls of the service and verify that they were made. It&rsquo;s less upfront work than setting up a real client, or simulating a message broker, but now you&rsquo;ve tied your tests to your implementation. You may feel like you&rsquo;ve saved time and effort now, but really you&rsquo;ve just deferred it for later, when you need to fix your tests when you&rsquo;ve change your implementation.</p>
<p>I know this is stuff I said before, so I&rsquo;ll just stop here, and end by saying that I&rsquo;m excited to seriously try out this approach to writing unit tests. Is it a better approach than using mocks? I guess time will tell. It&rsquo;s been my experience that it&rsquo;s when you need to refactor things in your service when you find out how good your tests are. So I guess we&rsquo;ll check back in about six months or so.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/some-more-thoughts-on-unit-testing.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/some-more-thoughts-on-unit-testing.mp3" type="audio/mpeg" length="1345958"></enclosure>
						<itunes:duration>122</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2024/05/25/095856.html</link>
				<pubDate>Sat, 25 May 2024 10:58:56 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2024/05/25/095856.html</guid>
				<description><![CDATA[<p>Trying out the new audio narration feature for Micro.blog that <a href="https://www.manton.org/2024/05/24/161419.html">Manton just announced</a>. If you&rsquo;re hearing me read these words out aloud, then I guess you could say that it&rsquo;s working. I doubt that I&rsquo;d do this for many of the posts I write here, even the long form ones. It&rsquo;s not really conducive to how I write here: I&rsquo;m hardly Ben Thompson. And I usually find myself having to take several takes just to record something decent (I&rsquo;m already up to take seven or something).</p>
<p>But who knows? Maybe I&rsquo;ll do it more often than I expect. And in either case, it&rsquo;s nice to have the option.</p>
<p>Anyway, I suppose Matt will eventually release an update to Tiny Theme to support this properly. But to tide me over until then, I&rsquo;ve added the following <a href="https://tiny.micro.blog/microhooks/">microhook</a> to include a play button on the post byline:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#75715e">&lt;!-- layouts/partials/microhook-post-byline.html --&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;{{ .Permalink }}&#34;</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;post-date u-url&#34;</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">time</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;dt-published&#34;</span> <span style="color:#a6e22e">datetime</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;{{ .Date.Format &#34;</span><span style="color:#a6e22e">2006-01-02</span> <span style="color:#a6e22e">15:04:05</span> <span style="color:#a6e22e">-0700</span><span style="color:#960050;background-color:#1e0010">&#34;</span> <span style="color:#960050;background-color:#1e0010">}}&#34;</span>&gt;{{ .Date.Format &#34;Jan 2, 2006&#34; }}&lt;/<span style="color:#f92672">time</span>&gt; ∞
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">a</span>&gt;
</span></span><span style="display:flex;"><span>{{ if .Params.audio -}}
</span></span><span style="display:flex;"><span>  {{ with .Params.audio -}}
</span></span><span style="display:flex;"><span>   &lt;<span style="color:#f92672">span</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;byline-separator&#34;</span>&gt;&lt;/<span style="color:#f92672">span</span>&gt;
</span></span><span style="display:flex;"><span>   &lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text/javascript&#34;</span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://micro.blog/narration.js?url={{ . }}&#34;</span>&gt;&lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>  {{ end }}
</span></span><span style="display:flex;"><span>{{ end }}
</span></span></code></pre></div><p>I also add a bit of styling to add a nice bullet separator between that and the date:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#f92672">span</span>.<span style="color:#a6e22e">byline-separator</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">display</span>: <span style="color:#66d9ef">inline-block</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">span</span>.<span style="color:#a6e22e">byline-separator</span>::<span style="color:#a6e22e">after</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">content</span>: <span style="color:#e6db74">&#34;•&#34;</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">padding-left</span>: <span style="color:#ae81ff">7</span><span style="color:#66d9ef">px</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">padding-right</span>: <span style="color:#ae81ff">3</span><span style="color:#66d9ef">px</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">color</span>: <span style="color:#a6e22e">var</span>(<span style="color:#f92672">--</span>accent2);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">div</span>.<span style="color:#a6e22e">microblog_narration_button</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">color</span>: <span style="color:#a6e22e">var</span>(<span style="color:#f92672">--</span>link);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>(Oh, it looks like Manton has updated the Markdown parser to support code fences in the posts screens. That&rsquo;s great.)</p>
<p>I will admit that it&rsquo;s a bit of a rush job: I wanted to add this as quickly as possible. But I guess it&rsquo;ll do until someone with better design skills improves on this.</p>
<audio controls="controls" src="https://cdn.uploads.micro.blog/25293/2024/trying-out-narration.mp3" preload="metadata" style="display: none;">
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2024/trying-out-narration.mp3" type="audio/mpeg" length="1211799"></enclosure>
						<itunes:duration>75</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2023/10/31/while-poking-through.html</link>
				<pubDate>Wed, 01 Nov 2023 07:53:23 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2023/10/31/while-poking-through.html</guid>
				<description><![CDATA[<p>While poking through some old GarageBand projects I came across this track I wrote a few of years ago. I didn&rsquo;t think much of it of the time, but over the last day or so, it&rsquo;s started to grow on me.</p>
<audio src="https://cdn.uploads.micro.blog/25293/2023/drifting-pulsations.mp3" controls>
  <a href="https://cdn.uploads.micro.blog/25293/2023/drifting-pulsations.mp3">Download</a>
</audio>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2023/drifting-pulsations.mp3" type="audio/mpeg" length="10527473"></enclosure>
						<itunes:duration>328</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2023/10/18/more-logic-pro.html</link>
				<pubDate>Wed, 18 Oct 2023 22:11:26 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2023/10/18/more-logic-pro.html</guid>
				<description><![CDATA[<p>More Logic Pro this evening. Here&rsquo;s a recording of the main theme from <em>Tubular Bells 2</em>. Love how the Steinway Grand Piano sounds.</p>
<audio controls src="https://cdn.uploads.micro.blog/25293/2023/tb-ii-main-theme.mp3">
  <a href="https://cdn.uploads.micro.blog/25293/2023/tb-ii-main-theme.mp3">Download</a>
</audio>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2023/tb-ii-main-theme.mp3" type="audio/mpeg" length="2940928"></enclosure>
						<itunes:duration>91</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2023/10/09/launched-logic-pro.html</link>
				<pubDate>Mon, 09 Oct 2023 22:02:54 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2023/10/09/launched-logic-pro.html</guid>
				<description><![CDATA[<p>Launched Logic Pro and did some MIDI recording this evening. Here&rsquo;s an except from &ldquo;Top of the Morning&rdquo; from <em>Tubular Bells 3</em>.</p>
<p><audio controls src="https://cdn.uploads.micro.blog/25293/2023/top-of-the-morning.mp3"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2023/top-of-the-morning.mp3" type="audio/mpeg" length="1587136"></enclosure>
						<itunes:duration>79</itunes:duration>
					
				
			</item>
		
			<item>
				<title></title>
				<link>https://lmika.org/2022/04/09/fired-up-logic-pro-for.html</link>
				<pubDate>Sat, 09 Apr 2022 14:53:00 +1100</pubDate>
				
				<guid isPermaLink="true">https://lmika.org/2022/04/09/fired-up-logic-pro-for.html</guid>
				<description><![CDATA[<p>Fired up Logic Pro for the first time in a while. Trying a rearrangement of <a href="https://souleyedigitalmusic.bandcamp.com/track/passion-for-exploring">Passion for Exploring</a> from the <em>VVVVVV Sound Track</em>. Got the chorus sounding pretty good, although some of the synth attributes need a bit of fine tuning.  Here&rsquo;s a sample of what I&rsquo;ve got so far.</p>
<p><audio controls src="https://cdn.uploads.micro.blog/25293/2022/a50f5fe349.mp3"></audio></p>
]]></description>
				
					
						<enclosure url="https://lmika.org/uploads/2022/a50f5fe349.mp3" type="audio/mpeg"></enclosure>
					
				
			</item>
		
	</channel>
</rss>
