<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xml:base="https://nick.tay.blue/">
<channel>
	<title>Nicholas Tay</title>
	<description>Miscellaneous, but probably tech-related personal posts.</description>
	<language>en-au</language>
	<link>https://nick.tay.blue/</link>
	<atom:link href="https://nick.tay.blue/rss.xml" rel="self" type="application/rss+xml" /><item>
		<title>Enabling wake-on-LAN in Linux</title>
		<guid>https://nick.tay.blue/2025/03/05/wol/</guid>
		<link>https://nick.tay.blue/2025/03/05/wol/</link>
		<pubDate>05 Mar 25 00:00 UTC</pubDate>
		<description><![CDATA[<p>This is probably a pretty simple, well-documented post, but just for my own reference (as usual!). I was sad when I tried to WoL (via jumpbox) after booting into Linux whilst away from home for a couple days and it didn&rsquo;t work&hellip;</p>
<p>First, we just need to make sure the usual BIOS setting (Wake-on-LAN, Magic Packet, etc&hellip;) is enabled. &ndash; In my case on ASRock this was actually called &ldquo;PCIE Devices Power On&rdquo;. I&rsquo;m also on a Realtek card.</p>
<p>Then, the <em>simplest</em> form of this is ensure the NIC is configured to still idle for the magic packet while sleeping (as root, where enp5s0 is my main NIC):</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ ethtool -s enp5s0 wol g
</span></span></code></pre></div><p>&hellip; where &lsquo;g&rsquo; means &lsquo;Wake on MagicPacket™&rsquo; (see ethtool man page for more details!). This should be run <strong>every reboot</strong> to make sure the NIC is still configured as such.</p>
<p>To confirm settings:</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ ethtool enp5s0
</span></span><span style="display:flex;"><span>Settings <span style="color:#8839ef">for</span> enp5s0:
</span></span><span style="display:flex;"><span>	Supported ports: <span style="color:#04a5e5;font-weight:bold">[</span> TP	MII <span style="color:#04a5e5;font-weight:bold">]</span>
</span></span><span style="display:flex;"><span>	...
</span></span><span style="display:flex;"><span>	...
</span></span><span style="display:flex;"><span>	Wake-on: g
</span></span><span style="display:flex;"><span>	Link detected: yes
</span></span></code></pre></div><p>Notice that &lsquo;Wake-on&rsquo; is &lsquo;g&rsquo;. By default (at least for me), this was &rsquo;d&rsquo; for disabled.</p>
<p><strong>If you are using NetworkManager</strong> though, like the default in Fedora and as such, my setup, a more elegant solution could be to have that manage it for us. This is also quite easy, but perhaps less simple:</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ nmcli connection show
</span></span><span style="display:flex;"><span>NAME                      UUID                                  TYPE       DEVICE     
</span></span><span style="display:flex;"><span>Wired connection <span style="color:#fe640b">1</span>        3.......-....-....-....-...........d  ethernet   enp5s0
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># (My desired one is &#39;Wired connection 1&#39;)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ nmcli connection modify <span style="color:#40a02b">&#34;Wired connection 1&#34;</span> 802-3-ethernet.wake-on-lan magic
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ nmcli device reapply enp5s0
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># (Note &#39;enp5s0&#39; should be the device in the profile you edited as above &#39;show&#39;)</span>
</span></span></code></pre></div><p>After this, you can validate using &rsquo;ethtool&rsquo; as prior simplistic approach that it all worked.</p>
<p>As usual (i.e. Windows), it may take your computer an <strong>extra reboot</strong> to get things to work. Always try that first if WoL doesn&rsquo;t work right away! (I got stuck for a while before on an older PC because of this.)</p>
<hr>
<p><strong>Bonus</strong>: Windows. A similar extra config is usually also required, at least for Realtek as I&rsquo;ve used. Usually you&rsquo;ll need the Realtek drivers installed, then in the &lsquo;Advanced&rsquo; section of the NIC properties, there&rsquo;s a &lsquo;Wake on Magic Packet&rsquo; setting you&rsquo;ll need to enable. Then reboot once and/or twice if required and it should &lsquo;just work&rsquo;.</p>
<hr>
<p><strong>Bonus II</strong>: How to actually WoL? I typically have this saved in a script on my jumpbox (Rocky Linux, <code>net-tools</code> package, as root, where enp1s0 is the network interface on the same network as the main PC): <code>ether-wake -i enp1s0 &lt;main:pc:mac:address:here&gt;</code></p>
<p>(As usual, the MAC address of the main PC can be found with e.g. <code>ip addr show dev enp5s0</code>.)</p>
]]></description>
	</item><item>
		<title>mysqld got signal 6 ... InnoDB give my data back!</title>
		<guid>https://nick.tay.blue/2025/02/06/mysql-bricked/</guid>
		<link>https://nick.tay.blue/2025/02/06/mysql-bricked/</link>
		<pubDate>06 Feb 25 00:00 UTC</pubDate>
		<description><![CDATA[<p>The other weekend I was back in Melbourne (for Chinese New Year &ndash; happy new year!) and was extracting some data off a dead BTRFS (<em>I know, this was probably done to myself</em>) RAID 1&rsquo;d Proxmox setup.</p>
<p>Probably due to an unclean shutdown and/or filesystem woes, my MariaDB setup (in an Alpine LXC, for Nextcloud) got corrupted. Unfortunately, remaining backups were also months old, given I was relying on my university storage for it (haha), and all I had was an old copy of the setup on my old &lsquo;server&rsquo;.</p>
<p>To be honest, the old backup was probably enough, but I decided to take the challenge on vs MySQL &ndash; I use it enough at work to warrant messing with it.</p>
<hr>
<h2 id="preparation">Preparation</h2>
<p>So, the first step (after some simple attempts on the original LXC itself) was copying off the data to a more stable environment to work on (who knows how else LXC could be screwing with things).</p>
<ul>
<li>I decided to simply use a Rocky Linux VM that was already lying around.</li>
<li>Originally, I tried using the MariaDB in the system repos, but that didn&rsquo;t help, and so eventually switched to the <a href="https://mariadb.com/kb/en/yum/">MariaDB-official dnf repo</a> (*more to come here :D)
<ul>
<li>This was to try installing the latest versions and thinking maybe a later InnoDB engine would be more kind.</li>
<li>If you&rsquo;re going to do this, ensure the official <code>mariadb-server</code> package is removed, then replace it with <code>MariaDB-server</code> with the new repo in place.</li>
</ul>
</li>
</ul>
<h2 id="initial-attempts-innodb-force-recovery-modes">Initial attempts: InnoDB force-recovery modes</h2>
<p>So, at first&hellip;</p>
<ul>
<li>I had copied the data as-it-was into <code>/root/ncsql</code>.</li>
<li>Then, just tried firing the database back up with the newer MariaDB, simply in the foreground (no need to mess with systemd/etc!) with: <code>mysqld_safe --datadir /root/ncsql --user root</code>.
<ul>
<li>The <code>--user root</code> in my case was simply out of laziness &ndash; I don&rsquo;t care for security given this is a rescue operation, in a disposable VM, and the files were owned by root given how I copied them across</li>
<li>The dreaded &lsquo;mysqld got signal 6&rsquo; then arrived &ndash; process in foreground just stopped, and a stackdump with the message appeared in the log file. If we follow their instructions first, we would try starting with the various <a href="https://mariadb.com/kb/en/innodb-recovery-modes/">InnoDB recovery modes</a> (i.e. from my understanding, relaxing invariants to hopefully &lsquo;just&rsquo; load things back).</li>
</ul>
</li>
<li>Increasingly to the <code>mysqld_safe</code> command line, add the <code>--innodb-force-recovery 1</code> flag and value, slowly increasing until the maximum of 6.</li>
</ul>
<p>If your database fires up OK here with one of these modes &ndash; good news! It &lsquo;just&rsquo; worked. Jump to the dump+restore section below.</p>
<p>But, if you&rsquo;re like me, there&rsquo;s more fun to be had&hellip;</p>
<h2 id="force-recovery-failed-now-what">Force-recovery failed, now what&hellip;</h2>
<p>So, after a recovery level of 2, all the way to 6, I started getting &lsquo;mysqld got signal 11&rsquo; now, with much worse looking stack dumps.</p>
<p>Even MariaDB itself was thinking this could be a software bug of itself, given how corrupted things were.</p>
<p><em>(This was the point where originally, I tried copying it off to the VM, trying newer MariaDB versions, etc. Until all of that didn&rsquo;t work, and I scoured around for what others could have done.)</em></p>
<p>I then stumbled across this <a href="https://stackoverflow.com/a/16720185">older XAMPP related crashed MySQL StackOverflow post+answer</a>. After a bunch more related reading, my understanding of the key data files are:</p>
<ul>
<li>The database you&rsquo;re interested in has a bunch of <code>*.frm</code> and <code>*.ibd</code> files. These are the table metadata, and InnoDB data files respectively</li>
<li><code>ibdata1</code> has very important InnoDB metadata, a must-have</li>
<li><code>ib_logfile0, ib_logfile1...</code> are the InnoDB redo logs, and are for recovering transactions when database crashes
<ul>
<li>These log files seem like in some cases, you can delete them, but risk losing those last few transactions / left in a weirder state</li>
</ul>
</li>
</ul>
<h2 id="recovery-time">Recovery time</h2>
<p>With the above key-files in hand, you may be thinking we could Frankenstein something together &ndash; and that&rsquo;s of course what I tried (and spoiler, it worked!). Here&rsquo;s what I did&hellip;</p>
<ul>
<li>Initialised a fresh MySQL data directory, simply by starting the MariaDB service: <code>systemctl start mariadb</code>
<ul>
<li>I just used the default spot because this was essentially a fresh VM; on Rocky, this is <code>/var/lib/mysql</code></li>
<li>The systemd service unit has a pre-start to create these defaults, so I lazily utilised it. You could probably use <code>mysql_install_db</code> too.</li>
</ul>
</li>
<li>Confirmed things were working by just running (as root, of course): <code>mysql</code> - should connect just fine.</li>
<li>Stopped the MariaDB service: <code>systemctl stop mariadb</code></li>
<li>Transplanted the aforementioned folders and files in to the fresh data location, <code>/var/lib/mysql/data</code>: <code>&lt;database folder&gt;</code> (in my case, <code>nextcloud</code>), <code>ibdata1</code>, <code>ib_logfile0</code>, <code>ib_logfile1</code></li>
<li>Started up MariaDB, this time in the foreground to more easily troubleshoot: <code>mysqld_safe --user root</code>.</li>
<li>Shortly after launching, it crashed, but in the log file it said my MariaDB version was <em>too new(!)</em> to recover from the given files. I hadn&rsquo;t seen this message before now (signs of recovery attempts! hope!), so I followed its guidance and downgraded.
<ul>
<li>In my case, this meant going from the latest &lsquo;11.rolling&rsquo; repo (<code>https://rpm.mariadb.org/11.rolling/rhel/$releasever/$basearch</code>; repo file in <code>yum.repos.d</code> and contents originally installed from <code>https://mirror.mariadb.org/yum/11.rolling/rocky9-amd64/MariaDB.repo</code>)</li>
<li>&hellip; to the suggested highest version from the logs of &lsquo;10.6&rsquo;. I simply replaced the &lsquo;11.rolling&rsquo; with this in the repo file, uninstalled and reinstalled MariaDB</li>
</ul>
</li>
<li>After starting back up (<code>mysqld_safe</code>), it was still unhappy with signal 6 &ndash; no worry for now, we still have the force modes to go through</li>
<li>Upon starting back up with <code>mysqld_safe --user root --innodb-force-recovery 2</code> (usually starting from 1 and going up like before, but this is what worked from me) &ndash; we&rsquo;re in! No crashes!</li>
</ul>
<p>It is quite interesting to me that this worked though, and how MySQL could not do this recovery itself. The files were there!</p>
<p>(That said, I will say: the data looks <em>mostly</em> there to me. But there&rsquo;s no telling what could have been subtly missing.)</p>
<p>If this still didn&rsquo;t work for you, I&rsquo;m pretty sure it&rsquo;s just game over.</p>
<h2 id="dump--restore">Dump + restore</h2>
<p>Obviously, you shouldn&rsquo;t run MariaDB in this state, with the recovery modes on and probably a bunch of safety checks switched off.</p>
<p>The easiest and recommended way to recover is to simply take a database dump (backup), then restore. Simply, this is:</p>
<ul>
<li>Take the backup (in another terminal session): <code>mysqldump --all-databases &gt; /root/backup.sql</code> (or if you want just dump a single database)</li>
<li>Stop MariaDB (with <code>mysqladmin shutdown</code>)</li>
<li>Move away (or if you&rsquo;re confident, remove) the transplanted stuff, i.e. <code>/var/lib/mysql</code></li>
<li>Reinitialise the database (or in the simple case as per before, just fire up the systemd service) and start MariaDB back up</li>
<li>Restore the backup: <code>mysql &lt; /root/backup.sql</code></li>
</ul>
<p>&hellip; and that should be it! Your database should be back, with hopefully the data intact.</p>
<h2 id="ending-remarks">Ending remarks</h2>
<p>Whilst this worked, I would not rely on this being the case at all. <strong>Take backups!</strong> Don&rsquo;t be lazy like me, and keep putting it off.</p>
<p>This should also speak to the fragility (of the data; although it was kind of on me for the filesystem stuff &ndash; I will say I did turn off CoW for this subvolume) and opaqueness (of the error messages) of MySQL.</p>
<p>Going forward, I see myself switching over to PostgreSQL. The backups should also be much better, with their <code>*.pgdump</code> format.</p>
<p>(I always found it silly that MySQL&rsquo;s only way of backing up was SQL queries serialised&hellip; very inefficient to the point where if you don&rsquo;t need anything special, backing up to CSV and restoring that is faster, due to not having to parse queries!)</p>
<p>Hope this can help someone though, if it does come down to it!</p>
]]></description>
	</item><item>
		<title>Wine &#43; &#39;proper&#39; DualSense (PS5) controller support via hidraw</title>
		<guid>https://nick.tay.blue/2024/01/21/wine-dualsense/</guid>
		<link>https://nick.tay.blue/2024/01/21/wine-dualsense/</link>
		<pubDate>21 Jan 24 00:00 UTC</pubDate>
		<description><![CDATA[<p>Well, I&rsquo;m already back at it again with a Wine post &ndash; it&rsquo;s working pretty well for games, I&rsquo;m so glad I took the plunge to just switch over to Linux!</p>
<p>I use a DualSense controller with Genshin Impact, and wanted to get it to work right. Specifically, by default, we run into Xbox controller prompts in-game, no DualSense features (such as gyro aim) and no haptics. I knew from Windows that support definitely exists for all of these, so let&rsquo;s fix it up!</p>
<p>This guide will probably work for similar games with such native PS controller support. Tested with wine-ge-proton8-25 in Bottles at time of writing, on Fedora 39 KDE.</p>
<h2 id="enablingallowing-hidraw">Enabling/allowing hidraw</h2>
<p>By default, Proton has SDL enabled and hidraw disabled &ndash; I believe this is for Steam Input to function reliably. We don&rsquo;t want this now, so let&rsquo;s switch it back on.</p>
<ol>
<li>Ensure Valve’s udev rules are installed: <code>sudo dnf install steam-devices</code> (<a href="https://rpmfusion.org/Configuration">RPMFusion</a> package)
<ul>
<li>(This comes with rules for common controller/joystick devices to allow hidraw access)</li>
<li>Reload udev if not already installed + replug controller</li>
<li><code>sudo udevadm control --reload-rules &amp;&amp; sudo udevadm trigger</code></li>
</ul>
</li>
<li>Launch the registry editor in the relevant Wine prefix
<ol>
<li>Navigate to <code>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\winebus</code></li>
<li>Set <code>DisableHidraw</code> to <code>0</code></li>
</ol>
</li>
</ol>
<p>That&rsquo;s it, the PS prompts and gyro controls should now work in Genshin.</p>
<h2 id="haptics-support">Haptics support</h2>
<p>This is (obviously) optional, but the more tricky part, with less info online around about it.</p>
<p>The main issue is that the PS5 controller uses its audio device for haptics (back 2 channels of the 4 channel surround), and games look for this audio device by name. The name of the device is different under Linux, so we need to trick it by renaming.</p>
<p>Under Fedora 39&rsquo;s default config, the audio session manager is WirePlumber for PipeWire. So, in <code>~/.config/wireplumber/main.lua.d/60-dualsense.lua</code>, we can create a custom rule:</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span>rule <span style="color:#04a5e5;font-weight:bold">=</span> {
</span></span><span style="display:flex;"><span>	matches <span style="color:#04a5e5;font-weight:bold">=</span> {
</span></span><span style="display:flex;"><span>		{
</span></span><span style="display:flex;"><span>			{ <span style="color:#40a02b">&#34;node.name&#34;</span>, <span style="color:#40a02b">&#34;matches&#34;</span>, <span style="color:#40a02b">&#34;*Sony_Interactive_Entertainment_Wireless_Controller*&#34;</span> },
</span></span><span style="display:flex;"><span>		},
</span></span><span style="display:flex;"><span>	},
</span></span><span style="display:flex;"><span>	apply_properties <span style="color:#04a5e5;font-weight:bold">=</span> {
</span></span><span style="display:flex;"><span>		[<span style="color:#40a02b">&#34;node.description&#34;</span>] <span style="color:#04a5e5;font-weight:bold">=</span> <span style="color:#40a02b">&#34;Wireless Controller&#34;</span>,
</span></span><span style="display:flex;"><span>	},
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>table.insert(alsa_monitor.rules,rule)
</span></span></code></pre></div><p>&hellip;then reboot, et voilà.</p>
<p>(You may also need to ensure the &lsquo;Profile&rsquo; for the device is set to &lsquo;Analog Surround 4.0 Output&rsquo;, and volume is at 100% + unmuted. This is easiest done via pavucontrol.)</p>
<hr>
<h2 id="bonus-using-hidraw-with-any-device">Bonus: using hidraw with any device</h2>
<p>You can fairly easily use the same approach to use any device over hidraw even if Valve&rsquo;s udev rules don&rsquo;t have the device you want to use. This could be useful for certain joysticks that you don&rsquo;t want going through Wine&rsquo;s SDL layer.</p>
<p>You can create your own udev rule in a similar vain to Valve&rsquo;s ones in <code>/usr/lib/udev/rules.d/60-steam-input.rules</code>. This will look something like e.g. <code>/etc/udev/rules.d/60-my-device.rules</code> (you can use <code>lsusb</code> to fetch ids):</p>
<pre tabindex="0"><code># My cool device
KERNEL==&#34;hidraw*&#34;, ATTRS{idVendor}==&#34;&lt;VID&gt;&#34;, ATTRS{idProduct}==&#34;&lt;PID&gt;&#34;, MODE=&#34;0660&#34;, TAG+=&#34;uaccess&#34;
</code></pre><p>&hellip;and reload udev + replug as usual.</p>
<p>Under Proton, they have a whitelist for what devices it allows for hidraw (the PS5 controller is on there by default). Since this is a custom device, you will then need to modify any launch script / bottle environment variables to include <code>PROTON_ENABLE_HIDRAW=0x&lt;VID&gt;/0x&lt;PID&gt;</code> (all caps) and this should get it through the whitelist. (or, even better, if it&rsquo;s a common device, <a href="https://github.com/ValveSoftware/wine/blob/26425af97506e119f76d636ecc95d647e91afa83/dlls/winebus.sys/unixlib.c#L133">consider upstreaming to Valve</a>!)</p>
<hr>
<h2 id="references">References</h2>
<ul>
<li>Controllers under Proton: <a href="https://github.com/ValveSoftware/Proton/blob/proton_8.0/docs/CONTROLLERS.md">https://github.com/ValveSoftware/Proton/blob/proton_8.0/docs/CONTROLLERS.md</a></li>
<li>DualSense &lsquo;advanced features&rsquo; work: <a href="https://github.com/ValveSoftware/Proton/issues/5900">https://github.com/ValveSoftware/Proton/issues/5900</a></li>
<li>Renaming devices with WirePlumber: <a href="https://wiki.archlinux.org/title/WirePlumber#Changing_a_device/node_property">https://wiki.archlinux.org/title/WirePlumber#Changing_a_device/node_property</a></li>
</ul>
]]></description>
	</item><item>
		<title>Getting WineASIO to work (at least on Fedora 39)</title>
		<guid>https://nick.tay.blue/2024/01/06/wineasio/</guid>
		<link>https://nick.tay.blue/2024/01/06/wineasio/</link>
		<pubDate>06 Jan 24 00:00 UTC</pubDate>
		<description><![CDATA[<p><em>(This post was updated on 2024-03-30 to support Fedora 40 too.)</em></p>
<h2 id="background">Background</h2>
<p>Recently I formatted my home computer and made the jump to Linux &ndash; specifically, the lazy way and just using Fedora Workstation 39 KDE Spin. It&rsquo;s been surprisingly pretty good so far!</p>
<p>However, I wanted to try running a Windows game via WINE which had ASIO support to get its HD audio working. After some mucking about, I got WineASIO working and thought I&rsquo;d share the details on how.</p>
<h2 id="making-it-work">Making it work</h2>
<p><em>Note</em>: I only needed it working for <strong>64-bit</strong> so that&rsquo;s all I bothered with. It also assumes you are wanting to use <strong>Pipewire JACK</strong> (although, build steps could probably be adapted to regular JACK too).</p>
<h3 id="building-wineasio">Building WineASIO</h3>
<p>In case it works (and/or saves me time in future!), I&rsquo;ve uploaded a build of v1.2.0 here: <a href="/static/upload/wineasio64-1.2.0-build.tar.gz">/static/upload/wineasio64-1.2.0-build.tar.gz</a></p>
<ol>
<li>Grab a copy of WineASIO&rsquo;s source code (at time of writing it was v1.2.0): <a href="https://github.com/wineasio/wineasio/releases">https://github.com/wineasio/wineasio/releases</a></li>
<li>Install build dependencies (assuming you already have base &lsquo;Development Tools&rsquo; group): <code>sudo dnf install pipewire-jack-audio-connection-kit-devel wine-devel</code></li>
<li>Unpack it, then simply use <code>make 64</code> to run the build, outputs into <code>build64</code>. Out should come a <code>wineasio64.dll</code> and <code>wineasio64.dll.so</code>
<ul>
<li>(A reference I saw seemed to suggest a modified Makefile was needed, but this seemed to no longer be the case)</li>
</ul>
</li>
</ol>
<h3 id="installing-wineasio">Installing WineASIO</h3>
<p>In my case, I was using <strong>Bottles</strong> (Flatpak) to manage my WINE prefix, so this was the part that needed to cater for it. For the purposes of these steps, I will highlight the Bottles locations. &ndash; Otherwise, the default WINE prefix lives in <code>~/.wine</code>, and the default WINE libraries live in <code>/usr/lib64/wine</code>.</p>
<p>(<code>wineasio-register</code> could work, but to make sure the final registering works in Bottles I think it&rsquo;s better to just do it manually.)</p>
<ol>
<li>Ensure the Pipewire JACK connection kit is installed: <code>sudo dnf install pipewire-jack-audio-connection-kit</code></li>
<li>Ensure your user is able to use realtime priorities (via the Pipewire group / security limit rule), and can access audio devices: <code>sudo usermod -aG pipewire,audio $USER</code></li>
<li>Copy built WineASIO libraries into WINE libraries folder:
<ul>
<li><code>cp wineasio64.dll.so ~/.var/app/com.usebottles.bottles/data/bottles/runners/wine-ge-proton8-25/lib64/wine/x86_64-unix</code></li>
<li><code>cp wineasio64.dll ~/.var/app/com.usebottles.bottles/data/bottles/runners/wine-ge-proton8-25/lib64/wine/x86_64-windows</code></li>
</ul>
</li>
<li>Copy built WineASIO DLL into relevant prefix folder (or, the game EXE folder should work too):
<ul>
<li><code>cp wineasio64.dll ~/.var/app/com.usebottles.bottles/data/bottles/bottles/&lt;BOTTLE NAME&gt;/drive_c/windows/system32</code></li>
</ul>
</li>
<li>For Bottles Flatpak, you&rsquo;ll also need to allow access to the Pipewire device:
<ul>
<li><code>flatpak override --user --filesystem=xdg-run/pipewire-0 com.usebottles.bottles</code></li>
<li>Restart Bottles for good measure</li>
</ul>
</li>
<li>Register WineASIO DLL with the WINE system:
<ul>
<li>In Bottles, fire up the Command Prompt for the relevant prefix</li>
<li><code>C:</code></li>
<li><code>cd C:\WINDOWS\SYSTEM32</code></li>
<li><code>regsvr32 wineasio64.dll</code></li>
</ul>
</li>
<li>A reboot is now probably required</li>
</ol>
<h3 id="testing-it">Testing it</h3>
<p>At this stage you may be able to just fire up whatever it is you&rsquo;re trying to do. However, in my case, it was very unhelpful because at first it didn&rsquo;t work right away, and the game decided to hang on startup.</p>
<ol>
<li>Grab a copy of VB-Audio&rsquo;s ASIO Driver Tester: <a href="https://forum.vb-audio.com/viewtopic.php?t=1204">https://forum.vb-audio.com/viewtopic.php?t=1204</a></li>
<li>Unpack it, then launch VBASIOTest64.exe</li>
<li>Click &lsquo;Devices&rsquo; -&gt; &lsquo;WineASIO&rsquo;
<ul>
<li>(At this stage, WineASIO should come up. Otherwise, review the installation steps above.)</li>
</ul>
</li>
<li>You should hear a sine wave playing, and numbers should start coming up. This is how you know it all worked!
<ul>
<li>(Otherwise, an error message should come up below and in the terminal. In my case, the terminal output suggested it couldn&rsquo;t connect to JACK, and it turned out it was the Flatpak allow step that was missed.)</li>
</ul>
</li>
</ol>
<p>The ASIO device should be ready to go, connected to Pipewire JACK! It should be simply called &lsquo;WineASIO&rsquo;, for any programs that should require its name.</p>
<h2 id="references">References</h2>
<p>Notably, some of these details I stumbled across were seemingly out of date in some spots, so I wanted to post my own post/guide. They did help me put this together though, so here are the references:</p>
<ul>
<li><a href="https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1495">https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1495</a></li>
<li><a href="https://github.com/theNizo/linux_rocksmith/blob/main/guides/setup/fed-pipewire.md">https://github.com/theNizo/linux_rocksmith/blob/main/guides/setup/fed-pipewire.md</a></li>
</ul>
<hr>
<h2 id="further-experimentation">Further experimentation</h2>
<p>There&rsquo;s certainly a few things more I&rsquo;d like to play with in this space:</p>
<ul>
<li>Different kernels. I&rsquo;m already running the <a href="https://copr.fedorainfracloud.org/coprs/bieszczaders/kernel-cachyos/">kernel-cachyos</a> since that was most convenient in COPR, but perhaps some other realtime ones could further improve latency/quality
<ul>
<li>I stumbled upon <a href="https://copr.fedorainfracloud.org/coprs/ycollet/audinux/packages/">audlinux</a>, and this is fairly intriguing</li>
<li>The kernel has definitely already improved single-core-heavy game performance, I&rsquo;d suggest experimenting here for sure if you have time to waste :)</li>
</ul>
</li>
<li>Resampling quirks. I now have to run my system in 44.1kHz mode to match audio output from WINE (or it results in no or sped up audio)&hellip; but I&rsquo;m curious if I can run it in 48kHz instead and just have the 44.1kHz resample. (or, just a way to have apps detect/forced to the right one, and no crackling/artefacts!!)</li>
</ul>
<hr>
<p><em>Updates after initial publishing:</em></p>
<ul>
<li>2024-01-07: Added missing realtime/audio setup+group steps, missing C drive switch in DLL registration, and minor reordering of steps</li>
<li>2024-01-29: Moved prebuilt download into blog hosting rather than relying on Windblume filehost</li>
<li>2024-03-30: F40 or <a href="https://src.fedoraproject.org/rpms/pipewire/c/ecc2c916e3f8ca3b7701b8d43062ff3cee73479a?branch=f40">this change</a> possibly broke this guide - updated realtime instructions to actually use pw group instead of piggybacking realtime-setup&rsquo;s &rsquo;nice&rsquo; rules - those aren&rsquo;t actually needed and just the pipewire group was the whole time. Also added further experimentation notes for future expansion</li>
</ul>
]]></description>
	</item><item>
		<title>Back to GitHub Pages we go</title>
		<guid>https://nick.tay.blue/2023/07/22/back-to-gh-pages/</guid>
		<link>https://nick.tay.blue/2023/07/22/back-to-gh-pages/</link>
		<pubDate>22 Jul 23 00:00 UTC</pubDate>
		<description><![CDATA[<p>Well, we&rsquo;re back to GitHub Pages.</p>
<p>But why? For a few reasons, but all centred around how Cloudflare Pages felt pretty restrictive, or even <em>prescriptive</em> in the way they allow users to set up hosting. The two things always on my mind were: enforcing &rsquo;non-ugly&rsquo; URLs and not allowing plain HTTP.</p>
<p>Apart from that, I just don&rsquo;t particularly like hosting my small, personal stuff on Cloudflare all too much anyway, seeing that more of the web is centralising on Cloudflare, when more of it really should be decentralised.</p>
<p>Why now? Well, I moved to Cloudflare Pages originally since it let me easily use Hugo, as per <a href="/2022/02/17/hugo/">my original blog post here</a>. But today I found out while playing around with GitHub&rsquo;s settings, however, that Pages now supports using GitHub Actions as a builder, and publish artifacts that way, similar to GitLab&rsquo;s offering.</p>
<hr>
<p>I thought this was great and I could move back now &ndash; I never liked the ideas of pushing built artifacts as source code to the repo under a &lsquo;docs&rsquo; folder.</p>
<p>So, I got started and threw together an Actions workflow file.</p>
<p>&hellip;</p>
<p><figure>
	<img src="/static/post-img/202307-ghactions.jpg" alt="A screenshot of the GitHub commit CI status, with the build step taking 7s and the deploy step taking 8s">
	<figcaption>A total of 15s, about the same as Cloudflare!<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>And sure enough, the build took about just as long, and it&rsquo;s working as intended (if you&rsquo;re able to read this post).</p>
<p>You can view the GitHub Actions workflow file here: <a href="https://github.com/nicholastay/personal-web/blob/master/.github/workflows/build.yaml">https://github.com/nicholastay/personal-web/blob/master/.github/workflows/build.yaml</a></p>
<p>Simply, I took a few reference GitHub Actions files, along with Hugo&rsquo;s <a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/">updated guide</a>, and stripped it down to the bare requirements. (The official given reference had so much extra crud! I don&rsquo;t want your sass-jamstack-nodejs nonsense, just stitch together some static HTML, please. <a href="/2022/02/17/hugo/"><em>stares at Jekyll</em></a>)</p>
<p>Overall, it wasn&rsquo;t too bad to pick up, and was a great excuse to finally try out GitHub&rsquo;s own CI. I had only used TeamCity and GitLab CI at work before, so this was another tool in the arsenal!</p>
<hr>
<p>Now, back to your weird old browser programming, with TLS out of the way.</p>
<p>(<a href="/2022/02/10/redesign/">no, I&rsquo;m serious.</a> &ndash; this was broken after moving to Cloudflare due to its enforcement of HTTPS/TLS)</p>
<p><em>(I&rsquo;ve also done a bit of improvement work to the site in the meantime! There&rsquo;s a dark theme based on your browser settings now, and the Life timeline no longer relies on JS/AJAX. Hooray!)</em></p>
]]></description>
	</item><item>
		<title>Looking back at my music listening (feat. Last.fm &amp; SQL)</title>
		<guid>https://nick.tay.blue/2023/07/16/last-fm-local-db/</guid>
		<link>https://nick.tay.blue/2023/07/16/last-fm-local-db/</link>
		<pubDate>16 Jul 23 00:00 UTC</pubDate>
		<description><![CDATA[<p><em>(I threw this together a while ago, but figured I should move it from a private GitHub gist to a public post!)</em></p>
<p><a href="https://last.fm">Last.fm</a> is pretty cool. It allows me to use my own library (or really, any provider!) whilst keeping track of what I listen to. For some reason I like tracking things like this, so I can look back and see what I was doing at a past point (such as with TV shows, I use Trakt).</p>
<p>However, what if Last.fm goes away one day? Also, what if I want to run my own custom queries/insights against my data?</p>
<blockquote>
<p>(Third-year uni) Me: Of course, just stash all this in my own SQL database! Then, I can run whatever query I want to pull the insights I&rsquo;d like.</p>
</blockquote>
<p>Well, indeed, the me who was nearing the end of his databases uni unit found a way to do that back then, and it&rsquo;s pretty cool just to have. (I&rsquo;m still figuring out what&rsquo;s the best way to visualise, etc.)</p>
<hr>
<p>I decided on MariaDB(/MySQL) since it was just what I had on my home server, but it really could have been anything (today, I&rsquo;d probably use PostgreSQL)&hellip; anything but Oracle though (it&rsquo;s what my uni used&hellip;)!</p>
<p>Here&rsquo;s the schemas I went with:</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#8839ef">create</span> <span style="color:#8839ef">table</span> music_plays (
</span></span><span style="display:flex;"><span>	dt datetime,
</span></span><span style="display:flex;"><span>	artist <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>),
</span></span><span style="display:flex;"><span>	title <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>),
</span></span><span style="display:flex;"><span>	album <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>)
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#8839ef">alter</span> <span style="color:#8839ef">table</span> music_plays <span style="color:#8839ef">add</span> <span style="color:#8839ef">primary</span> <span style="color:#8839ef">key</span> (dt,artist,title);
</span></span></code></pre></div><p>The three items are primary keys so on a reimport, if there happens to be duplicates, they will be skipped.</p>
<hr>
<p>Then, fetching the data. Well, I found this tool allows me to easily export off Last.fm my plays into a CSV: <a href="https://mainstream.ghan.nl/scrobbles.html">https://mainstream.ghan.nl/scrobbles.html</a></p>
<p>From here MySQL makes it super easy to load this in, with:</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#8839ef">load</span> <span style="color:#8839ef">data</span> <span style="color:#8839ef">local</span> infile <span style="color:#40a02b">&#39;/home/nick/scrobbles-&lt;...&gt;.csv&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8839ef">into</span> <span style="color:#8839ef">table</span> music_plays
</span></span><span style="display:flex;"><span>fields terminated <span style="color:#8839ef">by</span> <span style="color:#40a02b">&#39;,&#39;</span>
</span></span><span style="display:flex;"><span>optionally enclosed <span style="color:#8839ef">by</span> <span style="color:#40a02b">&#39;&#34;&#39;</span>
</span></span><span style="display:flex;"><span>lines terminated <span style="color:#8839ef">by</span> <span style="color:#40a02b">&#39;\r\n&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8839ef">ignore</span> <span style="color:#fe640b">1</span> lines
</span></span><span style="display:flex;"><span>(<span style="color:#04a5e5;font-weight:bold">@</span>unixts,<span style="color:#04a5e5;font-weight:bold">@</span>dummy,artist,<span style="color:#04a5e5;font-weight:bold">@</span>dummy,album,<span style="color:#04a5e5;font-weight:bold">@</span>dummy,title,<span style="color:#04a5e5;font-weight:bold">@</span>dummy)
</span></span><span style="display:flex;"><span><span style="color:#8839ef">set</span> dt <span style="color:#04a5e5;font-weight:bold">=</span> from_unixtime(<span style="color:#04a5e5;font-weight:bold">@</span>unixts);
</span></span></code></pre></div><p>This can then be run for whatever subsequent updates. <code>select UNIX_TIMESTAMP(MAX(dt)) from music_plays;</code> might be a handy query to avoid re-scraping everything with the above tool.</p>
<hr>
<p>As an extension, I wanted to also have my local music library&rsquo;s contents in another table, to perform joins against the play data for extended metadata (for now, only &rsquo;language&rsquo;). (Later, I found that this isn&rsquo;t perfect since sometimes Last.fm renames around things, though!)</p>
<p>My music player of choice on Windows in MusicBee, and the &ldquo;Additional Tagging and Reporting Tools&rdquo; plugin seems to get the job done: Tools -&gt; Additional Tagging and Reporting Tools -&gt; Library Reports.</p>
<p>From here I could choose the tags I wanted and output as a CSV too, and load that into my table in MySQL:</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#8839ef">create</span> <span style="color:#8839ef">table</span> music (
</span></span><span style="display:flex;"><span>	artist <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>),
</span></span><span style="display:flex;"><span>	title <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>),
</span></span><span style="display:flex;"><span>	album <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>),
</span></span><span style="display:flex;"><span>	album_artist <span style="color:#04a5e5">varchar</span>(<span style="color:#fe640b">255</span>),
</span></span><span style="display:flex;"><span>	lang_tag <span style="color:#04a5e5">char</span>(<span style="color:#fe640b">5</span>)
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#8839ef">alter</span> <span style="color:#8839ef">table</span> music <span style="color:#8839ef">add</span> <span style="color:#8839ef">primary</span> <span style="color:#8839ef">key</span> (artist,title,album);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8839ef">load</span> <span style="color:#8839ef">data</span> <span style="color:#8839ef">local</span> infile <span style="color:#40a02b">&#39;/home/nick/track-list.csv&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8839ef">into</span> <span style="color:#8839ef">table</span> music
</span></span><span style="display:flex;"><span>fields terminated <span style="color:#8839ef">by</span> <span style="color:#40a02b">&#39;,&#39;</span>
</span></span><span style="display:flex;"><span>optionally enclosed <span style="color:#8839ef">by</span> <span style="color:#40a02b">&#39;&#34;&#39;</span>
</span></span><span style="display:flex;"><span>lines terminated <span style="color:#8839ef">by</span> <span style="color:#40a02b">&#39;\r\n&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8839ef">ignore</span> <span style="color:#fe640b">1</span> lines
</span></span><span style="display:flex;"><span>(artist,title,album,album_artist,<span style="color:#04a5e5;font-weight:bold">@</span>lang_tag)
</span></span><span style="display:flex;"><span><span style="color:#8839ef">set</span> lang_tag<span style="color:#04a5e5;font-weight:bold">=</span><span style="color:#8839ef">nullif</span>(<span style="color:#04a5e5;font-weight:bold">@</span>lang_tag,<span style="color:#40a02b">&#39;&#39;</span>);
</span></span></code></pre></div><hr>
<p>Now, as previously mentioned, not only do I have a local save of my play data from Last.fm, but also the ability to query into the data!</p>
<p>For example, what prompted me to do a fresh import (and subsequently reminded me to formalise this into a blog post), was that I noticed I broke 100k scrobbles the other day. But what was my 100,000th play? Easy, with MySQL! (note, 99999 since it&rsquo;s 0-indexed with <code>offset</code>):</p>
<pre tabindex="0"><code>MariaDB [nick]&gt; select * from music_plays order by dt asc limit 1 offset 99999;
+---------------------+---------+--------------+--------------+
| dt                  | artist  | title        | album        |
+---------------------+---------+--------------+--------------+
| 2023-07-09 20:03:47 | YOASOBI | アイドル     | アイドル     |
+---------------------+---------+--------------+--------------+
</code></pre><p>Ah, of course it&rsquo;s YOASOBI&rsquo;s IDOL, the song that&rsquo;s stuck in my head after watching the anime for it, just as for everyone else who did&hellip;</p>
<p>Anyway, I&rsquo;d love to do more with the data, but I&rsquo;m just not very good at this / creative. Would be curious to see what others can do with their data though!</p>
<p>(As a note, I&rsquo;m also backing up my Trakt data, for much of the same reason. Maybe I should also load it in to a database at some point too!)</p>
]]></description>
	</item><item>
		<title>Windows Update, go away! Don&#39;t touch my drivers</title>
		<guid>https://nick.tay.blue/2023/06/21/windows-update-drivers/</guid>
		<link>https://nick.tay.blue/2023/06/21/windows-update-drivers/</link>
		<pubDate>21 Jun 23 00:00 UTC</pubDate>
		<description><![CDATA[<p>This is regarding the &ldquo;Advanced Micro Devices, Inc. - Display - 31.0.22000.11023 (2)&rdquo; update on Windows 11.</p>
<p>TL;DR Windows Update kept screwing with my drivers &ndash; now it will never have the privilege of doing so again on <a href="/windows-setup/">any future setup of mine</a>. Also my best friend is DDU (and it always has been).</p>
<p>Group Policy Setting:</p>
<pre tabindex="0"><code>gpedit.msc -&gt; Computer Configuration -&gt; Administrative Templates -&gt; Windows Components -&gt; Windows Update.
    - Windows 11: -&gt; Manage updates offered from Windows Update. Do not include drivers with Windows Updates: Enabled.
    - Windows 10: Do not include drivers with Windows Update: Enabled.
</code></pre><p><a download="goawaydriverupdates.reg" href="data:text/plain;base64,V2luZG93cyBSZWdpc3RyeSBFZGl0b3IgVmVyc2lvbiA1LjAwDQoNCltIS0VZX0xPQ0FMX01BQ0hJTkVcU09GVFdBUkVcUG9saWNpZXNcTWljcm9zb2Z0XFdpbmRvd3NcV2luZG93c1VwZGF0ZV0NCiJFeGNsdWRlV1VEcml2ZXJzSW5RdWFsaXR5VXBkYXRlIj1kd29yZDowMDAwMDAwMQ0K">One-click .reg file</a> - content below:</p>
<pre tabindex="0"><code>Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate]
&#34;ExcludeWUDriversInQualityUpdate&#34;=dword:00000001
</code></pre><p><em>(also useful if you&rsquo;re unfortunate enough to be on a &lsquo;Home&rsquo; version; thanks to <a href="https://gpsearch.azurewebsites.net/#13437">this great tool &lsquo;GPS&rsquo; for the reference key</a>, note I tested only on W10)</em></p>
<hr>
<p>So I was working from home today and switching the display configs of my monitors between &lsquo;Extend&rsquo; and &lsquo;Second screen only&rsquo;. Until upon doing so, would black screen my whole computer until a hard reset&hellip; what?</p>
<p>Upon coming back up, I would be thrown back to the Microsoft Basic Display driver with no second monitor anymore. In an attempt to fix this, I tried to install the latest, fresh drivers from AMD. It would say the install finished but there was some issue&hellip;</p>
<p>In Device Manager the GPU was then showing as disabled. Upon trying to re-enable, it would error out and an AMD dialog would come up saying so too.</p>
<p>Then it was time to try <a href="https://www.guru3d.com/files-details/display-driver-uninstaller-download.html">DDU</a>. This did the trick as expected, and reinstalling the AMD driver again fixed everything.</p>
<p>&hellip; Only to happen again, <strong>twice</strong>! Then I noticed Windows Update was doing some driver changes.</p>
<p><figure>
	<img src="/static/post-img/202306-wupdate.jpg" alt="Windows Update screen on Windows 11 showing multiple reinstallations of the AMD GPU driver">
	<figcaption>Windows Update... *waves fist*<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<hr>
<p><em>(slightly ranty)</em></p>
<p>It seems that Windows kept trying to apply some AMD GPU driver version, only to keep ****ing my computer, where when I touched display settings it would completely break to a full black screen.</p>
<p>Honestly, it&rsquo;s pretty insane that I had to nuke the driver with DDU to un**** it all and let everything install as usual again. Even worse, it even installed weirdly on my third un****-ing of it and I had to install twice.</p>
<p><figure>
	<img src="/static/post-img/202306-radeon.jpg" alt="AMD GPU Software: &ldquo;Windows Update may have automatically replaced your AMD Graphics driver &hellip; not compatible &hellip;&rdquo;">
	<figcaption>Oh dear... even AMD doesn&#39;t approve.<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>I suspect this kept happening on switching driver settings as Windows Update was applying the driver in the background <strong>while I&rsquo;m using the PC</strong> but wasn&rsquo;t fully taking effect until I changed display settings.</p>
<p>WTF is Microsoft doing? Don&rsquo;t touch my drivers, they&rsquo;re key to standard operation. Particularly if it&rsquo;s going to be applied during regular operation without a restart, and potentially ending up in a bad state.</p>
<hr>
<p><em>Updates after initial publishing:</em></p>
<ul>
<li>2025-01-27: Added Windows 10 gpedit location &amp; 1-click registry location, given I stopped using Windows 11 too</li>
</ul>
]]></description>
	</item><item>
		<title>OpenWRT GL.iNet router, (double) NAT &#43; IPsec troubles</title>
		<guid>https://nick.tay.blue/2023/03/06/openwrt-glinet-ipsec/</guid>
		<link>https://nick.tay.blue/2023/03/06/openwrt-glinet-ipsec/</link>
		<pubDate>06 Mar 23 00:00 UTC</pubDate>
		<description><![CDATA[<p>Recently, I was travelling and got myself a GL.iNet travel router &ndash; the GL-SFT1200 Opal to be specific. It was the usual hotel Wi-Fi being horrible and Ethernet being much better &ndash; I&rsquo;m talking 3-5mbps and 55-70mbps better! (More explanation later, I want to cut to the chase.)</p>
<p>I usually use an IKEv2 VPN to get back to some of my infrastructure (I know, WireGuard is usually easier to cut through firewalls, but IKE is native on mobile). However, the connection established and logs in just fine (logs on the other end see two-way communication), but traffic just wouldn&rsquo;t flow. Wi-Fi Calling(!) also wasn&rsquo;t working &ndash; I am acutely aware that this feature also relies on IPsec, so what&rsquo;s the problem?</p>
<p>Well, after hours of research and trying many various firewall rules, it turned out to just be this:</p>
<pre tabindex="0"><code># SSH into your router...
$ vi /etc/config/firewall

config defaults
    ...
    option flow_offloading &#39;1&#39;
    option flow_offloading_hw &#39;0&#39;
</code></pre><p>Then, reboot the router for good measure (required for me); or at least run <code>/etc/init.d/firewall reload</code>.</p>
<p>What does this do? It switches off Hardware Flow Offloading (but software is fine). You can switch both off, the important one is that the hardware acceleration is off, but I found my VPNs worked fine with software one on, and the network was slightly more performant. The GL.iNet interface&rsquo;s &ldquo;Hardware Acceleration&rdquo; setting switches both these options off.</p>
<p>All along, it turned out that the hardware NAT (as far as I understand) was the problem! It was probably doing something &ldquo;wrong&rdquo; to my packets&hellip; but I don&rsquo;t fully understand why. If anyone knows better, I would love to know :)</p>
<hr>
<p>So, context. I&rsquo;m going to keep it a habit to leave the rambly context at the end to avoid becoming one of those terrible cooking websites.</p>
<p>I was running the travel router in Double NAT &ndash; something that most people just say not to do, but seeing as I&rsquo;m plugging my router into a public network, I&rsquo;d prefer all my devices to live behind my own perimeter, in case I did want to expose something. Some hotels&rsquo; firewalls also block inter-device communication, and I sometimes like to copy things over Wi-Fi, so that proves very inconvenient. If I had a Chromecast I&rsquo;d also want it to behind my own borders.</p>
<p>So, IPsec/Wi-Fi Calling &ndash; fairly important to me since it is useful to be reachable &lsquo;domestically&rsquo; (my travel SIM here only supports data). And, as far as I understood NAT-T should do its job, even behind a double NAT. Putting the router into bridge mode also made it work right away, so something was definitely amiss. Researching for hours yielded nothing, until I looked for potential issues with VPNs, NAT, and not specifically OpenWRT. Hopefully this posts saves someones&rsquo; time!</p>
<p>Switching the HW flow offloading off allowed me to connect to my personal IKEv2 VPN and verify it was working correctly right away. It was hard to verify if Wi-Fi Calling was working though, since the phone would have tried many times to establish the connection, doing something to the router already with its finicky NAT-ing &ndash; which is why restarting the router was important too &ndash; I knew my VPN was working, but Wi-Fi calling just would not establish until restarting. It caused me to think something else was also wrong, only to apply the age-old &ldquo;have you turned it off and on again&rdquo; and find out that was the remedy.</p>
<p>For the Android users, some research about Wi-Fi Calling yielded that on pfSense, the UDP timeout may also have to be adjusted for Android (I only tested on iPhone) &ndash; for those who may need it, the <code>net.netfilter.nf_conntrack_udp_timeout_stream</code> sysctl option raised to 900 may prove useful (please let me know if it is or isn&rsquo;t).</p>
<p>Hope this helps (and saves someone heaps of time)!</p>
]]></description>
	</item><item>
		<title>iOS, web views and privacy</title>
		<guid>https://nick.tay.blue/2022/09/13/ios-webview-privacy/</guid>
		<link>https://nick.tay.blue/2022/09/13/ios-webview-privacy/</link>
		<pubDate>13 Sep 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>Recently I&rsquo;ve been developing for iOS as part of my job, and working with <code>WKWebView</code>. Fun times. (and lots of memory pressure troubles.)</p>
