Installing Gentoo

I finally bite the bullet and installed Gentoo on VirtualBox (totally not motivated by the front page wishlist), thereby achieving my ultimate digital @5c3n510n (or descent according to DistroWatch).

Jokes aside, the installation process is surprisingly pleasant: the Gentoo Handbook is wonderfully written, and seems to have a plan for everything that might go wrong. I like the Handbook more than ArchWiki's Installation Guide as it also details the rationale behind each step I took, which is often a fun read in its own right. I would go as far as saying the Gentoo Handbook is actually more beginner friendly, as it carefully assembles bits of information that are normally scattered all over the place, providing a great starting point for learning how to tame the operating system. Besides, Gentoo Handbook covers more than installation: it also contains other necessary setup processes to set up a usable system. I will be gradually replicating my current desktop setup to decide if a migration is worth the time.

My very first encounter with GNU/Linux operating systems is Ubuntu 12.04: one of my classmates (vacuuny/A2Clef) was installing it in school's computer labs. There was a time when I would switch between various Ubuntu variants every few days. I dual booted Windows and Ubuntu for a while before switching entirely to Ubuntu in 2014. Much annoyed by the Amazon ads, I tried out Arch Linux as part of my New Year's resolution in 2015. Even with a second computer to look up instructions, it still took me quite a while to adapt to the new system. I ranted "maybe I still haven't gotten the Arch way" in my old blog, but never looked back once I got the knack of it.

I still try out other distributions from time to time in VirtualBox, but never find them to offer much improvements compared with Arch beyond the setup processes, and even more so when considering the excellent documentation on ArchWiki (well now we have a contender). Once I have my desktop environment set up, the experience between distributions is not that different, but the distinctions kicks in when problems occur and I search online for troubleshooting tips. Having more up-to-date packages is another charm Arch has. More recently, the systemd controversy caused me to start shopping around for a new distribution to try out, not so much because of the actual security concerns, but just to see what it is like to use different init system: my time in Ubuntu was spent mostly in GUIs (apt-get and nano was probably the only command I knew for the longest time) without knowing about init systems and Arch was already using systemd when I switched. Aside from Gentoo, the candidates include Void Linux and the BSDs. Void Linux was easy to set up with its installer wizard, yet I didn't feel compelled to move to it. Let's see if Gentoo would change my mind.

Trackpad and Swollen Batteries

For the last few weeks, the right click on my Dell XPS 13's trackpad is getting less responsive: the entire right half of the trackpad sunk around 2mm beneath the palm rest, making clicks hard to register. At first I dismissed it as normal wear, but it turned out that the swollen batteries lifted the left half of the trackpad to such a degree that the trackpad warped. I immediately ordered an OEM replacement (Dell JD25G) swapped out the swollen batteries. XPS 13 (9343) was a breeze to service. The screws that hold the bottom panel (a quite hefty hunk of aluminum) in place are all clearly visible and the component layout allows battery to be swapped with minimal disassembly. I also swapped out the WLAN card (Dell DW1560) for an Intel AC9560, whose drivers are in the mainline Linux kernel.

The trackpad felt normal after the battery swap, of course. However, the fact that average laptop battery starts to degrade around 18 months surprised me quite a bit. Mine lasting nearly four years is probably quite decent. Newer laptops uses prismatic cells (those slab shaped batteries also found in phones) instead of cylindrical ones, as can be found in my first laptop, Dell Vostro 3750. Roughly speaking, prismatic cells trade size for lifespan by emitting external casing and gas vents found on cylindrical cells. The battery swell is caused by gas build up, which might have been avoided in cylindrical cells with vents. It's interesting that (easily) removable batteries have largely disappeared in consumer laptops - even the large desktop replacements (to be fair, those spend most of the time plugged in anyways). The only consumer electronics that still almost always have removable batteries I can think of are cameras.

After the incident, I started to browse current laptops on the market as the new quad/hex core laptop CPUs are quite tempting an upgrade (my XPS 13 has a i5-5200U). I was not a huge fan of the latest XPS 13 (9380) mostly because of the port selection: I just don't have any USB Type-C devices, so the 1 Type-C plus 2 Type-A combination found on XPS 13 (9360) is superior in my opinion. Besides ports, the onboard WLAN card and removal of full-sized SD card slot also make the latest model less appealing.

