<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Previnder</title><link>https://previnder.com/</link><description>Recent content on Previnder</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 20 Oct 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://previnder.com/index.xml" rel="self" type="application/rss+xml"/><item><title>How to test local area network speed</title><link>https://previnder.com/test-local-network-speed/</link><pubDate>Mon, 20 Oct 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/test-local-network-speed/</guid><description>&lt;p>To test the link speed between two machines on a local network, a method that is often used is to send a file from one machine to the other using a network file sharing protocol such as &lt;a href="https://wiki.archlinux.org/title/Samba">SMB&lt;/a>, &lt;a href="https://wiki.archlinux.org/title/NFS">NFS&lt;/a>, &lt;a href="https://wiki.archlinux.org/title/SSHFS">SSHFS&lt;/a>, or &lt;a href="https://wiki.archlinux.org/title/Rsync">rsync over SSH&lt;/a>.&lt;/p>
&lt;p>Unless one of those protocols is already set up on the two computers, this is a very cumbersome way to test network speeds between them. And if the network is faster than one of the storage devices of the two computers involved, either the one from which the file is read or the one to which the file is written (or both), this method would not test the maximum network speed possible. This can easily happen if one of those storage devices happens to be an old fashioned hard-disk.&lt;/p></description></item><item><title>Ext4 reserves five-percent of the filesystem's available space by default</title><link>https://previnder.com/ext4-reserved-blocks/</link><pubDate>Tue, 14 Oct 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/ext4-reserved-blocks/</guid><description>&lt;p>By default, Ext4 reserves 5% of the filesystem’s block count for the super-user, so that root processes can continue to run without problem even if other non-privileged processes are prevented from writing to the filesystem when it’s full.&lt;/p>
&lt;p>This makes perfect sense for the root partition where the operating system is installed, but for most other partitions, reserving 5% of the disk space for the super-user is probably a waste of storage space.&lt;/p></description></item><item><title>Storing IP addresses in MariaDB</title><link>https://previnder.com/storing-ips-in-mariadb/</link><pubDate>Wed, 16 Jul 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/storing-ips-in-mariadb/</guid><description>&lt;p>What’s the best datatype to store IP addresses as in MariaDB?&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> It’s 2025 and, according to Google, &lt;a href="https://www.google.com/intl/en/ipv6/statistics.html">nearly half the internet now supports IPv6&lt;/a>. So whichever data type is the best, it will have to support both IPv4 and IPv6 addresses.&lt;/p>
&lt;p>There are, in that case, three main options:&lt;/p>
&lt;ol>
&lt;li>&lt;code>VARBINARY(16)&lt;/code>: With this option you could store IPv6 addresses as 16-byte byte-strings and IPv4 addresses as 4-byte byte-strings; or you could store all IP addresses as 16-byte byte-strings by converting all IPv4 addresses to IPv4-mapped IPv6 addresses first.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> If you go with the latter option, then of course the data type could simply be &lt;code>BINARY(16)&lt;/code> instead of &lt;code>VARBINARY(16)&lt;/code>, making the type a little bit simpler and saving you a byte per each row.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/li>
&lt;li>&lt;code>VARCHAR(45)&lt;/code>: This is the simplest option. You just store the IP addresses in their textual representation. Like in the previous option, you could convert IPv4 addresses to IPv4-mapped IPv6 addresses first, but what would be the point?&lt;/li>
&lt;li>&lt;code>INET6&lt;/code>&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>: This is of course the data-type that MariaDB provides for storing IPv6 addresses, as well as IPv4 addresses mapped into IPv6 addresses. Internally, all &lt;code>INET6&lt;/code> values are stored as 16-byte fixed length byte-strings, and clients interacting with MariaDB see them in their textual representation.&lt;/li>
&lt;/ol>
&lt;p>As you might expect, if there’s nothing special that needs to be taken into consideration, &lt;code>INET6&lt;/code> is the best option for storing IP addresses in MariaDB, for several reasons.&lt;/p></description></item><item><title>Make KDE Plasma’s file indexer, Baloo, usable</title><link>https://previnder.com/make-baloo-usable/</link><pubDate>Mon, 28 Apr 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/make-baloo-usable/</guid><description>&lt;p>KDE Plasma is great, but the file indexer that ships with it, Baloo, is not. In fact, it’s terrible. If I leave it as it is, one of its processes, for some reason, inevitably starts using 100% CPU, which I only notice once my laptop starts heating up. You’d think this only happens for a short period of time when a lot of new files are waiting to be indexed at once, but that doesn’t seem to be the case, from what I can tell.&lt;/p></description></item><item><title>Migrating a Progressive Web App (PWA) to a new domain without breaking existing installations</title><link>https://previnder.com/pwa-domain-change/</link><pubDate>Sun, 09 Mar 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/pwa-domain-change/</guid><description>&lt;p>Recently, I migrated &lt;a href="https://discuit.org/">Discuit&lt;/a>, which is a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps">Progressive Web App (PWA)&lt;/a>, from &lt;code>discuit.net&lt;/code> to &lt;code>discuit.org&lt;/code>. Everything went smoothly and seamlessly, I’m glad to say, without it messing up the existing user experience in any way. In fact, had I not made an &lt;a href="https://discuit.org/Discuit/post/FZadJa9b">announcement about it&lt;/a>, most users wouldn’t have even noticed the change.&lt;/p>
&lt;p>Migrating a website to a new domain is usually straightforward, at least for simple websites: a basic HTTP 301 “Moved Permanently” response is often enough to redirect traffic from the old domain to the new. But for PWAs, this approach can break existing installations. This is because a blanket 301 redirect would change the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin">origin&lt;/a> of both the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest">manifest file&lt;/a> and the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">service worker file&lt;/a>, both of which are required to be on the same origin they were first installed from.&lt;/p></description></item><item><title>Setting up a trusted, self-signed SSL/TLS certificate authority in Linux</title><link>https://previnder.com/tls-ca-linux/</link><pubDate>Mon, 17 Feb 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/tls-ca-linux/</guid><description>&lt;p>With OpenSSL, it’s pretty easy to generate a simple &lt;a href="https://en.wikipedia.org/wiki/Self-signed_certificate">self-signed TLS certificate&lt;/a>. Just run the following command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">openssl req -x509 -newkey rsa:4096 -sha256 -days &lt;span class="m">365&lt;/span> -nodes -keyout cert.key -out cert.crt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The files that this command generates, &lt;code>cert.key&lt;/code> and &lt;code>cert.crt&lt;/code>, could be passed to a web server, for example, and it will work fine; that is, all the connections made to that web server will be properly encrypted. The only problem with using this certificate, however, is that our browser doesn’t trust it, because it has not been signed with a &lt;a href="https://en.wikipedia.org/wiki/Certificate_authority">certificate authority&lt;/a> that the browser trusts.&lt;/p></description></item><item><title>How to convert TTF fonts to WOFF2</title><link>https://previnder.com/ttf-to-woff2/</link><pubDate>Wed, 01 Jan 2025 00:00:00 +0000</pubDate><guid>https://previnder.com/ttf-to-woff2/</guid><description>&lt;p>When you download a font from a source like &lt;a href="https://fonts.google.com/">Google Fonts&lt;/a>, it’s likely in either &lt;a href="https://en.wikipedia.org/wiki/TrueType">TTF&lt;/a> or &lt;a href="https://en.wikipedia.org/wiki/OpenType">OTF&lt;/a> formats, the two most widely used font formats in the world. If you’re going to use these fonts on the web, however, it’s a good idea to convert them to &lt;a href="https://en.wikipedia.org/wiki/Web_Open_Font_Format">WOFF2&lt;/a> first, because WOFF2 fonts are significantly smaller in size (WOFF2 fonts are the same as TTF or OTF fonts but compressed).&lt;/p>
&lt;p>Of course, in many cases (as with Google Fonts) one can just use a CDN, but it’s generally a good idea to go to the trouble of self-hosting fonts (on the same domain as your site), rather than using a CDN, as then the fonts would be delivered to the end-user slightly faster when they visit your site. That’s because accessing a CDN involves making additional network requests, DNS lookups, fetching additional CSS files, etc.&lt;/p></description></item><item><title>How to gracefully shutdown a Go HTTP server</title><link>https://previnder.com/shutdown-go-http-server/</link><pubDate>Tue, 03 Dec 2024 00:00:00 +0000</pubDate><guid>https://previnder.com/shutdown-go-http-server/</guid><description>&lt;p>The following code snippet of Go starts a simple HTTP server that responds with “Hello World” to every request it gets.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">	&lt;span class="nx">server&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Server&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">		&lt;span class="nx">Addr&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s">&amp;#34;:8080&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">		&lt;span class="nx">Handler&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">HandlerFunc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">func&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">w&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ResponseWriter&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">r&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Request&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">			&lt;span class="nx">w&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Write&lt;/span>&lt;span class="p">([]&lt;/span>&lt;span class="nb">byte&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">		&lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">	&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">	&lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">server&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ListenAndServe&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">		&lt;span class="nx">log&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Fatal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">err&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">	&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But there’s a small problem: the &lt;code>Server.ListenAndServe&lt;/code> method blocks until the server terminates—until, to be more specific, one of &lt;code>Server.Close&lt;/code> or &lt;code>Server.Shutdown&lt;/code> methods is called, or it encounters a fatal error. In this example, the server never terminates (unless there’s an error), and one would have to terminate the process manually from the outside, by for instance hitting &lt;code>Ctrl+C&lt;/code> and sending an interrupt &lt;a href="https://en.wikipedia.org/wiki/Signal_(IPC)">signal&lt;/a> to the process.&lt;/p></description></item><item><title>By way of beginning</title><link>https://previnder.com/beginning/</link><pubDate>Sat, 16 Nov 2024 00:00:00 +0000</pubDate><guid>https://previnder.com/beginning/</guid><description>&lt;p>There is perhaps a uniquely human instinct to leave our mark on the world, if nothing else to simply say that we were once here to whomever comes later. People have a tendency to carve their names or initials on rocks, trunks of trees, walls, benches, or some other hard surface they know is not going to be withered away by the elements too soon, especially if they’ve spent a lot of time in that place. The image that best illustrates this instinct to me is the stenciled hands humans have left, thousands of years ago, on the walls of &lt;a href="https://en.wikipedia.org/wiki/Cueva_de_las_Manos">Cueva de las Manos&lt;/a>, in Santa Cruz, Argentina.&lt;/p></description></item></channel></rss>