<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>akos.ma</title><link>https://akos.ma/</link><description>Recent content on akos.ma</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Fri, 04 Sep 2026 00:00:00 +0200</lastBuildDate><atom:link href="https://akos.ma/index.xml" rel="self" type="application/rss+xml"/><item><title>Shima Uta</title><link>https://akos.ma/blog/shima-uta/</link><pubDate>Fri, 04 Sep 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/shima-uta/</guid><description><![CDATA[ <p>The year is 2000 or 2001. Argentine comedian <a href="https://en.wikipedia.org/wiki/Alfredo_Casero">Alfredo Casero</a>, known in the country for a quite revolutionary comedy show on TV called <a href="https://en.wikipedia.org/wiki/Cha_Cha_Cha_(TV_series)">&ldquo;Cha Cha Cha&rdquo;</a>, which aired in the early 90&rsquo;s, went to a Japanese restaurant to eat some sushi, a dish that had just arrived to the country and was the latest culinary hype.</p>]]></description><content:encoded><![CDATA[ <p>The year is 2000 or 2001. Argentine comedian <a href="https://en.wikipedia.org/wiki/Alfredo_Casero">Alfredo Casero</a>, known in the country for a quite revolutionary comedy show on TV called <a href="https://en.wikipedia.org/wiki/Cha_Cha_Cha_(TV_series)">&ldquo;Cha Cha Cha&rdquo;</a>, which aired in the early 90&rsquo;s, went to a Japanese restaurant to eat some sushi, a dish that had just arrived to the country and was the latest culinary hype.</p>
<p>In between maki and nigiri, he heard a song on the loudspeakers of the restaurant, called <a href="https://en.wikipedia.org/wiki/Shima_Uta_(The_Boom_song)">&ldquo;Shima Uta&rdquo;</a>, by a Japanese group named <a href="https://en.wikipedia.org/wiki/The_Boom">The Boom</a>. The <em>coup de coeur</em> was immediate.</p>
<p>He asked the waiter for the name of the song, and the next day he somehow found a copy of the CD in Buenos Aires, got obsessed with it, and ended up deciding to record a cover… in Japanese. Because why not.</p>
<p>Needless to say, Alfredo Casero speaks Japanese as well as I speak Klingon. Never mind, Japanese pronounciation is quite easy for Spanish speakers apparently, so he learned the lyrics phonetically, as one does, and recorded the song.</p>
<p>Lo and behold, the song topped the charts in Argentina, and against all odds, even became a hit in Japan.</p>
<p><a href="https://www.youtube.com/watch?v=N7PeM761nFI">The official video</a> of the song features a &ldquo;making of&rdquo; at the end, and it&rsquo;s hilarious.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube-nocookie.com/embed/N7PeM761nFI?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>Not only that, but in 2002 the football world cup took place in Japan &amp; South Korea… and I kid you not, <a href="https://www.youtube.com/watch?v=9NmQ0x1l0Og">The Boom invited Casero</a> to sing the song with them, live, in a stadium in Japan.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube-nocookie.com/embed/9NmQ0x1l0Og?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>There&rsquo;s something unusually Argentine about this whole story. Naive, bold, stupid, brilliant, funny.</p>
]]></content:encoded></item><item><title>30 Years on the Web</title><link>https://akos.ma/blog/30-years-on-the-web/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/30-years-on-the-web/</guid><description><![CDATA[ <p>On Friday, August 30th, 1996, I published a <a href="https://groups.google.com/g/soc.culture.argentina/c/hT3XJv048Z0/m/PDwak0P9qNEJ">message</a> on the &ldquo;soc.culture.argentina&rdquo; <a href="https://en.wikipedia.org/wiki/Usenet">Usenet</a> newsgroup, announcing the existence of a new page on this thing called &ldquo;the web&rdquo;: the URL was <code>http://sc2a.unige.ch/~kosmacze</code> and it was my first personal website.</p>]]></description><content:encoded><![CDATA[ <p>On Friday, August 30th, 1996, I published a <a href="https://groups.google.com/g/soc.culture.argentina/c/hT3XJv048Z0/m/PDwak0P9qNEJ">message</a> on the &ldquo;soc.culture.argentina&rdquo; <a href="https://en.wikipedia.org/wiki/Usenet">Usenet</a> newsgroup, announcing the existence of a new page on this thing called &ldquo;the web&rdquo;: the URL was <code>http://sc2a.unige.ch/~kosmacze</code> and it was my first personal website.</p>
<p>That URL does not exist anymore, and sadly the Internet Archive <a href="https://web.archive.org/web/20260000000000*/http://sc2a.unige.ch/~kosmacze">never archived it</a>. I do have some fragments here and there, in some very old CD-ROMs I burned at the turn of the millenium, but I haven&rsquo;t been able to find a proper, exhaustive backup of the whole thing. To give you an idea, this is what the <a href="https://web.archive.org/web/19961225173704/http://sc2a.unige.ch/">home page of sc2a.unige.ch looked like</a> in December of 1996. This was &ldquo;the web&rdquo;; a bunch of text formatted with Times New Roman, or whatever the default serif font was in your workstation.</p>
<p>In that message I also asked for help, since I was using a text-based operating system (a <a href="https://en.wikipedia.org/wiki/VAX">VAX</a> system running an old version of <a href="https://en.wikipedia.org/wiki/OpenVMS">VMS</a>) and I did not have a computer with Netscape available to test the page. Imagine that. How did I create that content? At home, using <a href="https://en.wikipedia.org/wiki/HoTMetaL">HoTMetaL Pro</a> and an HTML plugin for Microsoft Word 6.0 that could save documents as (horrendous, let&rsquo;s be honest) HTML. Years later I moved into <a href="/blog/editplus/">EditPlus</a>, FrontPage, <a href="/blog/javascript-animations/">Dreamweaver</a>… but not yet at that point. This was just me, most probably Notepad, and some late night HTML knowledge on my PC running Windows 3.1.</p>
<p>How did I get this knowledge? Well, through Elizabeth Castro&rsquo;s awesome <a href="https://www.amazon.com/HTML-World-Visual-QuickStart-Guide/dp/0201884488">HTML Visual Quickstart Guide 1st Edition</a>! The last edition I could find of that book was <a href="https://www.htmlcssvqs.com/">from 2018</a>.</p>
<p>Some of the older articles in this blog were initially published in that page, like for example my tongue-in-cheek <a href="/blog/manuel-pratique-de-lutilisateur-dinternet-et-du-vms-%C3%A0-sc2a.unige.ch-et-%C3%A0-uni2a.unige.ch/">manual</a> for users of the Internet at the sc2a.unige.ch server, or my first <a href="/blog/javascript-calculator/">JavaScript calculator</a>. I even published a journal of my <a href="/blog/1996/">1996</a> trip to Argentina… maybe one day I&rsquo;ll publish it again here.</p>
<p>That website single-handedly kickstarted my <a href="/blog/the-oldest-web-pages-ive-made-still-online/">career</a> as a professional web designer, programmer, and now, 30 years later, software architect. It all boils down to that moment in time, when I used <a href="https://en.wikipedia.org/wiki/File_Transfer_Protocol">FTP</a> to upload those humble HTML files into the VMS account that my university provided their students with.</p>
<p>Since then, web technology evolved in uncanny and extraordinary ways; from the wonder of AJAX, which <a href="/blog/ajax-before-time/">I first saw in action in 2002</a>, to <a href="/blog/macromedia-flash/">Flash movies</a>, to XML, to JSON, to CSS, to WebSockets, to the <code>&lt;canvas&gt;</code> tag, to the incredible <a href="/blog/the-new-clock-and-the-evolution-of-javascript/">evolution</a> of <a href="/blog/douglas-crockford/">JavaScript</a> (both on the <a href="/blog/gamma/">client</a> and <a href="/blog/server-side-javascript-in-1997/">server</a> sides), to <a href="/blog/java-applets-in-2023/">Java applets</a>, to <a href="/blog/conway-in-c89/">WebAssembly</a>, I&rsquo;ve used pretty much every single technology that browsers have made available to us.</p>
<p>It all started the moment I decided to click on the &ldquo;View Source&rdquo; menu on Netscape, and started to learn how websites were made.</p>
]]></content:encoded></item><item><title>Ghostty</title><link>https://akos.ma/blog/ghostty/</link><pubDate>Fri, 21 Aug 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/ghostty/</guid><description> In a previous post I talked about WezTerm, a cross-platform terminal emulator application written in Rust that I liked. This time I&amp;rsquo;m going to talk about another one written in Zig called Ghostty, and I like this one even more.</description><content:encoded><![CDATA[ <p>In a previous post I talked <a href="/blog/adopting-wezterm/">about WezTerm</a>, a cross-platform terminal emulator application written in Rust that I liked. This time I&rsquo;m going to talk about another one written in Zig called Ghostty, and I like this one even more.</p>
<p><a href="https://ghostty.org/">Ghostty</a> is yet another brainchild of <a href="https://mitchellh.com/">Mitchell Hashimoto</a>, of <a href="https://www.hashicorp.com/en">HashiCorp</a> fame.</p>
<p>The installation on Fedora 44 requires a few steps, since it&rsquo;s not available on Flatpak at the moment, nor it is immediately available on standard Fedora repos:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ sudo dnf copr <span style="color:#ec0000">enable</span> scottames/ghostty
</span></span><span style="display:flex;"><span>$ sudo dnf install ghostty
</span></span></code></pre></div><p>I then opened the configuration file <code>~/.config/ghostty/config.ghostty</code> using the <code>CTRL+,</code> (comma) sequence, and added these settings for my personal pleasure:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#5f5fff">app-notifications</span> <span style="color:#ec0000">=</span> <span style="color:#008900">no-clipboard-copy</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">cursor-style</span> <span style="color:#ec0000">=</span> <span style="color:#008900">block</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">cursor-style-blink</span> <span style="color:#ec0000">=</span> <span style="color:#008900">true</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">font-family</span> <span style="color:#ec0000">=</span> <span style="color:#008900">&#34;BlexMono Nerd Font&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">font-size</span> <span style="color:#ec0000">=</span> <span style="color:#008900">16</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">keybind</span> <span style="color:#ec0000">=</span> <span style="color:#008900">F11=toggle_fullscreen</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">link-url</span> <span style="color:#ec0000">=</span> <span style="color:#008900">true</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">maximize</span> <span style="color:#ec0000">=</span> <span style="color:#008900">true</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">shell-integration-features</span> <span style="color:#ec0000">=</span> <span style="color:#008900">no-cursor</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">theme</span> <span style="color:#ec0000">=</span> <span style="color:#008900">light:iTerm2 Light Background,dark:iTerm2 Dark Background</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">window-theme</span> <span style="color:#ec0000">=</span> <span style="color:#008900">system</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">working-directory</span> <span style="color:#ec0000">=</span> <span style="color:#008900">window-inherit-working-directory</span>
</span></span></code></pre></div><p>And conveniently enough, a quick <code>CTRL+SHIFT+,</code> reloads the configuration live after editing the file.</p>
<p>I found Ghostty to be exactly the terminal application I wanted all along; it&rsquo;s fast, cross-platform, convenient, configurable, and it behaves perfectly well.</p>
<p><img src="ghostty.png" alt=""></p>
]]></content:encoded></item><item><title>How to Embed Images as Base64 Strings in Hugo</title><link>https://akos.ma/blog/how-to-embed-images-as-base64-strings-in-hugo/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/how-to-embed-images-as-base64-strings-in-hugo/</guid><description> &lt;p>You can configure your Hugo website to automatically embed an image into a web page as a &lt;a href="https://en.wikipedia.org/wiki/Base64">Base64&lt;/a> string; this post shows you how.&lt;/p></description><content:encoded><![CDATA[ <p>You can configure your Hugo website to automatically embed an image into a web page as a <a href="https://en.wikipedia.org/wiki/Base64">Base64</a> string; this post shows you how.</p>
<p>Let&rsquo;s assume your Markdown posts have this structure:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>title: &#39;Some Title&#39;
</span></span><span style="display:flex;"><span>author: &#39;Jane Smith&#39;
</span></span><span style="display:flex;"><span>excerpt: &#39;Blah blah…&#39;
</span></span><span style="display:flex;"><span>slug: some-title
</span></span><span style="display:flex;"><span>image: some-title.jpg
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>This is my article…
</span></span></code></pre></div><p>Then in your Hugo theme templates you can use code like this to read the image, transform it as Base64, and embed the result on the final HTML:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{- $imgPath := $page.Params.image -}}
</span></span><span style="display:flex;"><span>{{- $image := $page.Resources.GetMatch $imgPath -}}
</span></span><span style="display:flex;"><span>{{- if $image -}}
</span></span><span style="display:flex;"><span>{{- $thumb := $image.Fit &#34;420x420&#34; -}} {{/* Obviously optional */}}
</span></span><span style="display:flex;"><span>{{- $base64 := $thumb.Content | base64Encode -}}
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#ec0000">p</span>&gt;&lt;<span style="color:#ec0000">a</span> <span style="color:#5f5fff">href</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;{{ $page.Permalink }}&#34;</span>&gt;&lt;<span style="color:#ec0000">img</span> <span style="color:#5f5fff">class</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;thumbnail&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5f5fff">src</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;data:{{ $image.MediaType.Type }};base64,{{ $base64 }}&#34;</span>&gt;&lt;/<span style="color:#ec0000">a</span>&gt;&lt;/<span style="color:#ec0000">p</span>&gt;
</span></span><span style="display:flex;"><span>{{- else -}}
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#ec0000">p</span>&gt;&lt;<span style="color:#ec0000">a</span> <span style="color:#5f5fff">href</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;{{ $page.Permalink }}&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    {{ partial &#34;gray-image-placeholder&#34; (dict &#34;className&#34; &#34;thumbnail&#34;) }}&lt;/<span style="color:#ec0000">a</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#ec0000">p</span>&gt;
</span></span><span style="display:flex;"><span>{{- end -}}
</span></span></code></pre></div><p>The <code>gray-image-placeholder</code> shown in the <code>else</code> clause is just a file located in the <code>layouts/partials/</code> folder of your theme, to be used in case the image your specified does not exist, called <code>gray-image-placeholder.html</code> and looking like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#ec0000">img</span> <span style="color:#5f5fff">class</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;{{ .className }}&#34;</span> <span style="color:#5f5fff">src</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;data:image/png;base64,
</span></span></span><span style="display:flex;"><span><span style="color:#008900">iVBORw0KGgoAAAANSUhEUgAABAAAAAMACAIAAAA12IJaAAAABGdBTUEAALGPC/
</span></span></span><span style="display:flex;"><span><span style="color:#008900">xhBQAAAAFzUkdCAdnJLH8AAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgA
</span></span></span><span style="display:flex;"><span><span style="color:#008900">ABdwnLpRPAAAAAlwSFlzAAALEwAACxMBAJqcGAAADS1JREFUeNrt10ENAAAIxDBA9cnHBg
</span></span></span><span style="display:flex;"><span><span style="color:#008900">mthP3WSQoAAPhhJAAAAAMAAAAYAAAAwAAAAAAGAAAAMAAAAIABAAAADAAAAGAAAAAAAwAA
</span></span></span><span style="display:flex;"><span><span style="color:#008900">ABgAAADAAAAAgAEAAAAMAAAAYAAAAAADAAAAGAAAAMAAAAAABg (… snip…)
</span></span></span><span style="display:flex;"><span><span style="color:#008900">AAAYAAAAMAAAAAABgAAADAAAACAAQAAAK5bhvYHaF3qNu4AAAAASUVORK5CYII=&#34;</span>&gt;
</span></span></code></pre></div><p>The <code>className</code> inserted will be the one passed in the <code>(dict)</code> used when calling the partial.</p>
]]></content:encoded></item><item><title>Playing With Admonitions</title><link>https://akos.ma/blog/playing-with-admonitions/</link><pubDate>Fri, 07 Aug 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/playing-with-admonitions/</guid><description><![CDATA[ <p>I&rsquo;ve added the possibility of generating <a href="https://docs.asciidoctor.org/asciidoc/latest/blocks/admonitions/">Asciidoctor-style admonitions</a> to this website, not only in the final HTML generated for this website, but also in the PDF and EPUB outputs, and you might have seen them in action in previous posts.</p>]]></description><content:encoded><![CDATA[ <p>I&rsquo;ve added the possibility of generating <a href="https://docs.asciidoctor.org/asciidoc/latest/blocks/admonitions/">Asciidoctor-style admonitions</a> to this website, not only in the final HTML generated for this website, but also in the PDF and EPUB outputs, and you might have seen them in action in previous posts.</p>
<p>In Asciidoctor and <a href="https://antora.org/">Antora</a> I liked to use such highlighted blocks, to showcase some particular information, so I wanted to have them on this website too. Although, as you might imagine, Markdown does not provide this capability <em>per se</em>.</p>
<p>The Markdown code I use looks like this, showing its corresponding output below.</p>
<h2 id="notes">Notes</h2>
<p>Great for extra information.</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>::: note
</span></span><span style="display:flex;"><span>This is a note.
</span></span><span style="display:flex;"><span>:::
</span></span></code></pre></div><p>NOTE: This is a note.</p>
<h2 id="tips">Tips</h2>
<p>In green, for suggestions or shortcuts.</p>
<pre tabindex="0"><code>::: tip
This is a tip.
:::
</code></pre><p>TIP: This is a tip.</p>
<h2 id="important">Important</h2>
<p>Emphasis you must not miss.</p>
<pre tabindex="0"><code>::: important
This is important.
:::
</code></pre><p>IMPORTANT: This is important.</p>
<h2 id="caution">Caution</h2>
<p>Risk of confusion or bad outcome.</p>
<pre tabindex="0"><code>::: caution
This is a cautionary tale.
:::
</code></pre><p>CAUTION: This is a cautionary tale.</p>
<h2 id="warning">Warning</h2>
<p>To highlight hazard or serious consequences.</p>
<pre tabindex="0"><code>::: warning
This is a warning.
:::
</code></pre><p>WARNING: This is a warning.</p>
<h2 id="pdf-and-epub">PDF and EPUB</h2>
<p>This also works in the <a href="playing-with-admonitions.pdf">PDF</a> and <a href="playing-with-admonitions.epub">EPUB</a> outputs, too.</p>
<p><embed src="playing-with-admonitions.pdf"
width="100%" height="900px" ></p>
]]></content:encoded></item><item><title>How to Solve Webcam Shenanigans With systemd</title><link>https://akos.ma/blog/how-to-solve-webcam-shenanigans-with-systemd/</link><pubDate>Fri, 31 Jul 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/how-to-solve-webcam-shenanigans-with-systemd/</guid><description> &lt;p>Last year I talked about &lt;a href="/blog/my-faithful-logitech-c930e-webcam/">my faithful Logitech C930e webcam&lt;/a>, and at the end of the article I mentioned that I have to manually disable the autofocus, and that sadly that setting is gone at every reboot, and even every time I unplug the webcam; my question then was, can I automate this somehow?&lt;/p></description><content:encoded><![CDATA[ <p>Last year I talked about <a href="/blog/my-faithful-logitech-c930e-webcam/">my faithful Logitech C930e webcam</a>, and at the end of the article I mentioned that I have to manually disable the autofocus, and that sadly that setting is gone at every reboot, and even every time I unplug the webcam; my question then was, can I automate this somehow?</p>
<p>And the answer is yes, of course you can. The first thing I&rsquo;ve done is to change the approach, and instead of manually typing this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ v4l2-ctl --device<span style="color:#ec0000">=</span>/dev/video4 --set-ctrl <span style="color:#ec0000">focus_automatic_continuous</span><span style="color:#ec0000">=</span><span style="color:#008900">0</span>
</span></span></code></pre></div><p>… I took a different approach, using the <code>v4l2ctrl</code> command instead:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ sudo dnf install v4l2ucp
</span></span><span style="display:flex;"><span>$ v4l2ctrl -d /dev/video4 -s camera-settings.txt
</span></span></code></pre></div><p>This saves all settings of the camera in a single text file, and the cool thing is that you can use the <code>-l</code> argument to load them back, and it gives you control over many different parameters of the webcam in one place and you can load them in one shot:</p>
<pre tabindex="0"><code>$ v4l2ctrl -d /dev/video4 -l camera-settings.txt
</code></pre><h2 id="loading-on-startup">Loading on Startup</h2>
<p>Now I need to wrap this command as a <a href="https://en.wikipedia.org/wiki/Systemd">systemd</a> service that is executed every time my my machine boots up, saved in a file named <code>fix-webcam.service</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-systemd" data-lang="systemd"><span style="display:flex;"><span><span style="color:#ec0000">[Unit]</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">Description</span><span style="color:#ec0000">=</span><span style="color:#008900">Fix Logitech webcam autofocus</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ec0000">[Service]</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">Type</span><span style="color:#ec0000">=</span><span style="color:#008900">oneshot</span>
</span></span><span style="display:flex;"><span># Wait 10 seconds for systemd-logind to grant video device permissions
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">ExecStartPre</span><span style="color:#ec0000">=</span><span style="color:#008900">/usr/bin/sleep 10</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">ExecStart</span><span style="color:#ec0000">=</span><span style="color:#008900">/usr/bin/v4l2ctrl -d /dev/video4 -l /home/user/camera-settings.txt</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ec0000">[Install]</span>
</span></span><span style="display:flex;"><span><span style="color:#5f5fff">WantedBy</span><span style="color:#ec0000">=</span><span style="color:#008900">default.target</span>
</span></span></code></pre></div><p>I installed this service it in my local systemd user folder:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ mkdir -p ~/.config/systemd/user
</span></span><span style="display:flex;"><span>$ mv fix-webcam.service ~/.config/systemd/user/fix-webcam.service
</span></span><span style="display:flex;"><span>$ systemctl --user daemon-reload
</span></span><span style="display:flex;"><span>$ systemctl --user <span style="color:#ec0000">enable</span> fix-webcam.service
</span></span></code></pre></div><p>TIP: Yes, you can also use symbolic links and store the services somewhere else.</p>
<p>Et voilà! Now this service is executed every time I start my machine. But what happens if I unplug the webcam? Then the settings would be gone again. Worry not! Turns out, there&rsquo;s a way to trigger the systemd service above whenever a USB device is plugged.</p>
<h2 id="loading-on-unplug--replug">Loading on Unplug &amp; Replug</h2>
<p>First plug your webcam, and find the ID of your USB device:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ lsusb  | grep 046d
</span></span><span style="display:flex;"><span>Bus <span style="color:#008900">003</span> Device 032: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver
</span></span><span style="display:flex;"><span>Bus <span style="color:#008900">003</span> Device 034: ID 046d:0843 Logitech, Inc. Webcam C930e
</span></span></code></pre></div><p>The <code>046d</code> vendor ID corresponds to Logitech, and in the case of my C930e webcam, <code>0843</code> is the product ID. I also have a wireless Logitech MX Master 3S mouse, so the dongle appears there as well.</p>
<p>Then, as a superuser, I created a new file called <code>/etc/udev/rules.d/99-dock-fixes.rules</code> with the following contents:</p>
<pre tabindex="0"><code># Trigger the webcam script when the Logitech camera is plugged in
ACTION==&#34;bind&#34;, SUBSYSTEM==&#34;usb&#34;, ATTR{idVendor}==&#34;046d&#34;, ATTR{idProduct}==&#34;0843&#34;, TAG+=&#34;systemd&#34;, ENV{SYSTEMD_USER_WANTS}+=&#34;fix-webcam.service&#34;
</code></pre><p>Then reload the changes, and trigger the action to test it:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ sudo udevadm control --reload-rules
</span></span><span style="display:flex;"><span>$ sudo udevadm trigger --action<span style="color:#ec0000">=</span><span style="color:#ec0000">bind</span>
</span></span></code></pre></div><p>TIP: I could verify the changes with another tmux panel showing the output of the following command: <code>watch &quot;v4l2-ctl --list-ctrls --device /dev/video4 | grep focus_automatic&quot;</code></p>
<p>Et voilà (bis)! Now every time, a few seconds after I re-plug your webcam, my preferred settings apply.</p>
<p>NOTE: In the code above I&rsquo;m using the <code>bind</code> action instead of <code>add</code>, for a reason; you should know that when you plug in a USB device, <code>ACTION==&quot;add&quot;</code> fires the exact millisecond the metal connects, before Linux has actually loaded the webcam or audio drivers. Sometimes, <code>udev</code> refuses to trigger the systemd service because the underlying device nodes don&rsquo;t fully exist yet. Instead, <code>bind</code> tells <code>udev</code> to wait until the Linux drivers have actually attached to the hardware before triggering the service.</p>
]]></content:encoded></item><item><title>Birome</title><link>https://akos.ma/blog/birome/</link><pubDate>Fri, 24 Jul 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/birome/</guid><description><![CDATA[ <p>In Argentina we like to tell this urban legend that is somehow kind-of-true, that the <a href="https://en.wikipedia.org/wiki/Ballpoint_pen">ballpoint pen</a> was invented there, thanks to the idea of a Hungarian-born man called <a href="https://en.wikipedia.org/wiki/L%C3%A1szl%C3%B3_B%C3%ADr%C3%B3">László Bíró</a> who moved to Argentina at some point during World War II.</p>]]></description><content:encoded><![CDATA[ <p>In Argentina we like to tell this urban legend that is somehow kind-of-true, that the <a href="https://en.wikipedia.org/wiki/Ballpoint_pen">ballpoint pen</a> was invented there, thanks to the idea of a Hungarian-born man called <a href="https://en.wikipedia.org/wiki/L%C3%A1szl%C3%B3_B%C3%ADr%C3%B3">László Bíró</a> who moved to Argentina at some point during World War II.</p>
<p>This story is not entirely true in the sense that when Bíró came to Argentina he had <em>already</em> invented the ballpoint pen (actually, it was invented by <a href="https://en.wikipedia.org/wiki/John_J._Loud">somebody else</a>, but that early patent lapsed without commercial distribution). The first large-scale production and commercialization of the ballpoint pen started and spread from there, through the &ldquo;Bíró &amp; Meyne&rdquo; company. And yes, in Argentina we still refer to ballpoint pens as &ldquo;biromes&rdquo; (derived from the company name), and I&rsquo;m not kidding, that&rsquo;s really how we call them, and that&rsquo;s how I&rsquo;ll call them in this article.</p>
<p>Then the story goes that a French man called <a href="https://en.wikipedia.org/wiki/Marcel_Bich">Marcel Bich</a> bought Bíró&rsquo;s patent, and thus begat the <a href="https://en.wikipedia.org/wiki/Bic_Cristal">Bic Cristal</a> ballpoint pen that we all know, somewhere between the 1950s and 60s. And this is the gist of this article.</p>
<p>Because for all practical purposes, I consider the birome (specifically, the Bic Cristal) to be the most important invention of the 20th century. Yes: more important even that aeroplanes, computers, antibiotics, cell phones, tamagotchis, space travel, Walkmans, Pink Floyd, paperback books, or whatever else that came up during that time. The Bic Cristal is inexpensive (like, dirt cheap, not even 0.22 CHF per unit <a href="https://www.galaxus.ch/en/s12/product/bic-cristal-original-100x-pens-14555783">from Galaxus</a>, that&rsquo;s like 0.27 USD or 0.24 EUR), durable, lightweight, trustworthy, ubiquitous, simple, practical, reliable, and I&rsquo;m running out of positive adjectives as I write this. And no, no other brand of birome can reach the quality of the Bic Cristal, not even remotely. All other biromes just plain suck in one way or another.</p>
<p>The Bic Cristal birome is a triumph of human engineering and ingenuity. It&rsquo;s so good it hurts. Paraphrasing Steve Jobs, it&rsquo;s like a bicycle for your hand.</p>
<p>Not many technologies created by humans can claim to be so deceptively useful and trustworthy at the same time. The birome is the most important invention of the 20th century because it democratized, without pretention and without limits, writing for everyone, everywhere, at every time.</p>
<p>No matter how many other kinds of pens I try (and believe me, I love my <a href="https://pentel.ch/energel/">Pentel EnerGel</a> pens, I truly do) I <em>always</em> come back to the Bic Cristal. It&rsquo;s the pen I used throughout primary and high school (except for a short while in early primary school, when my teachers insisted we use fountain pens for some pedantic reason).</p>
<p>I simply love the ink quality (it dries in literal milliseconds and never ever fades away from paper) and how lightweight it feels on my hand. Its transparency tells you how much ink remains on it, and the cap fits perfectly on the opposite side while you write, providing a very nice counterweight on your fingers.</p>
<p>The birome feels surprisingly good in your hand. But, of course, writing is out-of-fashion these days, just like reading, or more generally, just like thinking.</p>
<p>As the Joker <a href="https://www.youtube.com/watch?v=IEuB3bAgdjY">said</a> in the 1989 &ldquo;Batman&rdquo; movie,</p>
<blockquote>
<p>The pen is truly mightier than the sword.</p>
</blockquote>
<p>And in that category, the Bic Cristal birome is the mightiest of them all.</p>
]]></content:encoded></item><item><title>Ubuntu 5.10 on QEMU</title><link>https://akos.ma/blog/ubuntu-5.10-on-qemu/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/ubuntu-5.10-on-qemu/</guid><description><![CDATA[ <p>Following the celebration of my <a href="/blog/20-years-of-linux/">20 years with Linux</a>, I wanted to recreate the moment I installed Ubuntu &ldquo;Breezy Badger&rdquo; 5.10 for the first time, and with <a href="https://www.qemu.org/">QEMU</a> it was quite easy to do on my modern Fedora 44 environment of 2026.</p>]]></description><content:encoded><![CDATA[ <p>Following the celebration of my <a href="/blog/20-years-of-linux/">20 years with Linux</a>, I wanted to recreate the moment I installed Ubuntu &ldquo;Breezy Badger&rdquo; 5.10 for the first time, and with <a href="https://www.qemu.org/">QEMU</a> it was quite easy to do on my modern Fedora 44 environment of 2026.</p>
<h2 id="install-and-run">Install and Run</h2>
<p>First of all I downloaded the <a href="https://old-releases.ubuntu.com/releases/breezy/ubuntu-5.10-install-i386.iso">install CD for i386</a> of that old release, <a href="https://old-releases.ubuntu.com/releases/breezy/">still available</a> on the Ubuntu website after all these years.</p>
<p>Once that was done, I proceeded to create a QEMU virtual hard disk to install the OS into:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ qemu-img create -f qcow2 ubuntu.qcow2 30G
</span></span></code></pre></div><p>Then, just launch a new virtual machine, booting from the virtual CD-ROM drive first, emulating a gigabyte of RAM, which is a reasonable amount for a computer of 2005:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ qemu-system-i386 <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -m <span style="color:#008900">1024</span> <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -cdrom ubuntu-5.10-install-i386.iso <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -drive <span style="color:#ec0000">file</span><span style="color:#ec0000">=</span>ubuntu.qcow2,format<span style="color:#ec0000">=</span>qcow2 <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -boot d <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -no-reboot
</span></span></code></pre></div><p>The VM boots, and you&rsquo;re immediately taken to the installation process. Select your locale and keyboard, and choose the defaults for the graphics card. Enter your desired hostname, timezone, and create a new user for your installation. The whole process takes a while to finish.</p>
<p>Once this is done, the VM shuts down automatically instead of rebooting (thanks to the <code>-no-reboot</code> option) and then you must start it back again, directly from the hard disk this time:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ qemu-system-i386 <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -m <span style="color:#008900">1024</span> <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -drive <span style="color:#ec0000">file</span><span style="color:#ec0000">=</span>ubuntu.qcow2,format<span style="color:#ec0000">=</span>qcow2 <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -boot c <span style="color:#008900">\
</span></span></span><span style="display:flex;"><span>  -full-screen
</span></span></code></pre></div><p class="shadow"><img src="ubuntu-5.10-booting.png" alt=""></p>
<p>The operating system boots into a configuration phase, and after a few minutes, voilà! Ubuntu &ldquo;Breezy Badger&rdquo; 5.10 on your screen, 21 years later:</p>
<p><img src="ubuntu-5.10-running.png" alt=""></p>
<p>The default system includes quite a lot of software, including OpenOffice, Firefox, and whatnot. It was quite an impressive offering, all for free, and immediately compatible with pretty much every personal computer available to the public in 2005. No wonder Ubuntu became so popular back in the day.</p>
<h2 id="ppc-shenanigans">PPC Shenanigans</h2>
<p>Before reaching this point, I tried unsuccessfully to run the PPC version of Ubuntu Badger, which was the one I installed on my <a href="https://en.wikipedia.org/wiki/IBook#iBook_G3_Dual_USB_(%22Snow%22,_2001-2003)">&ldquo;Snow&rdquo; iBook G3</a> 21 years ago.</p>
<p>I gave a short description of that machine <a href="/blog/xubuntu/">in an old article</a> on this blog:</p>
<blockquote>
<p>The main machine where I have Xubuntu installed is a rather old G3 iBook that I bought in 2002, with only 256 MB of RAM and 30 GB of hard disk. The machine runs like a charm, but of course with GNOME and KDE there’s a lot of swapping. As soon as I installed the Xfce desktop, things went really faster. I can only recommend using Xubuntu in old machines: the base system only takes 90 MB of RAM, and applications load faster than in GNOME or KDE.</p>
</blockquote>
<p>Let&rsquo;s all take a minute to consider that a modern operating system, running very decent software, could run in just 256 MB of RAM. <em>Le sigh</em>.</p>
<p>I first used the <code>qemu-system-ppc</code> command, with the <code>-M mac99,via=pmu</code> argument, to help this old Ubuntu recognize my mouse and keyboard. In particular, the <code>via=pmu</code> argument supposedly is meant to route the input devices through something called the &ldquo;Power Management Unit&rdquo;, expected by Ubuntu PPC kernels back in the day. I also tried using the <code>-cpu g3</code> and the <code>-vga std</code> options in various iterations.</p>
<p>After the installation (which was somewhat successful), I had to boot the VM the <code>-prom-env &quot;boot-device=hd:,\yaboot&quot;  -prom-env &quot;boot-args=conf=hd:,\yaboot.conf&quot;</code> arguments, because otherwise the VM defaults to looking for an Apple bootloader… which doesn&rsquo;t exist in this context for obvious reasons. Instead we ask the VM to boot directly from <a href="https://en.wikipedia.org/wiki/Yaboot">Yaboot</a>.</p>
<p>But the biggest drawback was that the installer failed to correctly setup the <a href="https://en.wikipedia.org/wiki/X.Org_Server">X.org</a> server, and thus no desktop would ever appear on screen. This is without mentioning that QEMU had to translate all PPC instructions to the x86_64 architecture of my laptop, which meant that the whole system was reaaaaaaally sluggish.</p>
<p>So, at the end of the day, the i386 version was perfect for the purposes of memorabilia.</p>
<p>At this point in my laptop I have emulators for <a href="/blog/word-5.5-on-dosbox/">MS-DOS</a>, <a href="/blog/word-5.1a-and-excel-4-for-mac-on-basilisk-ii/">Mac OS System 7.5</a>, <a href="/blog/freedos-on-qemu/">FreeDOS</a>, <a href="/blog/alpine-linux-in-virtualbox/">Alpine Linux</a>, and now also Ubuntu 5.10 for 32-bit i386.</p>
]]></content:encoded></item><item><title>Tango</title><link>https://akos.ma/blog/tango/</link><pubDate>Fri, 10 Jul 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/tango/</guid><description><![CDATA[ <p>Ah, so you think I&rsquo;m going to talk about the dance called <a href="https://en.wikipedia.org/wiki/Tango">Tango</a>; but no, this time I&rsquo;m going to talk about an <a href="https://es.wikipedia.org/wiki/Tango_(%C3%A1lbum_de_Charly_Garc%C3%ADa_y_Pedro_Aznar)">album called &ldquo;Tango&rdquo;</a>, by those two towering figures of <a href="/blog/the-very-quick-and-sloppy-guide-to-argentine-rock/">Argentine rock</a>, namely <a href="https://en.wikipedia.org/wiki/Charly_Garc%C3%ADa">Charly García</a> and <a href="https://es.wikipedia.org/wiki/Pedro_Aznar">Pedro Aznar</a>.</p>]]></description><content:encoded><![CDATA[ <p>Ah, so you think I&rsquo;m going to talk about the dance called <a href="https://en.wikipedia.org/wiki/Tango">Tango</a>; but no, this time I&rsquo;m going to talk about an <a href="https://es.wikipedia.org/wiki/Tango_(%C3%A1lbum_de_Charly_Garc%C3%ADa_y_Pedro_Aznar)">album called &ldquo;Tango&rdquo;</a>, by those two towering figures of <a href="/blog/the-very-quick-and-sloppy-guide-to-argentine-rock/">Argentine rock</a>, namely <a href="https://en.wikipedia.org/wiki/Charly_Garc%C3%ADa">Charly García</a> and <a href="https://es.wikipedia.org/wiki/Pedro_Aznar">Pedro Aznar</a>.</p>
<p>Now, you&rsquo;re reading this and you&rsquo;re probably asking yourself, why? As <a href="https://en.wikipedia.org/wiki/Simon_Sinek">Simon Sinek</a> once said, <a href="https://en.wikipedia.org/wiki/Start_with_Why">start with why</a>: why, why, why does this guy always talk to us without talking to us. Why, why, why.</p>
<p>Well, I&rsquo;ll tell you why. Because I am talking to you. More precisely, <a href="https://www.youtube.com/watch?v=Z7AERldCALc">I&rsquo;m talking to your heart</a>, which is exactly the title of a song by our national hero Charly García, released in &ldquo;Tango&rdquo; on March 29th, 1986, that is, a bit over 40 years ago, and I&rsquo;ll leave it up to you to Google Translate the <a href="https://genius.com/Charly-garcia-y-pedro-aznar-hablando-a-tu-corazon-lyrics">lyrics</a>, which are sublime.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube-nocookie.com/embed/Z7AERldCALc?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>Oh yeah, it does sound 1980s, huh? Those synths. THOSE SYNTHESIZERS.</p>
<p>Charly, being the superstar he still is (regardless of his substance abuse) has had <a href="https://es.wikipedia.org/wiki/Hello!_MTV_Unplugged">his own MTV Unplugged</a> album in the 1990s, because it was such a tradition, and within that Unplugged album there&rsquo;s another song I deeply love, (originally released together in the same album &ldquo;Tango&rdquo;), and that other incredible song is called <a href="https://www.youtube.com/watch?v=Fy1WuMSC7Wg">&ldquo;Pasajera en Trance&rdquo;</a>, and here it goes again because reasons. It speaks of distance, flow, travel, and so many other things.</p>
<p>&ldquo;She dances on the sea&rdquo;, says Charly.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube-nocookie.com/embed/Fy1WuMSC7Wg?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>OK, here go the lyrics, because they are out-of-this-world. Enjoy.</p>
<blockquote>
<p>She’s about to board, <br>
maybe she’ll snag a seat on the deck. <br>
She’s about to take off, <br>
she’s leaving. <br>
She travels without paying, <br>
the old trick of walking in the shadows. <br>
She dances on the sea, <br>
she’s leaving. <br>
Passenger in a trance, <br>
passenger in perpetual transit. <br>
Passenger in a trance, <br>
passing through the right places. <br>
True love, <br>
is like sleeping and being awake. <br>
True love, <br>
is like living in an airport.</p>
</blockquote>
<p>As Charly says at the end, &ldquo;merci beaucoup&rdquo;.</p>
]]></content:encoded></item><item><title>NeXTClock</title><link>https://akos.ma/blog/nextclock/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0200</pubDate><guid>https://akos.ma/blog/nextclock/</guid><description><![CDATA[ <p>So here is a new project on GitLab called <a href="https://gitlab.com/akosma/nextclock">NeXTClock</a>: a small browser-based recreation of a NeXTSTEP-style clock applet from the 1990s. This modern version renders a 64-unit clock face into a square <code>&lt;canvas&gt;</code> using JavaScript and <code>requestAnimationFrame()</code>, with optional scaling from 64 to 500 pixels, because, well, Java Applets <a href="/blog/java-applets-in-2023/">aren&rsquo;t really a thing anymore</a>.</p>]]></description><content:encoded><![CDATA[ <p>So here is a new project on GitLab called <a href="https://gitlab.com/akosma/nextclock">NeXTClock</a>: a small browser-based recreation of a NeXTSTEP-style clock applet from the 1990s. This modern version renders a 64-unit clock face into a square <code>&lt;canvas&gt;</code> using JavaScript and <code>requestAnimationFrame()</code>, with optional scaling from 64 to 500 pixels, because, well, Java Applets <a href="/blog/java-applets-in-2023/">aren&rsquo;t really a thing anymore</a>.</p>
<h2 id="background">Background</h2>
<p>The original source code of the Java applet came from the <a href="https://web.archive.org/web/19981207040305/http://the-labs.com/NeXTClock/">Internet Archive</a>. This original <code>NeXTClock</code> applet was written by <a href="https://renekmueller.com/">Rene K. Mueller</a> and is preserved in <code>original/NeXTClock.java</code> in the GitLab project. That applet used <a href="https://en.wikipedia.org/wiki/Abstract_Window_Toolkit">AWT</a>, a background GIF, and a thread that updated the displayed time. I used that Java applet in my <a href="/blog/gamma/">&ldquo;GaMMA&rdquo; home page</a> around 1999, until 2004.</p>
<p>Interestingly enough, the original Java version was written almost exactly 30 years ago at the time of this article:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>// --- NeXTClock, written by Rene K. Mueller &lt;kiwi@the-labs.com&gt;
</span></span><span style="display:flex;"><span>//     V0.20: Jul 20, 1996
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ec0000">import</span> java.awt.Graphics;
</span></span><span style="display:flex;"><span><span style="color:#ec0000">import</span> java.awt.Image;
</span></span><span style="display:flex;"><span><span style="color:#ec0000">import</span> java.awt.Color;
</span></span><span style="display:flex;"><span><span style="color:#ec0000">import</span> java.awt.Font;
</span></span><span style="display:flex;"><span><span style="color:#ec0000">import</span> java.awt.FontMetrics;
</span></span><span style="display:flex;"><span><span style="color:#ec0000">import</span> java.util.Date;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ec0000">public</span> <span style="color:#ec0000">class</span> <span style="color:#5f5fff">NeXTClock</span> <span style="color:#ec0000">extends</span> java.<span style="color:#5f5fff">applet</span>.<span style="color:#5f5fff">Applet</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ec0000">implements</span> Runnable {
</span></span><span style="display:flex;"><span>// ...
</span></span></code></pre></div><p>The translated source code in JavaScript in <code>src/NeXTClock.js</code> keeps the same 64 x 64 layout and the same visual idea: a NeXT-like clock tile with the weekday, day of the month, month, green seven-segment time, and blinking separator pixels. The drawing code scales that original layout to fit larger square canvases while preserving the pixelated look.</p>
<h2 id="usage">Usage</h2>
<p>Include <code>NeXTClock.js</code>, add a <code>&lt;CANVAS&gt;</code> object on your page, then create and start a clock:</p>
<div class="highlight"><pre tabindex="0" style="color:#757575;background-color:#000;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#ec0000">script</span> <span style="color:#5f5fff">src</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;NeXTClock.js&#34;</span>&gt;&lt;/<span style="color:#ec0000">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#ec0000">canvas</span> <span style="color:#5f5fff">id</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;clock&#34;</span> <span style="color:#5f5fff">width</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;128&#34;</span> <span style="color:#5f5fff">height</span><span style="color:#ec0000">=</span><span style="color:#008900">&#34;128&#34;</span>&gt;&lt;/<span style="color:#ec0000">canvas</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#ec0000">script</span>&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#ec0000">const</span> canvas <span style="color:#ec0000">=</span> <span style="color:#ec0000">document</span>.getElementById(<span style="color:#008900">&#34;clock&#34;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#ec0000">const</span> clock <span style="color:#ec0000">=</span> <span style="color:#ec0000">new</span> NeXTClock(canvas, {
</span></span><span style="display:flex;"><span>    size<span style="color:#ec0000">:</span> <span style="color:#008900">128</span>,
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  clock.start();
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#ec0000">script</span>&gt;
</span></span></code></pre></div><p><noscript><img src="noscript.png" alt=""></noscript></p>
<p align="center">
<canvas id="clock1" width="64" height="64"></canvas>
&nbsp;
<canvas id="clock2" width="128" height="128"></canvas>
&nbsp;
<canvas id="clock3" width="256" height="256"></canvas>
</p>
<p style="text-align: center"><input type="button" id="startButton" value="Start"> <input type="button" id="stopButton" value="Stop"> <span id="timeSpan"></span><br>
<input type="range" min="0" max="1440" value="0" step="1" id="timeRange" style="width: 80%"></p>
<script src="NeXTClock.js"></script>
<script src="app.js"></script>
<p>The constructor expects an <code>HTMLCanvasElement</code>. By default, it uses the canvas display size and keeps it square. You can also pass a <code>size</code> option or call <code>setSize()</code> later; requested sizes are rounded and clamped between 64 and 500 pixels.</p>
<p>Available methods on the class:</p>
<ul>
<li><code>start()</code> begins animation using <code>requestAnimationFrame()</code>.</li>
<li><code>stop()</code> cancels the animation frame loop.</li>
<li><code>draw(date)</code> draws one frame for the supplied <code>Date</code>, or the current local time when omitted.</li>
<li><code>setSize(size)</code> updates the square canvas size and redraws the clock.</li>
</ul>
<p>You can pass the following options to the constructor:</p>
<ul>
<li><code>backgroundSrc</code>: optional path to a background image. When omitted, the built-in canvas background is used.</li>
<li><code>darkGreen</code>: color used for the seven-segment time display. Defaults to <code>#00c800</code>.</li>
<li><code>size</code>: optional square canvas size in pixels, clamped from 64 to 500.</li>
</ul>
<p>The clock automatically observes canvas resizing when <code>ResizeObserver</code> is available, so CSS-driven size changes are reflected in the next rendered frame.</p>
<p>As usual, you can grab the source code <a href="https://gitlab.com/akosma/nextclock">on my GitLab account</a>.</p>
]]></content:encoded></item></channel></rss>