<p>While it can be a great tool when required, and can enable cross-talk between native-land and web-land, this actually can be a con within itself. I came across <a href="https://krausefx.com/blog/announcing-inappbrowsercom-see-what-javascript-commands-get-executed-in-an-in-app-browser">a post by Felix Krause</a>, detailing how this JavaScript capability can be abused.</p>
<p>Therefore, as part of my site being a very simple one, which should not having any JavaScript executing by itself, I realised I could employ a similar technique as Felix&rsquo;s proof of concept website, and play a part in making users aware of potential privacy implications.</p>
<p>Give it a try &ndash; visit this website via the in-built browser on iOS Facebook Messenger, Instagram, and others &ndash; and you should see a warning like so (if the apps are still being pesky):</p>
<p><figure>
	<img src="/static/post-img/202209-privacy-warning.jpg" alt="Privacy warning as displayed on this website in a potentially invasive browser (Instagram), including &lsquo;The browser you are using may be unsafe&hellip;&rsquo;">
	<figcaption>Privacy warning on this site when opening in Instagram in-app browser</figcaption>
</figure></p>
<p>As mentioned in the reference post, it isn&rsquo;t foolproof and can be worked around &ndash; but, I still think it&rsquo;s a valuable step in raising awareness (but also for myself to check if some app is being a bad boy!).</p>
<p><strong>Let this be a lesson to all of us to not trust in-app browsers on iOS!</strong> Use the &lsquo;Open in Safari&rsquo; option whenever possible!</p>
<p>You can find a copy of the script <a href="/assets/privacy-protect.js">in the assets folder of this site</a>, and use it as a reference for your own if you&rsquo;re interested on building something similar for your site &ndash; rest assured it is licensed under the usual BSD-2-Clause.</p>
<hr>
<p>To Apple: please implement something like &lsquo;app-bound domains&rsquo;, i.e. whitelist of sites that an app can inject into.</p>
<p>To iOS app developers: please just use <code>SFSafariViewController</code> :(</p>
]]></description>
	</item><item>
		<title>ThinkPad X230 &#43; coreboot: success</title>
		<guid>https://nick.tay.blue/2022/05/22/coreboot-x230/</guid>
		<link>https://nick.tay.blue/2022/05/22/coreboot-x230/</link>
		<pubDate>22 May 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>A few weeks ago, I did it! &ndash; my Lenovo ThinkPad X230 is now officially <code>coreboot</code>ed :D &hellip; but it wasn&rsquo;t without its hurdles.</p>