I also came across the Let's Note line of laptops from Panasonic, which are reliable, lightweight business laptops that often comes with removable batteries and a wide spectrum of ports. If only they weren't so prohibitively expansive, doesn't have those ugly "Wheel Pads", and come with US keyboard layout, they are quite the ideal laptops. I like the aesthetics of 2016 CF-MX5 series the most, but that won't make much of an upgrade.

More realistic choices include HP's EliteBook, Lenovo's ThinkPad T series, and Dell's Latitude/Precision lines. I vetoed EliteBook because all of them had a huge glaring proprietary docking port that I might never use. Latitude 5491 seem to have cooling issues due to the 45W TDP CPUs, while Latitude 7390 and 7490 both seem quite decent, with options to disable Intel ME and official Linux support. ThinkPad T480 pretty much ticks everything on my list, but it seems that the next iteration T490 will no longer have the bridge battery system and only one SODIMM slot, pretty much like T480s.

Hunting for second-handed machines is also an option, but it defeats the purpose of the upgrade since my primary motivation is the new quad core CPUs. Some may argue our laptops are overpowered already, and indeed my XPS 13 still feels pretty snappy though, so I'm not in urgent need for an upgrade. However, I did come up with a list of what I want in a laptop in case the ideal candidate shows up someday.

  • Good Linux driver support.
  • Below 15 inch in size and low travel weight. XPS 13 converted me from a DTR enthusiast to an Ultrabook follower: it does feel nice to be able carry a laptop all day without feeling it.
  • Non-Nvidia graphics. Both AMD and Intel has better open source driver support and I use my desktop for tasks heavily reliant on GPU.
  • Reasonable battery life (6 hours or more) and removable battery.
  • Not-too-radical port selections, not until all mouses and flash drives default to USB Type-C at least.
  • Standard components and easy to upgrade, i.e. SODIMM slot for memory, PCIe for WLAN card/SSD.
  • A nice trackpad. I'm rather insensitive to quality of laptop keyboards so anything marginally decent would do. It would be really cool to have an ErgoDox laptop though.
  • Not-super-high-resolution display. I'm not too picky about screens either, but 4K feels like an utter overkill for laptops this size that provides marginal improvements while draining more power. I've always used 16:9 displays, but I'm open to trying out different ones.

enumerate() with C++

Quite a few programming languages provide ways to iterate through a container while keeping count of the number of steps taken, such as enumerate() in Python:

for i, elem in enumerate(v):
    print(i, elem)

and enumerate() under std::iter::Iterator trait in Rust:

for (i, elem) in v.iter().enumerate() {
    println!("{}, {}", i, elem);

This is just a quick note about how to do similar things in C++17 and later without declaring extra variables out of the for loop's scope.

The first way is to use a mutable lambda:

std::for_each(v.begin(), v.end(),
              [i = 0](auto elem) mutable {
                  std::cout << i << ", " << elem << std::endl;

This could be used with all the algorithms that guarantees in-order application of the lambda, but I don't like the dangling ++i that could get mixed up with other logic.

The second way utilizes structured binding in for loops:

for (auto [i, elem_it] = std::tuple{0, v.begin()}; elem_it != v.end();
     ++i, ++elem_it) {
    std::cout << i << ", " << *elem_it << std::endl;

We have to throw in std::tuple as otherwise compiler would try to create a std::initializer_list, which does not allow heterogeneous contents.

The third least fancy method is to just calculate the distance every time:

for (auto elem_it = v.begin(); elem_it != v.end(); ++elem_it) {
    auto i = std::distance(v.begin(), elem_it);
    std::cout << i << ", " << *elem_it << std::endl;

Since we have to copy paste the starting point twice, I like other counter based approaches better.

In C++20, we have the ability to add an init-statement in ranged-based for loops, so we can write something like

for (auto i = 0; auto elem : v) {
    std::cout << i << ", " << elem << std::endl;

Meh, not that impressive. The new <ranges> library provides a more appealing way to achieve this:

for (auto [i, elem] : v | std::views::transform(
         [i = 0](auto elem) mutable { return std::tuple{i++, elem}; })) {
    std::cout << i << ", " << elem << std::endl;

I like the structured binding method and the <ranges> based method the most. It would be even better though if we can get a std::views::enumerate to solve this problem once and for all.

Hello Darkness, My Old Friend

With system wide dark modes becoming commonplace, I took the effort to tweak the color scheme of my blog and added a dark mode specific one using prefers-color-scheme in CSS. I also toyed around the idea of adding a user toggle using JavaScript per instructions here, but ultimately decided against it because of my (totally unjustified and groundless) distaste towards the language.

Color UsageLight ThemeDark Theme
Code Background#e3dacb#1c2534
Border 1#e7e3d3#181c2c
Border 2#d7d3c3#282c3c

Writing CSS is a such tiring endeavor, but on the bright side, picking colors is a surprisingly relaxing activity. The light mode color scheme now has reduced contrast, and I updated the isso style sheets with matching colors. Yes, I only inverted the colors in dark mode and did not reduce the font weights because of the peculiar way in which human vision work. Part of me already screams heresy when I look at the color codes formed by three numbers that seem to have no connection whatsoever—they are like dissonant chords that cause itches in brain—so I need them to at least sum up to a nice number.

Wissen ist Nacht!

Fun with Fonts on the Web

A more accurate version of the title probably should be "Fun with Fonts in Web Browsers", but oh well, it sounds cooler that way. Text rendering is hard, and it certainly doesn't help that we have a plethora of different writing systems (blame the Tower of Babel for that, I guess) which cannot be elegantly fitted into a uniform system. Running a bilingual blog doubles the trouble in font picking, and here's a compilation of the various problems I encountered.

Space Invaders

Most browsers join consecutive lines of text in HTML to a single one with an added space in between, so

<html>Line one and
line two.</html>

renders to

Line one and line two.

Such a simplistic rule doesn't work for CJK languages where no separators is used between words. The solution is to specify the lang attribute for the page (or any specific element on the page) like so:

<html lang="zh">第一行和

If your browser is smart enough (like Firefox), it will join the lines correctly. All the Blink based browsers, however, still stubbornly shove in the extra space, so it looks like I will be stuck in unwrapped source files like a barbarian for a bit longer. While not a cure-all solution, specifying the lang attribute still have the added benefit of enabling language-specific CSS rules, which comes in handy later.

Return of the Quotation Marks

As mentioned in a previous post, CJK fonts would render quotation marks as full-width characters, different from Latin fonts. This won't be a problem as long as a web page doesn't try to mix-and-match fonts: just use language specific font-stack.

body:lang(en) {
    font-family: "Oxygen Sans", sans-serif;

body:lang(zh) {
    font-family: "Noto Sans SC", sans-serif;

Coupled with matching lang attributes, the story would have ended here. Firefox even allows you to specify default fonts on a per language basis, so you can actually get away with just the fallback values, like sans-serif or serif, and not even bother writing language specific CSS.

However, what if I want to use Oxygen Sans for Latin characters, Noto Sans SC for CJK characters? While seemingly an sensible solution, specifying font stack like so,

body:lang(zh) {
    font-family: "Oxygen Sans", "Noto Sans SC", sans-serif;

would cause the quotation marks to be rendered using Oxygen Sans, which displays them as half-width characters. The solution I found is to declare an override font with a specified unicode-range that covers the quotation marks,

@font-face {
    font-family: "Noto Sans SC Override";
    unicode-range: U+2018-2019, U+201C-201D;
    src: local("NotoSansCJKsc-Regular");

and revise the font stack as

body:lang(zh) {
    font-family: "Noto Sans SC Override", "Oxygen Sans", "Noto Sans SC", sans-serif;

Now we can enjoy the quotation marks in their full-width glory!

Font Ninja

Font files are quite significant in size, and even more so for CJK ones: the Noto Sans SC font just mentioned is over 8MB in size. No matter how determined I am to serve everything from my own server, this seems like an utter overkill considering the average HTML file size on my site is probably closer to 8KB. How does all the web font services handle this then?

Most web font services work by adding a bunch of @font-face definitions into a website's style sheet, which pulls font files from dedicated servers. To reduce the size of files been served, Google Fonts slice the font file into smaller chunks, and declare corresponding unicode-range for each chunk under @font-face blocks (this is exactly how they handle CJK fonts). They also compress the font files into WOFF2, further reducing file size. On the other hand, Adobe Fonts (previously known as Typekit) seem to have some JavaScript wizardry that dynamically determines which glyphs to load from a font file.

Combining best of both worlds, and thanks to the fact that this is a static site, it is easy to gather all the used characters and serve a font file containing just that. The tools of choice here would be pyftsubset (available as a component of fonttools) and GNU AWK. Compressing font files into WOFF2 also requires Brotli, a compression library. Under Arch Linux, the required packages are python-fonttools, gawk, brotli, and python-brotli.

Here's a shell one-liner to collect all the used glyphs from generated HTML files:

find . -type f -name "*.html" -printf "%h/%f " | xargs -l awk 'BEGIN{FS="";ORS=""} {for(i=1;i<=NF;i++){chars[$(i)]=$(i);}} END{for(c in chars){print c;} }' > glyphs.txt

You may need to export LANG=en_US.UTF-8 (or any other UTF-8 locale) for certain glyphs to be handled correctly. With the list of glyphs, we can extract the useful part of font files and compress them:

pyftsubset NotoSansSC-Regular.otf --text-file=glyphs.txt --flavor=woff2 --output-file=NotoSansSC-Regular.woff2

Specifying --no-hinting and --desubroutinize can further reduce size of generated file at the cost of some aesthetic fine-tuning. A similar technique can be used to shrink down Latin fonts to include only ASCII characters (or keep the extended ASCII range with U+0000-00FF):

pyftsubset Oxygen-Sans.ttf --unicodes="U+0000-007F" --flavor=woff2 --output-file=Oxygen-Sans.woff2

Once this is done, available glyphs can be checked using most font manager software, or this online checker (no support for WOFF2 though, but you can convert into other formats first, such as WOFF).

I also played around the idea of actually dividing the glyphs into further chunks by popularity, so here's another one liner to get list of glyphs sorted by number of appearances

find . -type f -name "*.html" -printf "%h/%f " | xargs -l awk 'BEGIN{FS=""} {for(i=1;i<=NF;i++){chars[$(i)]++;}} END{for(c in chars){printf "%06d %s\n", chars[c], c;}}' | sort -r > glyph-by-freq.txt

It turns out my blog has around 1000 different Chinese characters, with roughly 400 of them appearing more than 10 times. Since the file sizes I get from directly a single subsetting is already good enough, I didn't bother proceeding with another split.

For Your Browsers Only

With all the tricks in my bag, I was able to cut down the combined font file size to around 250KB, still magnitudes above that of an HTML file though. While it is nice to see my site appearing the same across all devices and screens, I feel the benefit is out of proportion compared to the 100-fold increase in page size.

Maybe it is just not worth it to force the choice of fonts. In case you want to see my site as I would like to see it, here are my go-to fonts:

Review of Star Wars: The Rise of Skywalker

Spoiler alert!

Just to get it out of the way: I watched the prequels before the original. I thought the prequels were fine - at first viewing, I felt it was as much an Obi-Wan story as it was Anakin's, and I didn't fully realize how good McGregor's performance was until I watched the old trilogy: they felt like the same person to my childhood self. After seeing full picture of the story, I can see how people who grew up with the original trilogy would view the prequels as an utter blasphemy of the original. Watching the prequels first did took out some thrill of the big reveal in Empire Strikes Back, but I was no less shocked when Anakin actually turned to the dark side in the prequels.

My very first encounter with Star Wars, however, were not the prequels, but a version of Star Wars: The Visual Encyclopedia I found in a local book store. It was all those weird weapons (including a lightwhip that I remembered distinctively), spaceships, and costumes that first enticed me to this world. I was more than rejoiced to find out that the prequels depicted exactly such an colorful yet exotic world. The tone of the original trilogy was a lot more bleak, more "spacey" than "alieny", and as a child who just witnessed the downfall of Anakin, the transition felt natural to me.

Moving on to the sequel trilogy. I watched The Force Awakens on launch date at 19:00 with my college roommate on launch date and we spent half an hour searching for a parking spot, barely making it to the screening by the opening scroll (we still got a ticket though). As for The Last Jedi, I watched it at night a month after it launched. I went to see The Rise of Skywalker at 9:00 the day it was released, a surprisingly fitting time for the end to a trilogy. TFA was a decent start, nostalgia mixed with several intriguing leads made the experience quite enjoyable. TLJ left a really bad taste in my mouth in that it not only answered questions TFA raised in the poorest way possible, but also spent too much time trying to teach the old, established characters a lesson while neglecting the growth and development of the new characters. I still have an unpublished blog post full of my rants on TLJ (from 2018), so let's move on to TROS.

In short, I enjoyed watching TROS, despite it being a over-packed messy hodgepodge.

The beginning sequence revealing Kylo's encounter with the Emperor and the Falcon crew escaping First Order was succinct and exciting. As Finn, Rey, and Poe reunite though, the pacing dropped considerably, with meaningless arguments breaking out between the trio: I really hope team building is something the last movie of a trilogy shouldn't be worrying about, but the plots of TLJ left J. J. Abrams little choice here I guess.

Then the movie went nowhere for a good half an hour showing the trio wondering around different planets doing things, also "sacrificing" Chewbacca and C-3PO in the process. Even the revelation of Rey's healing powers seemed so intentional that they are bound to be plot devices. The only good scene out of all these is probably the Rey facing off Kylo. In fact, most of the dual scenes between the two are really enjoyable, and these are the only places I can see the slightest bit of human emotion from Rey (in contrast to Kylo, whose constant struggle and change of heart were expressed amazingly by Adam Driver). Rey being a Palpatine was interesting at first, but adds little to the her overall character: it was Kylo who felt the temptation from the dark side this whole time, and all of a sudden this becomes Rey's thing?

The dual on Death Star remains was visually stunning, but the way it ended could have been a bit less awkward: more mandatory plot device showoff, and an extra dose of Han Solo that I think was totally unnecessary given how good Adam Driver's portrayal is. Carrie Fisher's passing away was unfortunate, but I think that caused the rather rushed ending for her character. The entire self-exile sequence also felt corny, and uncharacteristic of Rey. Perhaps Leia being the one to give Rey the last guidance and her lightsaber would have worked better (either as she is passing away or as a Force ghost)?

Subsequent plot again splits Rey away from her supposed "teammates", and sets the stage of the final showdown between the Resistance and the "Final Order" based on Finn and Poe's seemingly crazy idea (which Poe was specifically told not to do in TLJ). Lando appearing early in the plot and doing pretty much nothing feels like a missed opportunity: lack of screen time with the new crew in previous films left him with little ways to interact with them. I would much prefer if he just make a one-off appearance among the thousands of starships coming to the Resistance's aid in the end. I like the do Resistance' side of story here though: characters are shown to be working together with good chemistry, and they accomplished the impossible in a sensible way.

The fight with the Emperor though was a mixed bag: everything leading up to the final face down was amazing (the lightsaber passing scene was great), until Rey had to face the Emperor alone. There seems to be simply too little emotional connections between Rey and the Emperor for any confrontation between them to have any weight. If anyone, Kylo Ren should be the one allowed to show his resolution at the end of his long journey, not Rey being the same Rey she was in TFA. Having Kylo sacrificing himself in the fight, assuming the role Vader played in Return of the Jedi, would have been a much more fitting ending to him than crawling back to heal and kiss Rey (AKA showing off the plot device we spend 15 minutes foreshadowing). The thousand Sith vs. thousand Jedi bit felt forced (pun intended) and doesn't really even tie into the story that much. By the way, the Emperor looked SCARY, and in a entertaining way: the aesthetic resembles 80's horror film, and strangely felt right here (not to mention that the movie opened with "THE DEAD SPEAK!"). It's also funny that star destroyers are finally rightfully so with their shiny new canons.

Well, looks like I didn't really enjoy the movie now, do I? I'm also surprised that I can still pull out so many things I didn't like despite remembering walking out of the movie theater with a sense of relief and fulfillment. Looking back, the whole trilogy just felt poorly planned, with throw-away characters appearing here and there whose screen time fed to some new droid or alien creature every film presumably just to sell more toys, and broken plot lines that just didn't really make sense. Perhaps The Rise of Skywalker is a valiant attempt at responding to a trick question with no suitable answer and I appreciated the effort. I wonder what the generation growing up with the sequel trilogy would think about them though: would they look back on them fondly the same way I look at the prequels (or Spider-Man 3 for that matter), or is my feeling not entirely clouded by nostalgia after all?

2019 in Review

Each New Year feels incrementally less special (see the relative length argument I wrote in review of 2018), although as an end to the laziness-inducing and overly noisy holiday season, having festival associated with new goals and resolutions is not too bad an idea.

Looking at the number 2020 does give me a bit more excitement as it always felt like such a distant time in the future: I don't even remember any sci-fi works referencing anything in the 2020s, as most of them either stopped at the 2010s or go way beyond to the 3000s. This new decade is stuck in what I call, an expectation limbo. Oh, fun fact from Wikipedia, 2020 will also see the beginning of the year of Metal Rat in Chinese calendar - such a punk name for a something rather traditional.

2019 Rewind

I'm glad to announce that everything went according to plan in 2019!

  • ☑ Run 400 miles. [555/400]
  • ☑ Write 10 blog posts. [14/10]
  • ☑ Stop using Gmail/Inbox app. [2/2]
  • ☑ Add rel=me links to blog.
  • ☑ Dive into Rust and Julia. [2/2]
  • ☑ Record books, music, and shows I enjoyed.
  • ☑ Clean my desktop computer.

With some uncertainties in my life sorted out, I've been following my daily routines a lot better in 2019. I still procrastinate on blog posts from time to time, but at least I'm also publishing ever so more often. Learning Rust and Julia was fun, and I did get some uses out of them in real projects. I also attempted Advent of Code in both languages and got to the day 17 before each day's questions started taking too much time. I thought about finishing all the remaining ones after Christmas, but decided against it - I don't see myself learning more about the languages through these questions and the time could be better spent elsewhere.

I gave the blog a face-lift, writing a new Hugo theme in the process, with this article serving as an inspiration. I find the process of eliminating all the nice-to-haves and bells-and-whistles oddly satisfying: I enjoy having my blog as a lean, mean, killing machine. The website feed has been updated to use ATOM, with each post displayed in its entirety instead of the default broken summary. I started using web feeds for reading blogs after failing miserably at my last attempt to organize my web browser bookmarks and I've enjoyed it so far.

I went to the movies three times this year, for Dragon Ball Super: Broly, Promare, and Star Wars: The Rise of Skywalker, and I mostly enjoyed my time in all three occasions: trying to quantify this enjoyment using a rating is probably not doing them justice, as I enjoyed the three for vastly different reasons. Since I visit the theaters so scarcely, the time I spend on airplanes actually account for a large portion of my movie consumption, and Spider-Man: Into to the Spider-Verse was the stand out among those I watched while flying. On Christmas Eve, instead of Toradora!, an tradition of mine during college, I rewatched Scott Pilgrim vs. the World, which I also first saw on a flight years ago, and it was as geird (Good but in a weird way and weird but in a good way, like, you know, goodd? This is not a real word yet, but who cares? It's year of Metal Rat!) as I remembered.

As someone that have always lived at places that never snow until 2018, snow to me is such a distant concept that I'd consider any movie with snow scenes a Christmas movie. Even after moving to a snowing city mid 2018, I still haven't seen the stereotypical fluffy Christmas snow that almost seem warm to the touch: all I got were piles of dirty water-ice compound on roadsides (oh and they find their way into your shoes too) that reminds me more of fish market than Christmas. Meh, I bet all those snow in the movies are just props, just like the Moon landing.

Back in 2018, I set up a Mastodon instance, and I have since deleted my twitter account, but I never use Mastodon that much. At first I thought it's just that I'm not the microblogging type, but now I'm starting think it's all the cognitive overhead of logging in, editing, tagging, and translating that made posting a status update rather daunting for me. I have been microblogging in twtxt format for the last few months of 2019 and I did rack up a considerable status count (all 110 of them). Being one command away from dumping whatever silly one-liner I have in mind is quite addicting, and revisiting the twtxt file also gives me new post ideas at times. Separating a Twitter-like social media service into read-only (with feed reader), write-only (what I use twtxt for), and interactive (still figuring that one out) parts simply works better for me. My twtxt file will likely replace Mastodon in the footer this year, as keeping a behemoth (just one more pun, please?) of a web app happy and running has not been exactly pleasant for me.

Speaking of deleting accounts, I've setup forwarding from all my Gmail accounts to my self-hosted email and all my devices are Gmail and Inbox (RIP) free now. I'm still not quite ready to completely ditch the Google accounts yet, but I'm getting closer: I've been trying out registrars other than Google Domains, and using Youtube's built-in web feeds instead of relying on subscriptions. I did finally remove my Facebook account though, and the account purge will likely continue.

Road to 2020

Since it worked out really well for 2019, I'll continue to match previous year's numbers on blog posts and running. Donuts have been my guilty pleasure late night in 2019 (thanks to Dunkin'), and it's one of the few kinds of food I still willingly consume despite the detrimental effect to my health. Thus, no donuts in 2020, not under my watch!

I do want to set up a proper data backup workflow, following 3-2-1 strategy and all that. As for new languages to learn, Go has been creeping on my radar for a while and with the release of Go modules, it seems like the right time to jump in. There's also C++20 on the horizon.

2020 will also see the release of several Linux phones (Librem 5 and PinePhone), and I'm more than willing to try some of them out and explore ways of escaping the Apple ecosystem. PineTime, on the other hand, might be the perfect replacement for my aging Pebble Time Round.

Out side of technical ones, I haven't read any books in quite a while, at least not those that can be classified as proper literature, and I seek to change that in 2020.

Here's to the end of Skywalker saga, and whatever comes after generation Z!

Staring at Yesterday in One Eye

The dead speak! The galaxy has heard a mysterious broadcast, a record of THE GREAT DIMENSIONAL FRACTURE in the familiar yet distant tone of MY PREVIOUS VESSEL.

A Link to the Past

Alright, that's enough puns and The Rise of Skywalker jokes from me. As mentioned before, my blog was originally using WordPress and switched to Hugo in 2017-09-01. To be more specific, I actually had two WordPress blogs: one named Pandora (because of Borderlands 2, but this is such an cliche name that I'm sure there's a million other imaginary planets using this name) hosted with, and another being Library of Trantor (because of Isaac Asimov's Foundation series) hosted on Bluehost, with the former written in English and latter in Chinese. Since I kept archives of both before taking them down, I was able to revive all those old posts from the grave using this tool and some elbow grease. I refrained myself from leaving out any of the old posts, as the main motivation of this effort is really just to be able to easily see and be reminded of my younger self. It's a strange yet familiar experience reading those old writings: I can see parts of me that has changed and parts that are still distinctively shimmy1996.

Handling images is tricky and my old posts made quite liberal uses of them unfortunately: I opted for the simplest way out and just kept the originals without any kind of fancy compression or styling. I still need to figure out a more efficient way to both store and serve those images. Even with Git LFS available, I was reluctant to add over 300 MB of images to my blog repository (so they are currently in untracked-land), and now my blog could definitely benefit from a CDN setup. Perhaps I could also do what Jupyter notebooks do—encode all images in Base64—to get a single HTML file.

For the regular visitors of my blog out there (if there are any), you might notice that the comment section looks different: that's right, the search for the ideal static site commenting system is finally over for me (until it starts again)! Through out the years, I've used WordPress, Duoshuo (now defunct), Disqus, and Isso as my comment systems. Now, my Hyperskip has superseded them all: taking inspiration from Staticman, I set up Hyperskip to store all the comments in a TOML file, and opted to use email as the submission method, simplifying the setup. Gone are the days of databases, queries, and external scripts, and I get to migrate and version control all the comments (including the ones from the WordPress era) in the same Git repository as my blog too.

The Other Old Friend

One week into the New Year and I have already switched color scheme of the website five times, with another dozen sitting in my folder (totally not because of how unsightly these RGB color codes are). Much like how I'm a bit burned-out from getting fonts right for everything, I have decided to remove all custom color choices from the website: no more syntax highlighting, fancy buttons, nor dark modes.

As long as there are little knobs that I can toy around with, I always find myself distracted and spending way too much time worrying about the most insignificant choice of words, colors, or spacing (as you can tell by how much of I blog about the blog). The only cure I found is to simply remove the opportunities of making those choices altogether, and stick with the default. This is why I replaced Isso (I spent too much time trying to make it not look so foreign) and tags and categories are now gone, too.

Completely contrast to how the saying normally goes, I hardly ever find myself missing the things I cut away. More often than not, I sympathize with the elephant that finally broke free from the rope, rather than the remorse after losing something cherished. I do occasionally ask myself whether maintaining all those babbling by my past self is just another such rope holding me back that I just haven't realized yet. Well, my response is: a cowboy could always use a lasso on the road.