<p><figure>
	<img src="/static/post-img/202205-coreboot.jpg" alt="Default TianoCore coreboot logo splash on my ThinkPad X230">
	<figcaption>coreboot success! -- default TianoCore boot splash</figcaption>
</figure></p>
<h2 id="obtaining-a-programmer">Obtaining a programmer</h2>
<p>Originally, I wanted to try using my Raspberry Pi 4 as the programmer, but then it randomly died&hellip; I&rsquo;m still hoping it will revive itself, but starting to lose hope. Then, my friend bought a cheap Chinese CH341A programmer, which when tested, only outputted 5V :( &ndash; our-hardware-mods-inadequate-selves then tried to perform the <a href="https://www.youtube.com/watch?v=-ln3VIZKKaE">3.3V mod</a> to no avail, breaking the board.</p>
<p>He then bought another one, but this time we did some research on buying one that <em>wouldn&rsquo;t need the mod</em>. This did actually end up working nicely, and for reference, if you don&rsquo;t want to perform the mod, be sure to buy a &lsquo;blue board&rsquo; programmer. There will then be a jumper in one of the corners that lets you switch voltages!</p>
<p><figure>
	<img src="/static/post-img/202205-programmer.jpg" alt="CH341A &lsquo;blue board&rsquo; programmer">
	<figcaption>CH341A USB programmer that is able to easily switch voltages</figcaption>
</figure></p>
<h2 id="building-coreboot">Building coreboot</h2>
<p>I didn&rsquo;t want to use any pre-built image, so naturally I went with building my own. The process was quite simple &ndash; I used <a href="https://garcia.casa/posts/x220-coreboot/">Greg Carcia&rsquo;s post</a> and <a href="https://www.chucknemeth.com/laptop/lenovo-x230/flash-lenovo-x230-coreboot">Chuck Nemeth&rsquo;s page</a> as references throughout the process, thanks to them! Note that to make the process easier, I used my Debian build VM to build the firmware. At first, I tried using my Fedora dev VM, but I couldn&rsquo;t figure out how to get the cross-toolchain working properly :(</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Used &#39;depth 1&#39; for faster clone since we don&#39;t need history anyway</span>
</span></span><span style="display:flex;"><span>$ git clone --depth <span style="color:#fe640b">1</span> --recursive https://review.coreboot.org/coreboot.git
</span></span><span style="display:flex;"><span>$ <span style="color:#04a5e5">cd</span> coreboot
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ <span style="color:#04a5e5">cd</span> util/ifdtool
</span></span><span style="display:flex;"><span>$ make
</span></span></code></pre></div><p>Then, we need a backup of the BIOS firmware first to continue.</p>
<h2 id="backup-time">Backup time</h2>
<p>The X230 is different to the X220 in that it has two halves. As far as I understand, the top one is the one with the BIOS, and the bottom one has Intel ME and other stuff. We&rsquo;ll need to read and flash to both though, to install coreboot but also wipe out Intel ME.</p>
<p><figure>
	<img src="/static/post-img/202205-chips.jpg" alt="The two BIOS chips on the X230, one above each other under a protective film">
	<figcaption>The two X230 chips, near the bottom left<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>Be sure the <strong>battery and AC adapter are detached</strong>, then try hooking up the SOIC8 clip. It took a few tries to attach, but finally we got it&hellip;</p>
<p><figure>
	<img src="/static/post-img/202205-flashing.jpg" alt="SOIC8 programming clip connected to bottom X230 BIOS chip">
	<figcaption>Flashing clip connected to X230 (sorry for bad angle :&lt;)</figcaption>
</figure></p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Attach to top chip</span>
</span></span><span style="display:flex;"><span>$ sudo flashrom -p ch341a_spi -r x230-top.bin
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Some options may come up. Try to read what&#39;s on the top of the chip - a torch + macro camera came in big here!</span>
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># (You can try to read some of it, and try to match up with the only possibly candidates as given by flashrom.)</span>
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># For me, it was:</span>
</span></span><span style="display:flex;"><span>$ sudo flashrom -p ch341a_spi -r x230-top.bin -c <span style="color:#40a02b">&#34;MX25L3206E/MX25L3208E&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Attach to bottom chip</span>
</span></span><span style="display:flex;"><span>$ sudo flashrom -p ch341a_spi -r x230-bottom.bin
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Same drill as above (they are different!); for me, it was:</span>
</span></span><span style="display:flex;"><span>$ sudo flashrom -p ch341a_spi -r x230-bottom.bin -c <span style="color:#40a02b">&#34;MX25L6406E/MX25L6408E&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Make up the complete dump (the usual format seems to be &#39;bottom+top&#39;)</span>
</span></span><span style="display:flex;"><span>cat x230-bottom.bin x230-top.bin &gt; x230-dump.bin
</span></span></code></pre></div><p>Make sure to try dumping twice, and checking they are the same, e.g. by <code>sha512sum</code> &ndash; this is to ensure there was no weirdness while reading.</p>
<p>Then, be sure to keep these files safe in case of a brick, and/or to restore back to factory.</p>
<h2 id="finish-building-coreboot">Finish building coreboot</h2>
<p>(I&rsquo;m pretty sure <code>me_cleaner</code> does not need to be done separately now, given the option in the main coreboot build.)</p>
<p>We&rsquo;ll now need to extract out the needed modules from the flash dumps, and put them in the right spot.</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ <span style="color:#04a5e5">cd</span> util/ifdtool
</span></span><span style="display:flex;"><span>$ ./ifdtool -x ~/x230-dump.bin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ <span style="color:#04a5e5">cd</span> ../../
</span></span><span style="display:flex;"><span>$ mkdir -p 3rdparty/blobs/mainboard/lenovo/x230
</span></span><span style="display:flex;"><span>$ <span style="color:#04a5e5">cd</span> 3rdparty/blobs/mainboard/lenovo/x220
</span></span><span style="display:flex;"><span>$ cp ~/coreboot/util/ifdtool/*.bin .
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ mv flashregion_0_flashdescriptor.bin descriptor.bin
</span></span><span style="display:flex;"><span>$ mv flashregion_1_bios.bin bios.bin
</span></span><span style="display:flex;"><span>$ mv flashregion_2_intel_me.bin me.bin
</span></span><span style="display:flex;"><span>$ mv flashregion_3_gbe.bin gbe.bin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ <span style="color:#04a5e5">cd</span> ~/coreboot
</span></span><span style="display:flex;"><span>$ make nconfig
</span></span></code></pre></div><p>A neat little menu should now pop up, and we can customise to our heart&rsquo;s content. The settings I changed were:</p>
<ul>
<li>Mainboard
<ul>
<li>Mainboard vendor: Lenovo</li>
<li>Mainboard model: ThinkPad X230</li>
<li>Size of CBFS filesystem in ROM: 0x200000
<ul>
<li>NOTE: This was boosted up as I wanted to use UEFI boot via TianoCore; probably leave it as 0x100000 for SeaBIOS</li>
</ul>
</li>
</ul>
</li>
<li>Chipset
<ul>
<li>Add Intel descriptor.bin file</li>
<li>Add Intel ME/TXE firmware
<ul>
<li>Verify the integrity of the supplied ME-TXE firmware</li>
</ul>
</li>
<li>Strip down the Intel ME/TXE firmware</li>
<li>Add gigabit ethernet firmware</li>
</ul>
</li>
<li>Devices
<ul>
<li>Display
<ul>
<li>Framebuffer mode: Linear &ldquo;high-resolution&rdquo; framebuffer</li>
</ul>
</li>
</ul>
</li>
<li>Generic Drivers
<ul>
<li>PS/2 keyboard init</li>
</ul>
</li>
<li>Payload
<ul>
<li>Add a payload: Tianocore payload
<ul>
<li>NOTE: This was for UEFI; can just use SeaBIOS for good old BIOS boot</li>
</ul>
</li>
<li>Tianocore payload: <strong>CorebootPayload</strong>
<ul>
<li>NOTE: <strong>Be sure to choose CorebootPayload</strong>!! UEFIPayload doesn&rsquo;t work.</li>
<li>I spent so long wondering why my X230 was bricked - turns out UEFIPayload does not support older devices like the X230; you have to use the older, unmaintained CorebootPayload (unfortunately) if you want UEFI.</li>
</ul>
</li>
<li>Secondary Payloads
<ul>
<li>Load coreinfo</li>
<li>Load nvramcui</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Then just Save -&gt; Exit and <code>make</code> away!</p>
<p>Since we are dealing with the X230, after it finishes building you&rsquo;ll need to split it back into the &rsquo;top&rsquo; and &lsquo;bottom&rsquo; bits.</p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ cp coreboot/build/coreboot.rom x230-coreboot.bin
</span></span><span style="display:flex;"><span>$ dd <span style="color:#8839ef">if</span><span style="color:#04a5e5;font-weight:bold">=</span>x230-coreboot.bin <span style="color:#dc8a78">of</span><span style="color:#04a5e5;font-weight:bold">=</span>x230-coreboot-bottom.bin <span style="color:#dc8a78">bs</span><span style="color:#04a5e5;font-weight:bold">=</span>1M <span style="color:#dc8a78">count</span><span style="color:#04a5e5;font-weight:bold">=</span><span style="color:#fe640b">8</span>
</span></span><span style="display:flex;"><span>$ dd <span style="color:#8839ef">if</span><span style="color:#04a5e5;font-weight:bold">=</span>x230-coreboot.bin <span style="color:#dc8a78">of</span><span style="color:#04a5e5;font-weight:bold">=</span>x230-coreboot-top.bin <span style="color:#dc8a78">bs</span><span style="color:#04a5e5;font-weight:bold">=</span>1M <span style="color:#dc8a78">skip</span><span style="color:#04a5e5;font-weight:bold">=</span><span style="color:#fe640b">8</span>
</span></span></code></pre></div><h2 id="flash-time">Flash time</h2>
<p>With that out of the way, all that was left to do was to perform the flash.</p>
<p><figure>
	<img src="/static/post-img/202205-flash-usb.jpg" alt="SOIC8 programming clip connected to X220 laptop, USB end plugged into X230 laptop">
	<figcaption>Flashing time! (only had a photo from flashing my friend&#39;s X220)</figcaption>
</figure></p>
<div class="highlight"><pre tabindex="0" style="color:#4c4f69;background-color:#eff1f5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Attach to bottom chip (note chip model as before)</span>
</span></span><span style="display:flex;"><span>$ sudo flashrom -p ch341a_spi -w x230-coreboot-bottom.bin -c <span style="color:#40a02b">&#34;MX25L6406E/MX25L6408E&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#9ca0b0;font-style:italic"># Attach to top chip (note chip model as before)</span>
</span></span><span style="display:flex;"><span>$ sudo flashrom -p ch341a_spi -w x230-coreboot-top.bin -c <span style="color:#40a02b">&#34;MX25L3206E/MX25L3208E&#34;</span>
</span></span></code></pre></div><p>&hellip;and if all went well, power up and it should work! (except as I mentioned above, it didn&rsquo;t for me at first because of TianoCore)</p>
<p>Hooray!</p>
<p>&hellip;</p>
<p>At the time of flashing, I insisted on UEFI since there was discussion in the Fedora community about deprecating BIOS. However, that may not be the case for a while longer, so I might try SeaBIOS &ndash; my friend is using SeaBIOS and it just boots so damn quickly.</p>
<hr>
<p>As an added bonus, I wanted to add in that I wanted to use my spare X220i to practice flashing first&hellip; but it had the style of BIOS chip that we didn&rsquo;t know how to attach properly to (the &rsquo;legs&rsquo; were tiny).</p>
<p><figure>
	<img src="/static/post-img/202205-x220-chip.jpg" alt="X220i BIOS chip with small &rsquo;legs&rsquo; coming off it">
	<figcaption>BIOS chip on my X220i<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>Luckily, my friend&rsquo;s X220i didn&rsquo;t have this issue. If anyone knows how to attach to these easily, please do let me know! :)</p>
]]></description>
	</item><item>
		<title>PPPoE, IPv6-over-IPv4 and packet loss</title>
		<guid>https://nick.tay.blue/2022/05/16/he-ipv6-pppoe/</guid>
		<link>https://nick.tay.blue/2022/05/16/he-ipv6-pppoe/</link>
		<pubDate>16 May 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>A bit ago I wanted to mess with IPv6 in my homelab, but my ISP still doesn&rsquo;t support it (<em>cough</em> TPG please). So, I resorted to setting up a block through the <a href="https://tunnelbroker.net/">Hurricane Electric (HE) Tunnelbroker</a>.</p>
<p>Setup was pretty straight-forward in OPNsense, setting up the GIF interface <a href="https://docs.opnsense.org/manual/how-tos/ipv6_tunnelbroker.html">as documented</a>. However, then I faced a pretty weird issue.</p>
<p>The tunnel only seemed to be half working(?) &ndash; I could ping <code>ipv6.google.com</code>, but couldn&rsquo;t ping anything else (or sometimes, it might have gone through with massive packet loss). This sort of weird behaviour is always so hard to debug&hellip;</p>
<p>But, after some reading, here&rsquo;s the fix:</p>
<ol>
<li>In OPNsense, configure the <strong>IPv6 tunnel interface MTU</strong> as something suitable, e.g. I use 1452 and it seems to work well
<ul>
<li>I read that the PPP header is 8 bytes, then the IPv4 header is 20 bytes, so this should be subtracted to make room</li>
<li>From my understanding, it then makes sense that the encapsulated IPv6 traffic must fit inside the transmission unit used for PPPoE. TPG&rsquo;s MTU is 1480, and when checking the MTU used for HE, it was also 1480&hellip;</li>
</ul>
</li>
<li>Update the MTU in the <strong>HE tunnel &lsquo;Advanced&rsquo;</strong> area
<ul>
<li>I missed this step and was wondering why it still didn&rsquo;t work (or rather, why it seemed to only work one way/weirdly)</li>
</ul>
</li>
</ol>
<p>Pretty simple, but it still feels like documentation/knowledge in this area is still rather hard to navigate. If I run into anything else in this space I&rsquo;ll be sure to post it up here!</p>
<p>After this, it was all pretty smooth-sailing to complete my IPv6 certification to &lsquo;Sage&rsquo; level on HE :D (will update on if I get that t-shirt :P)</p>
<p><figure>
	<img src="//ipv6.he.net/certification/create_badge.php?pass_name=nickt7&amp;badge=2" alt="My HE IPv6 certification certificate!">
	<figcaption>Hurricane Electric IPv6 Certification Badge for nickt7</figcaption>
</figure></p>
]]></description>
	</item><item>
		<title>Easier testing of GCP scripts with user credentials</title>
		<guid>https://nick.tay.blue/2022/03/13/gcloud-me/</guid>
		<link>https://nick.tay.blue/2022/03/13/gcloud-me/</link>
		<pubDate>13 Mar 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>Recently I&rsquo;ve been working with the Google Cloud Platform and Node.js at work. Sometimes it&rsquo;s a pain to generate service accounts for development, only to clean them up later, especially when you don&rsquo;t have IAM access.</p>
<p>But, I found out that you can just test your scripts/projects quite easily with your user account credentials:</p>
<ol>
<li>Install the <code>gcloud</code> CLI: <a href="https://cloud.google.com/sdk/docs/install">https://cloud.google.com/sdk/docs/install</a></li>
<li>Login to GCP in the CLI with <code>gcloud auth application-default login</code>
<ul>
<li>This will provide you with <em>application-default credentials</em> once authenticated, i.e. a JSON file similar to a service account&rsquo;s one, but is automatically picked up by SDK libraries</li>
</ul>
</li>
<li>Ensure the project ID is set&hellip;
<ul>
<li><code>export GCLOUD_PROJECT=&lt;your GCP project ID&gt;</code></li>
<li>Or, make sure it is defined in your script, e.g. <code>new BigQuery({ projectId: '&lt;your GCP project ID&gt;' })</code></li>
<li>(You may prefer the first option if in the production environment, you just want it to pick up the project ID by default and not hard-code it in the script)</li>
</ul>
</li>
<li>That&rsquo;s it!
<ul>
<li>Node.js libraries such as <code>@google-cloud/bigquery</code> should authenticate with your user access</li>
<li>It also works in other languages&rsquo; libraries such as ones in Ruby</li>
</ul>
</li>
</ol>
<p>This is pretty simple to do, but the third step above had me stumped for longer than I&rsquo;d like to admit. The process of signing in with &lsquo;application-default credentials&rsquo; is also quite verbose in the official documentation and isn&rsquo;t clear (at least to me) that this is what it does &ndash; hopefully this saves someone some time.</p>
<p>As common sense, this should not be used in production, but is very useful in testing or one-off manually executed scripts &ndash; be very careful if your regular user account has a lot of permissions though. Be sure to still test with a service account before deploying to ensure it has the right access.</p>
<p>Let me know if this approach is really bad and shouldn&rsquo;t be used, though &ndash; I&rsquo;m still a big noob at this. Otherwise, enjoy!</p>
]]></description>
	</item><item>
		<title>Jekyll to Hugo, GitHub to Cloudflare!</title>
		<guid>https://nick.tay.blue/2022/02/17/hugo/</guid>
		<link>https://nick.tay.blue/2022/02/17/hugo/</link>
		<pubDate>17 Feb 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>I never really was satisfied with Jekyll &ndash; I mean, the only reason I chose it as detailed in my <a href="/2021/04/07/first-post/">first post here</a> was that I wanted something easy to deploy, something I could just push some Markdown to and the post would be styled how I wanted it. And when I wanted to redesign the website, it would be easy to!</p>
<p>Indeed, it was already quite easy, with GitHub Pages doing the heavy lifting. But as I was redesigning the page, as easy Jekyll was to use, it felt a bit slow and I just didn&rsquo;t feel like that was the last static site generator I would use. <a href="https://gohugo.io/">Hugo</a> seemed like a good choice, with it being written in Go and highly recommended around the web.</p>
<p>So once that was sorted, I needed a new host, since GitHub Pages only supported Jekyll (not sure if I could&rsquo;ve used GitHub&rsquo;s CI, but anyway). Eventually, I landed on <a href="https://pages.cloudflare.com/">Cloudflare Pages</a>. I already use Cloudflare for DNS, so I guess it made sense to just try it out. As a side bonus, they have a pretty cool subdomain if you don&rsquo;t already have a domain name, in the format <code>*.pages.dev</code> &ndash; obviously I already have a domain name, but still pretty neat in my opinion anyway!</p>
<p>Once I had done the grunt work of learning the <a href="https://gohugo.io/templates/">Go templating syntax</a> and fought with Hugo for a bit to port over the site just how I wanted it, I was good to deploy. Cloudflare Pages is able to directly hook into my GitHub repo and just build the website on each push to the <code>master</code> branch which is quite convenient. However, I came across a problem on the first build:</p>
<p><figure>
	<img src="/static/post-img/202202-cferror.jpg" alt="Cloudflare Pages: Hugo build error on Hugo v0.54.0">
	<figcaption>Hugo build failed on the first try :(<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>Scrolling up revealed that it was running Hugo 0.54.0, and I noticed my local version was 0.88.1 &ndash; so upon setting the <code>HUGO_VERSION</code> environment variable to <code>0.92.2</code>, the latest version, everything was fixed! Not sure why Cloudflare Pages defaults to an older version (maybe since a version after breaks older pages?), but apart from this one hurdle, it was really very easy to deploy!</p>
<p>Oh, and for a blog this small (only 6 posts at the time of writing), I think this command output sums up my gripes with Jekyll:</p>
<pre tabindex="0"><code>nick@angel:/d/Dev/personal-web » time hugo &gt;/dev/null

real    0m0.202s
user    0m0.000s
sys     0m0.015s
nick@angel:/d/Dev/personal-web » git checkout 2022-jekyll
Switched to branch &#39;2022-jekyll&#39;
Your branch is up to date with &#39;origin/2022-jekyll&#39;.
nick@angel:/d/Dev/personal-web » time bundle exec jekyll build &gt;/dev/null

real    0m9.454s
user    0m0.000s
sys     0m0.031s
</code></pre><p>To be clear, Jekyll did report about 4 seconds to build the pages once it was actually generating (not including the time for Ruby <code>bundle</code> to start up). However, just for putting some HTML bits-and-pieces together, that is way too long!</p>
<p>Ruby also was a bit more of a pain to setup on Windows &ndash; I know, why am I still here, but I think it&rsquo;s still worth mentioning. Hugo was really easy and lighter to setup, especially since I used Chocolatey. While building the website, Hugo also came with hot-reloading out-of-the-box with the <code>hugo serve</code> server, which was a very welcome surprise.</p>
<p>I&rsquo;m quite happy with the results so far, let&rsquo;s see how it works out in the long run!</p>
]]></description>
	</item><item>
		<title>Iris: My daily-driver split keyboard</title>
		<guid>https://nick.tay.blue/2022/02/11/iris/</guid>
		<link>https://nick.tay.blue/2022/02/11/iris/</link>
		<pubDate>11 Feb 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>The Keebio Iris Keyboard Rev. 4: it has been my primary choice of input for about 6 months now, and I&rsquo;m quite happy with it! I&rsquo;ve paired it with Gateron Yellow switches, XDA-profiled keycaps and a rotary encoder.</p>
<p><figure>
	<img src="/static/post-img/202202-iris.jpg" alt="The final desk setup: primarily shows off my Iris Rev 4 and Logitech MX Vertical; has a Genshin Impact Keqing keyring, Samsung Galaxy Buds, Genshin Klee bomb plush for display">
	<figcaption>My final desk setup as of this post!<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>(Apart from the keyboard, there&rsquo;s a few <a href="https://genshin.mihoyo.com/">Genshin Impact</a>-themed items and my mouse of choice, the Logitech MX Vertical. The deskmat is a relatively new addition, and is a custom print of <a href="https://www.reddit.com/r/KeqingMains/comments/jyvc3k/tried_creating_a_keqing_desk_mat/">this deskmat graphic from Reddit</a> &ndash; thanks /u/jeryco25 for an awesome design!)</p>
<h2 id="using-the-board">Using the board</h2>
<p>It took me about 2 weeks to really get comfortable, but since the keyboard basically has all the letters and numbers in a QWERTY layout, the hardest part was adjusting to the &ldquo;columnar staggered&rdquo; linear layout, and (to a lesser extent) the missing symbols. But after a little bit, it actually turned out to be quite comfy, with the symbols actually being easier to type since I didn&rsquo;t have to reach anymore &ndash; just use a function layer!</p>
<p>Before using this keyboard, I used to never type properly. I learnt typing through playing games! My left hand would just hover around WASD, and I would somehow type at up to 120WPM like that. Due to the staggered layout, it feels as if this board forces me to type properly &ndash; but it&rsquo;s a good thing! Feels like it&rsquo;s better for my hands, and I&rsquo;m able to type at the same WPM as before :D.</p>
<h2 id="about-building-the-board">About building the board&hellip;</h2>
<p>Just like this blog post, I had put off actually building the keyboard for a while&hellip; the original plan was to lube the switches, but I decided to forget that and just build the damn thing so I could use it. In hindsight, I really should have at least make the switches hotswappable so I can test other switches/lube the switches later, but what&rsquo;s done is done now (resoldering time??).</p>
<p>This project was my first real foray into hardware and any sort of &lsquo;proper&rsquo; soldering, and I have to say it was simultaneously easy, but hard at the same time. I really didn&rsquo;t want to mess any of my components up, and despite my crappy soldering skills, I&rsquo;m happy to report the keys are still working (I&rsquo;m using them to type up this post!).</p>
<h2 id="tenting">Tenting?</h2>
<p>Another thing with split keyboards in terms of ergonomics that I wanted to try out was tenting, i.e. tilting the keyboard up in the centre, to have it more angled to my hands. Funnily enough, I came across <a href="https://www.reddit.com/r/MechanicalKeyboards/comments/9ucwyc/do_you_want_to_tilttent_your_iris_but_dont_have/">this post about tenting on a budget on Reddit</a>.</p>
<p>For now, it&rsquo;s suprisingly effective and cheap: the keyboard is already put together with brass standoffs, so all I needed was more of them. If you look carefully at the image above, you&rsquo;ll see there are more standoffs towards the centre.</p>
<p>The only issue with this setup is the keyboard can slide around on the desk without a deskmat. Luckily I got one just before building this keyboard, so it&rsquo;s a non-issue for now. On the outer sides though, I have put some 3M rubber feet on them, and I&rsquo;m yet to put some heatshrink on the inner brass standoff &lsquo;feet&rsquo; to have more friction (as suggested by the Reddit thread OP). I believe that should stop the sliding-around problem on smoother services.</p>
<h2 id="technical-setup">Technical setup</h2>
<p>The keyboard comes with the amazing <a href="https://qmk.fm/">QMK Firmware</a>, which basically allows limitless customisation of the keyboard through C code. However, in the initial stage where I&rsquo;m trying to figure out the layout I like, this turns out to be quite the annoyance, particularly when I&rsquo;m on Windows and setting up the whole toolchain is <em>a real pain</em>.</p>
<p>That&rsquo;s where <strong><a href="https://www.caniusevia.com/">VIA</a></strong> comes in. This was such a blessing in those intial stages, as all I had to do was use the VIA utility to update bindings, rather than having to flash the microcontroller every time. All I needed was the VIA-compatible QMK firmware flashed.</p>
<p><figure>
	<img src="/static/post-img/202202-via.jpg" alt="The VIA utility, showing my current keyboard layout on layer 0">
	<figcaption>The wonderful VIA utility!<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p><strong>A note here!</strong>: remember to <strong>backup</strong> the VIA config before flashing a new QMK firmware&hellip; otherwise it <em><strong>sometimes</strong></em> forgets the config. I&rsquo;m not sure when this happens, but it seems inconsistent &ndash; better to be safe than sorry!</p>
<p>So talking about flashing, the easiest way I found was to just reuse a Debian VM I already had setup last time for the <a href="/2021/06/24/fresh-tomato/">fresh tomatoes</a> stuff. What&rsquo;s nice, however, is I can setup a <strong>USB filter</strong> in VirtualBox for <strong>just the microcontroller DFU mode</strong> &ndash; that way, the keyboard HID device is attached to my Windows for regular typing, but when I reboot the keyboard into flashing mode, it automatically goes over to the VM, ready to be flashed! Then when flashing is done, the keyboard automagically comes back to the host.</p>
<p>But also as it turns out, since we still have the QMK firmware underneath, we can customise more <em>things</em> under the hood, such as the virtual mouse and its acceleration. The only drawback is VIA uses up quite a bit of the microcontroller ROM space &ndash; so we can&rsquo;t have all the additional QMK nice things enabled. But now after 6 months, I haven&rsquo;t touched my keyboard layers in ages, so I might migrate over to a static C QMK config some time (but sometimes it still is nice to customise a layer on-the-fly for games&hellip;).</p>
<p>A copy of my VIA config can be found here: <a href="https://gist.github.com/nicholastay/af6cf94917634ba71823f3f49223454b">https://gist.github.com/nicholastay/af6cf94917634ba71823f3f49223454b</a>. My customised VIA-compatible QMK firmware can be found it my fork, here: <a href="https://github.com/nicholastay/qmk_firmware">https://github.com/nicholastay/qmk_firmware</a>.</p>
]]></description>
	</item><item>
		<title>New year, new... website redesign.</title>
		<guid>https://nick.tay.blue/2022/02/10/redesign/</guid>
		<link>https://nick.tay.blue/2022/02/10/redesign/</link>
		<pubDate>10 Feb 22 00:00 UTC</pubDate>
		<description><![CDATA[<p>I&rsquo;m finally back&hellip; and the whole website now looks different! And we&rsquo;re also CC-BY-SA + BSD-2-Clause open source (see bottom of page)!</p>
<p>To be honest, I&rsquo;ve been meaning to write some more posts about some of the random bits and pieces I found when working on various things, both at work and personally. I do have a list of things to write up about! But, I guess I hold myself to too high of a standard, and don&rsquo;t really want to write blog posts that are too short and don&rsquo;t &lsquo;properly&rsquo; convey a point. I&rsquo;ll work towards putting that aside and posting more this year &ndash; more to come (hopefully).</p>
<p>So, why the redesign? Well, I was always pretty unhappy with the homepage. As I was shifting more towards a simplistic, more document-like website, which is viewable as a <em>page</em> (not as a design piece(?)), the more I really didn&rsquo;t like the vertical and horizontal centred <code>div</code> element. Now I&rsquo;m a lot happier, and we are back to a light theme (haha). On the Jekyll side, I&rsquo;ve also consolidated all of the site into one nice, neat layout &ndash; hooray! Again, I am just leveraging it as a simple templating system that works on GitHub Pages &ndash; I just need something to copy and paste repetitive elements for me.</p>
<p>As for the layout and design, I was inspired by <a href="https://cs.harvard.edu/malan/">David Malan&rsquo;s website</a> and <a href="https://drewdevault.com/">Drew DeVault&rsquo;s blog</a>. Just a plain layout, with a navigation-sort-of static bit on the left, and the content on the right. I am no UX designer, so coming up with my own novel ideas is not my field, but I have to say I&rsquo;m pretty happy with the result. If there are any accessibility issues though, <strong>please let me know</strong>! I would love to improve this area; it is actually a goal of mine to ensure it is so &ndash; half so more people can access the page easily, but it also is fun to remain fully compatible!</p>
<p>On the compatible part&hellip; this is why I love just keeping it <strong>simple</strong>. All too many times, especially for a simple portfolio*-ish* page like this, we&rsquo;re pulling in React, Vue, etc. That isn&rsquo;t my intention and I love quick, snappy pages that get to the point and just load. Hey, this website is perfectly usable on a text-based browser, look!:</p>
<p><figure>
	<img src="/static/post-img/202202-lynx.jpg" alt="Lynx Web Browser navigated to this website with all HTML elements rendering decently">
	<figcaption>This website, open in Lynx Web Browser<a class="cc" href="#licence"><sup>^</sup></a></figcaption>
</figure></p>
<p>Pretty awesome, right? Well, here it is on Windows 98 SE, Internet Explorer (not perfect, but very usable):</p>
<p><figure>
	<img src="/static/post-img/202202-w98.jpg" alt="Windows 98 SE Internet Explorer 5 navigated to this website; sidebar navigation elements are a little misaligned, but general page layout looks correct and is usable">
	<figcaption>Windows 98 SE, Internet Explorer 5</figcaption>
</figure></p>
<p>&hellip;and also on a Nintendo 3DS (yeah, I know this is actually decently modern, lol):</p>
<p><figure>
	<img src="/static/post-img/202202-3ds.jpg" alt="This website, as viewed on a Nintendo 3DS; mobile page layout is active and the only defect is the dot points not rendering properly">
	<figcaption>Nintendo 3DS Web Browser, latest firmware as of posting</figcaption>
</figure></p>
<p>Hope you enjoyed those glimpses into my irrational obsession with keeping my website accessible on almost anything. I am looking into <a href="https://gemini.circumlunar.space/">Gemini</a> and/or <a href="https://en.wikipedia.org/wiki/Gopher_(protocol)">Gopher</a>, and will see if I can use Jekyll to auto-generate these posts on there too &ndash; I think it&rsquo;d be pretty neat just as an alternative protocol, because what even is the web in 2022? (I think I&rsquo;m just sick of the Wéb-Three talk everywhere&hellip; :&lt; look I&rsquo;m trying to avoid mentioning it just in case&hellip;)</p>
<p>Anyways, I&rsquo;ll really be trying to post more this year!</p>
]]></description>
	</item><item>
		<title>Fresh tomatoes? Yes!: Belkin F7D3402v1 router firmware hacking</title>
		<guid>https://nick.tay.blue/2021/06/24/fresh-tomato/</guid>
		<link>https://nick.tay.blue/2021/06/24/fresh-tomato/</link>
		<pubDate>24 Jun 21 00:00 UTC</pubDate>
		<description><![CDATA[<p>So I got the FreshTomato firmware on my Belkin F7D3402v1 modem/router combo working! (albeit with some caveats for now) Here&rsquo;s how I did it. (source patch available at the end)</p>
<h2 id="background">Background</h2>
<p>I&rsquo;ve always wanted to try a modded firmware router, but it seemed like I never had the right model &ndash; we would always just have some random model that we got for cheap from a store, or whatever the ISP gave. When I came across <a href="https://www.youtube.com/watch?v=qDb0Wgm5sk0">a video on YouTube</a> about custom firmwares, I got reminded of this and decided to check out the one featured in that video: <a href="http://freshtomato.org/">FreshTomato</a>.</p>
<p>When I checked out their supported routers, what interested me was that some Belkin routers were supported &ndash; I happened to have a Belkin N300 router lying around. However, it&rsquo;s an old modem/router combo, from my ADSL2 days&hellip;</p>
<p>From a quick search around online, it seemed like usually modem/router combos weren&rsquo;t supported &ndash; but I felt no reason for this, and I could just repurpose one of the ports as the WAN, given I just wanted to use this as just a router now (for fun only - I&rsquo;ve got an ISP-provided ac router and even an OPNsense VM).</p>
<h2 id="fresh-tomato">Fresh Tomato?</h2>
<p>So I saw that the Belkin F7D3302v1 was supported &ndash; it looked similar, and apparently had the same Broadcom BCM4718 SoC inside.</p>
<p>However, upon downloading the F7D3302 firmware, it wouldn&rsquo;t flash. Didn&rsquo;t think it&rsquo;d be this easy. The Belkin upload screen would instantly fail and not even try to flash, so it must be some sort of signature issue.</p>
<p>Looks like I had to get a dev environment up. I spun up a Debian VM, grabbed the MIPS repo for FreshTomato and followed the instructions as given by the dev: <a href="https://bitbucket.org/pedro311/freshtomato-mips/">https://bitbucket.org/pedro311/freshtomato-mips/</a></p>
<h2 id="first-attempt">First attempt</h2>
<p>Having a quick poke around, it seemed to me the right &lsquo;release&rsquo; to use was the <code>src-rt</code> one, as the <code>TRX_MAGIC_</code> definitions were in <code>src-rt/include/trxhdr.h</code>.</p>
<p>Looking at the Makefile, it seemed like the &lsquo;TRX magic&rsquo; bytes were what I needed for the F7D3402. Hmm, how to figure this one out&hellip;</p>
<p>Luckily, I had found <a href="https://ddscentral.org/2012/06/f7d3402_replacing_dd-wrt_with_openwrt/">an old blog post</a> regarding some hacking being done on the F7D3402 by DDS Central. They detailed some patches they had applied to the kernel, swapping out the <code>TRX_MAGIC</code> value for <code>0x00017517</code>. Great, this is what I needed</p>
<p>So I found the line for F7D3302 in the Makefile, and added in this value for another image. It also seemed like the <code>r2f</code> make profile was the right one as it built Belkin images, so I gave that a shot.</p>
<p>&hellip;and, it did flash&hellip; but then the device was stuck and bricked.</p>
<h2 id="cfe-to-the-rescue">CFE to the rescue</h2>
<p>So I tried the 30/30/30 (hold reset 30s, 30s off, 30s on with button pressed) to no avail&hellip; admittedly I should have tried this first to ensure I have a recovery mode.</p>
<p>But, then I decided to try the same with the WPS button on the front, and it worked! I was able to connect over HTTP to 192.168.2.1, and the CFE mini server appeared to allow me to flash a binary again.</p>
<h2 id="more-digging">More digging</h2>
<p><code>grep --include=\*.c --include=\*.h -Ri F7D3302</code></p>
<p>My first thing to try was to check anywhere in the source that the F7D3302 could be referenced, and probably update those to be able to use the F7D3402.</p>
<p>After a bit of searching around on Bitbucket (to make it quicker to click around commits), I noticed there was another branch, <code>mips-RT-AC</code>. In the <code>src-rt</code> folder here, there seemed to be a specific build profile for <code>f7d</code>, as well as more features enabled &ndash; I decided to work on this branch instead.</p>
<h2 id="patching-the-code">Patching the code</h2>
<p>Needless to say, this was a tedious process for me, given my inexperience here and just throwing things at the wall and seeing what sticks. This honestly took a while due to this, and it&rsquo;s probably pretty self-explanatory with the patch at the end of this post.</p>
<p>When I flashed the first working build, had the 5 minute wait, and then the LED lit up orange&hellip; I guess that&rsquo;s the moment we all do this for. But then it was identified as a Belkin F5D8235-4 v3&hellip; I must have messed up the code somewhere, and one of the ports showed up as active &ndash; must be that file with the &lsquo;vlan ports&rsquo; set wrong.</p>
<p>Turns out the <code>boardrev</code> wasn&rsquo;t the same as the F7D3302, but the F5D8235-4 v3, 1100. Once that was fixed, it identified itself properly, and everywhere which used the <code>MODEL_F7D3402</code> enum value to check for the model worked properly.</p>
<h2 id="pointscaveats">Points/caveats</h2>
<p>A few interesting things/things I haven&rsquo;t been able to figure out (I&rsquo;ll probably edit this as I find more):</p>
<ul>
<li>4 LAN ports still show up, but I&rsquo;ve reassigned one of them to be WAN.
<ul>
<li>WAN port is the top port, just under the RJ11 jack (I had actually got lucky when changing the vlan port settings, that &lsquo;3&rsquo; happened to be the top one, which is what I wanted).</li>
<li>LAN0-2 are the next three, top to bottom.</li>
</ul>
</li>
<li>5GHz doesn&rsquo;t work. The interface doesn&rsquo;t even show up in SSH.</li>
</ul>
<h2 id="patch">Patch</h2>
<p>So all my work up to now can be applied with the following patch. Note I had worked on top of commit <code>069046ba70465c6bb91a3b870629b9d3223419c9</code>, and the patch file is in <code>git format-patch</code> format, with my working steps.</p>
<p>Patch: <a href="/static/fresh-tomato-f7d3402.patch">fresh-tomato-f7d3402.patch</a></p>
]]></description>
	</item><item>
		<title>Setting up macOS, and having a different password for FileVault</title>
		<guid>https://nick.tay.blue/2021/04/11/fde-mac/</guid>
		<link>https://nick.tay.blue/2021/04/11/fde-mac/</link>
		<pubDate>11 Apr 21 00:00 UTC</pubDate>
		<description><![CDATA[<p>So I&rsquo;m already back with another post!</p>
<p>Over the weekend I decided to play around with an old MacBook Air I still had lying around &ndash; it&rsquo;s a 13&quot; mid-2011 model. But it still does run well! It was on High Sierra (10.13) though, and unfortunately that&rsquo;s the last supported version on it. Not to worry though, the <a href="http://dosdude1.com/mojave/">Mojave Patcher</a> exists, so I decided to give it a try and it is working pretty great so far on this model. There seems to be more issues with Catalina though, so I&rsquo;m happy to just settle with 10.14 for now. I also get to use the App Store version of WireGuard which makes things easier (I use it to connect back to my homelab with personal internal services).</p>
<p>On to the topic in the post title: FileVault. This is my first time trying out FileVault &ndash; only fairly recently had I looked into encrypting all the things at rest, including setting up LUKS on my Linux machines. It really is great how simple it is to enable, and given you have hardware acceleration for encryption standards (which you should), there really is no real reason not to have it on, especially on a laptop that you may lose out in the wild. (Although, I&rsquo;m making this point as the Celeron 847 in the ThinkPad X220i doesn&rsquo;t even have AVX and LUKS can add a bit of slowdown to boot and general usage.)</p>
<p>Coming from this background of LUKS, I liked having a separate, stronger key to decrypt the system on boot, then have a <em>slightly</em> weaker password for general usage (lock screen, sudo). I know, probably not the best practice, but FileVault not having such an option and insisting on synchronising passwords with main user accounts kinda sucked. I was able to put together a workaround however, with bits and pieces of information around the webs.</p>
<p>So here we go, how to have a separate password for FileVault (assuming it is already enabled, and there is only one user on the system):</p>
<ol>
<li>Create a &ldquo;Sharing Only&rdquo; user for decryption purposes. I named mine &ldquo;FDE Login&rdquo; with the username &ldquo;fdeuser&rdquo;. The password set here will be the one used when turning on the Mac.
<ul>
<li>Side note: We use a &ldquo;Sharing Only&rdquo; account so it will not show up as a user on the Mac on the login screen. On a technical level its shell is restricted and has no home directory (/dev/null).</li>
</ul>
</li>
<li>Add in the account to FileVault with the terminal command: <code>sudo fdesetup add -usertooadd fdeuser</code>.</li>
<li>Enter your <strong>main user</strong> (&rsquo;nick&rsquo; here) credentials (username, then password).</li>
<li>Then, enter in the decryption user&rsquo;s password.</li>
<li>Now we will remove the main user from FileVault: <code>sudo fdesetup remove -user nick</code>.
<ul>
<li>You probably can remove more users with this step if there are more.</li>
</ul>
</li>
<li>Verify the only user is the &ldquo;fdeuser&rdquo; with: <code>sudo fdesetup list</code>.</li>
<li>On a reboot, the only user that comes up on FileVault should be the new &ldquo;FDE Login&rdquo; user, then you should be brought to the standard login screen after entering the password.</li>
</ol>
<p>And that&rsquo;s it! As a note, the recovery key you got when enabling FileVault should still work should it ever be required.</p>
]]></description>
	</item><item>
		<title>I&#39;m back! – and with a neat little site with Jekyll</title>
		<guid>https://nick.tay.blue/2021/04/07/first-post/</guid>
		<link>https://nick.tay.blue/2021/04/07/first-post/</link>
		<pubDate>07 Apr 21 00:00 UTC</pubDate>
		<description><![CDATA[<p>Finally, I&rsquo;ve setup a basic blog again on my website &ndash; I guess I just want a nice place to put random notes to self, and things like that, since I have a homelab that I setup recently (it&rsquo;s the reason for me getting this domain!) and it might be nice to just write some interesting findings and processes through playing with those technologies.</p>
<p>I wanted a balance between a light, simple HTML page, but also convenience in updating this website with my hosting of choice &ndash; GitHub Pages. Conveniently, GitHub can automatically build Jekyll pages on push, so I decided to check it out, using custom layouts for the first time (I had used full-on Jekyll templates before, but it just feels a little, <em>heavy</em>?).</p>
<p>It turns out that you can simply write HTML pages, not only Markdown posts, and simply weave in those &lsquo;moustache&rsquo; clauses to mix in dynamic content at build time, which is exactly what I wanted.</p>
<p>A primary goal of mine with this site is to keep it slim and usable &ndash; no heavy JavaScript frameworks, just simple ones where needed, and some CSS. Even if JavaScript is disabled, the site should still function perfectly, just with some reduced &rsquo;nice&rsquo; features, such as the translation on the front page. Heck, I&rsquo;ve even made this website usable with a text-based browser (hopefully!), so feel free to give that a try!</p>
<p>So now we&rsquo;re here! Hopefully I post more in the future&hellip; but we&rsquo;ll see.</p>
]]></description>
	</item></channel>
</rss>