Blog on hjr265.me

Recent content in Blog on hjr265.me
https://hjr265.me/blog/ (RSS)
visit blog
All Our Customer Care Agents Are Busy at This Moment
19 Sept 2024 | original ↗

It was the second week of August 2024. We realized that the television in our family space had suddenly stopped working. It would start, flash blue for a moment, and restart. If we left it running for a while, the boot logo would appear with parts of the panel garbled. This was no cheap, no-name, no-brand “smart” TV—at least that is what the...

How Hard Can It Be: Use JavaScript to Close Web Browser Window After Print
9 May 2024 | original ↗

So here is a simple JavaScript task I had to tackle for Toph: When a user clicks the Print button, open a new tab/window and activate the print dialog. Close the window when the user confirms the print or cancels the dialog. Attempt 1: Call window.close() Immediately After window.print() I used the onclick attribute on the Print button to open...

Remmina SPICE SSH Tunnel Bug and a Workaround
15 Jan 2024 | original ↗

I seem to come across the strangest of bugs. Bug Remmina SPICE over an SSH tunnel fails to handle keyboard-mouse interactions. I have set up several virtual machines with desktop operating systems using Libvirt on my primary computer. I can access these virtual machines over the network using Libvirt on my laptop. However, I wanted to use Remmina...

#100DaysToOffload Milestone: The 100th Blog Post
23 Nov 2023 | original ↗

And one hundred. I have posted 100 blog posts in the last 365 days. Why? Because I took on this #100DaysToOffload Internet challenge. My brain, trained on decades of video games, is tuned to enjoy challenges, no questions asked. But this challenge is very different from those social media challenges that die as fast as they become popular. How?...

Android Emulator Slow As a Snail; Reason BTRFS
23 Nov 2023 | original ↗

I have been writing software professionally for over a decade. I have been writing software for even longer than that. This week was the first time I wrote an Android program. Some journey it was. But that is a story for another day. Today, in this blog post, I want to share a strange issue I encountered with Android Emulator and a fix. If you...

Check If a WireGuard Connection Is Up
21 Nov 2023 | original ↗

I have several scripts and automation on my primary computer at home that can run when connected to the local area network of my workspace through a WireGuard connection. These scripts are for routine tasks for my servers at my workspace, like backing them up to remote storage. When the WireGuard connection is not running, the scripts fail at...

Scanning a Website for Broken Links in Go
20 Nov 2023 | original ↗

Yes, I know there are paid and free tools for doing this. And yes, I know there are tools for this that I can run locally. But this exercise allowed me to try out the well-designed Go package github.com/gocolly/colly. Colly is a web scraping framework for Go. Here is how I used it to quickly scan my website (the one you are on right now) for...

When Was the Last Time Technology Blew Your Mind?
19 Nov 2023 | original ↗

I read a blog post by Kev Quirk this morning. When Was the Last Time Tech Blew Your Mind? It was a refreshing read. The world has come a long way as far as technology is concerned. But I think somewhere along the lines, the definition of innovation changed. I upgraded my desktop computer a couple of months ago. Before the upgrade, I used an Intel...

Go Web Server for Remotely Powering on a Desktop Computer With a Raspberry Pi
18 Nov 2023 | original ↗

Last month, I wrote a blog post on how to use a Raspberry Pi and a 5V 2-channel relay to remotely power on or reset a desktop computer. Powering on a Desktop Computer Remotely With a Raspberry Pi To keep the blog post simple, I used the gpio command to interact with the GPIO pins on the Raspberry Pi. That works well. But by deploying a little web...

Forwarding a Port Over SSH in Go
16 Nov 2023 | original ↗

In the day and age where Kubernetes is the go-to tool for orchestrating your applications on the cloud, I have been spending time building Bullet. I enjoy working on this tool, building out features for it little by little. And it also allows me to learn so many details. For example I just added the ability to forward ports from the remote server...

Strange Hugo Bug and How to Work Around It
15 Nov 2023 | original ↗

I was about to deploy my site with the latest blog post this morning and found Hugo broken. Or, my Hugo config.toml is broken. It depends on how you want to look at it. I ran hugo deploy and bam! I see an internal template error. ERROR render of "taxonomy" failed: template: _internal/_default/rss.xml:3:9: executing "_internal/_default/rss.xml" at...

Serving JSON in Go with http.ServeContent
15 Nov 2023 | original ↗

I know many will start with something like Gin whenever they are working on a JSON/HTTP-based backend in Go. I, not entirely sure if the minority, try to stick to Go’s built-in net/http package and, at most, use Gorilla Mux in most of my Go projects. And so serving something simple like JSON is no different from the package’s point of view as any...

Editing an SVG Icon to Be Resize-friendly
14 Nov 2023 | original ↗

This blog post is about something that I think I have absolutely no expertise in: graphics. But that also makes exploring this field and the aha moments much more rewarding. A few weeks ago, I was working on adding an icon to the Toph Printd executable. I started to look for a suitable vector image on a paid vector icon and sticker repository I...

Testing a Go Package That Depends on Redis
13 Nov 2023 | original ↗

Redsync, one of my open-source Go packages, implements a distributed lock using Redis. It is an implementation of the Redlock algorithm. This Go package has tests that run against multiple real Redis servers. And it is an example of how you can use the TestMain function to customize your Go tests. The TestMain function, if defined in your Go...

Tracking io.Copy Progress in Go
12 Nov 2023 | original ↗

If you are writing Go code for any period, you must have used the io.Copy function. It takes an io.Writer and an io.Reader and copies everything from the reader to the writer until it reaches the end of file (EOF). The function returns the number of bytes copied and an error (if any, other than io.EOF). But this function blocks until the copy...

Responsive Activity Chart With Chart.js
11 Nov 2023 | original ↗

A few weeks ago I worked on improving the activity chart shown on Toph profiles. Among adding legends and tweaking the look and feel of the chart, I paid some attention to how the chart behaves in terms of responsiveness. Chart.js has built-in responsive features. But in this case, it meant the chart would scale as a whole. What I wanted instead...

Multi-threaded Downloads in Go
9 Nov 2023 | original ↗

The word multi-threaded here is an artifact of how download managers in the past worked. The idea is to download a large file in parts, in parallel, over multiple TCP streams at once. In certain circumstances this can speed up the download significantly. Let’s start with a naive way of downloading a file in Go: 1 2 3 4 5 6 7 8 9 10 11 12 // Error...

Building Advanced Search With Go and MongoDB
7 Nov 2023 | original ↗

I like software that allows advanced search. Advanced search is where you can use flags to indicate what you want. Take email software as an example. It may allow you to enter from:Bloo to:Mac subject:Imagination and find all emails that were sent from Bloo to Mac and has the word “Imagination” in the subject line. But how do you implement...

Backing up Self-hosted GitLab With Ansible
6 Nov 2023 | original ↗

I have been making software for over a decade now. And one thing I have learned to love through this is automation. After all, it is only a programmer who will spend hours automating a task that takes a few minutes to do. There are good reasons for this. I have a self-hosted GitLab instance for Furqan Software. And if you are self-hosting tools...

JavaScript window.close Won't Close the Window
4 Nov 2023 | original ↗

I learned something new today. In JavaScript within the web browser, window.close will not close the window if it was not opened using window.open or is a top-level window (or tab) with at one history entry. That is what the documentation of window.close says. It got in the way. I was adding a page endpoint that I would link to. The link would...

Adding Anchor Links Next to Headings in Hugo
3 Nov 2023 | original ↗

I like that the Markdown renderer in Hugo automatically adds an id attribute to the headings in the content. This allows you to link to a specific section in a long article. But, I wanted to make it easy for people to get that link. Hugo doesn’t do that by default, but makes it very easy to do with Markdown render hooks. By using the following as...

Setting Up Prometheus DNS-SRV Discovery with Terraform and DNSimple
2 Nov 2023 | original ↗

If you are using Prometheus to collect metrics from your server, and you don’t have a static set of servers, then you should set up automated discovery. There are many ways you can set up automated discovery in Prometheus. However, one of my preferred vendor-agnostic ways of doing this is to use DNS-SRV records. How does it work? Let’s say you...

Waiting for an HTTP Service in GitLab CI/CD
1 Nov 2023 | original ↗

Last weekend, I was setting up a Cypress test pipeline in GitLab for Toph for the 5th time. I have no idea why this pipeline keeps breaking over time. It’s like bread left in the open. Cypress is such a fantastic end-to-end testing tool. But it seems to need a lot of extra love. Something that I needed to do was, in the CI/CD script, wait for...

SOCKS Proxy Over SSH
31 Oct 2023 | original ↗

To test some of Toph’s IP-based access control features, I needed to access it from a few different IP addresses than mine. I thought I finally needed to get one of those VPN subscriptions YouTube content creators keep rambling about. Fortunately, I remembered an easier way to do this. You see, it is possible to run a SOCKS proxy that tunnels...

Are There Three Types of #100DaysToOffload Challengers?
31 Oct 2023 | original ↗

A couple of weeks ago, I wrote my second #100DaysToOffload milestone blog post. I mentioned how I feel like a remnant characteristic of my days in the university has played a role in taking this challenge. I have been writing more frequently as I am nearing the end of the challenge. It got me wondering: are there three types of #100DaysToOffload...

Uploading Files Over SSH in Go
29 Oct 2023 | original ↗

If you access servers remotely over SSH connections, you are bound to have come across scp. It is what you use to upload files to these remote servers. If you want to programmatically upload files like scp over an SSH connection to a remote server using Go, then you can use an ssh.Client: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22...

Steam Link Black Screen on a Retro Pie Raspberry Pi 4
27 Oct 2023 | original ↗

Last night, I encountered a strange issue setting up Steam Link on a Raspberry Pi running Retro Pie. Here is my attempt at a proper description of what I was seeing. After installing Steam Link using Retro Pie’s package manager and rebooting the Raspberry Pi, I could see “Ports” show up on the Emulation Station. Inside was “Steam Link”. I could...

Synchronization Constructs in the Go Standard Library
26 Oct 2023 | original ↗

Go provides sync.Mutex as its implementation of a mutual exclusion lock. However, it is not the only synchronization construct that is a part of the standard library. This blog post will look at four synchronization constructs that we can use instead of a sync.Mutex. Counter You may often see code using a sync.Mutex to synchronize access to a...

Powering on a Desktop Computer Remotely With a Raspberry Pi
25 Oct 2023 | original ↗

I access my primary computer remotely for various reasons. Take playing video games using Steam Remote Play, for example. I have a Windows virtual machine with a GPU passed through. With Steam running on it, I can connect from my phone, my laptop, or any device with the Steam Link app and play remotely. For games that are not on Steam, I can use...

Serving hjr265.me From an S3-like Bucket Using a Caddy Module
24 Oct 2023 | original ↗

I serve hjr265.me from an S3-like bucket hosted on Linode Object Storage. I have a Caddy instance that serves some of my Hugo-built websites, including this one. I use Hugo’s deployment function and s3cmd to deploy these websites. Why Both? Hugo’s deployment function uses the blob package from the Go Cloud Development Kit. This package comes with...

Switch Monitor Input from Linux Command Line
24 Oct 2023 | original ↗

For the longest time, I have looked at computer monitors as these dumb devices. All they do is turn video signals into colours on the screen. I was out of touch with the progress. Most modern computer monitors come with what is known as DDC/CI. It may be disabled by default, so you need to enable it using the monitor’s on-screen display (OSD)...

Making a Real-time "Last N Days" Leaderboard with MongoDB Aggregation Framework
22 Oct 2023 | original ↗

On Toph, there is a leaderboard of top solvers. Without any filters, this leaderboard shows the list of programmers who solved the most programming problems in the last seven days. Toph updates the leaderboard in real-time. There are a few ways to build a leaderboard like this one. The Naive Way The easy way is to run a daily or hourly cron that...

Windows Is Weird
20 Oct 2023 | original ↗

I know we could list a thousand reasons why Windows is weird. But this particular reason is my favourite. Here are the N steps to my favourite Windows 10 weirdness: Copy the URL to this blog post. https://hjr265.me/blog/windows-is-weird/ Paste the URL in a Notepad window. You see the entire URL to this blog post. Good. Open File Explorer....

Show a Log Throbber in Terminal with Go
19 Oct 2023 | original ↗

Show a Log Throbber in the Terminal with Go A long-running program made to run in a terminal window should indicate what it is doing. Judicious logging is the first step. While developing Printd for Toph, we needed a way to indicate the program status without outputting loglines repeatedly. Printd, a print server daemon, waits for print requests...

Not a "High-rated" Person
18 Oct 2023 | original ↗

I came across a post in a competitive programming community. The post read: Always felt like [competitive programming] is no different from any other sport. Trying to get to the top in any sport requires the ability to keep being persistent in your work irrespective of the situation and what people say. […] I personally have trained myself so far...

Gnome Not Reporting Bluetooth Earbuds Battery? Enable the D-Bus Interface
17 Oct 2023 | original ↗

I use one of these true wireless Edifier earbuds. I noticed how Android reports the battery level of these earphones. But Gnome doesn’t. Turns out, you need to enable the experimental D-Bus interface in the Bluetooth daemon on Linux for Gnome to know the battery level of the connected wireless earbuds. On Arch Linux (which I use, btw), I had to...

#100DaysToOffload Milestone: The 67th Blog Post
16 Oct 2023 | original ↗

It is my second milestone blog post of the #100DaysToOffload challenge. I posted my first milestone blog post on September 3, 2023. I will keep this one short. But I will say that I have posted as many #100DaysToOffload blog posts in the last 43 days as I have since I started the challenge. It is probably a remnant characteristic of my days in...

10 Forms of Bash Shell Parameter Expansion
15 Oct 2023 | original ↗

If I look at my search history with the word “bash” in it, the most frequently searched phrases turn out to be like “trim suffix bash” and “set bash variable if empty”. It seems I write Bash scripts frequently enough to need these, but not frequently enough to remember these simple Bash shell parameter expansion forms. In this blog post I am...

Parsing Social Media URLs in Go With Slinky
14 Oct 2023 | original ↗

Toph now allows programmers to show up to 5 social media URLs on their profile pages. Instead of showing the entire URL, I wanted to show the important bits from the URL. Screenshot of a profile panel from Toph To do that, I had to parse the social media URLs and extract information like the username or profile ID (when it is a GitHub, Twitter,...

Fixing Creality CR-10 Smart Touch Screen Orientation Issue
13 Oct 2023 | original ↗

The Creality CR-10 Smart is a very sensitive 3D printer, especially when updating firmware. Are you using an SD card that is too small? The printer won’t update. Too large? Again, the printer won’t update. You formatted it to FAT32 but used an allocation size that isn’t exactly 4096 KB. Tough luck: the printer won’t update. You successfully...

Bash Script to Auto-archive Downloads by Date
11 Oct 2023 | original ↗

Finding the files you are looking for without combing through hundreds of directories is a true time-saver and an easy productivity move. I try to keep my files and directories in order, named and organized neatly. I don’t have stale files at the base of my home directory. I have separate directories for my projects, my company stuff, and the...

Stardew Valley and Eric Barone
10 Oct 2023 | original ↗

It is no secret that I play video games. Over the years, I, no doubt, have learned a lot from video games. But one particular video game and its developer stand out the most. Stardew Valley Stardew Valley A friend of mine at school introduced me to Harvest Moon. I had tried it before, but he introduced me to the mechanics and quirks of Harvest...

Building a Blog With Hugo
9 Oct 2023 | original ↗

A few weeks ago, I came across a blog post on my RSS reader: Building a blog in Django. This simple tutorial by Simon Willison was an enjoyable read. I understand the topic is not novel, but I liked how it reminds you of the simple features that enhance the implementation of a blog. Quoting from the blog post by Simon Willison: Here are the...

Setup HTTP3 with NGINX Mainline
8 Oct 2023 | original ↗

HTTP3 is here. Well, almost. If you are using NGINX, you can update to the mainline version and start using HTTP3 today experimentally. Installing NGINX Mainline As of writing this blog post, NGINX v1.24 is the latest stable version. But, HTTP3 is available in v1.25. On Ubuntu/Debian-esque servers, the easiest way to install the mainline NGINX...

Prevent Git Commits with Unformatted Go Code
7 Oct 2023 | original ↗

Git has this great feature that I think is well-known but under-used. I am talking about Git hooks. With Git hooks, you can run scripts during different Git actions. Like this one: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #!/bin/sh GOFILES=`git diff --name-only --cached | grep -e '.go$' | grep -ve 'vendor/'` UNFMTFILES=() for f in $GOFILES; do...

Mattermost (or Slack) Message on SSH Login
5 Oct 2023 | original ↗

You have a server that you access over SSH. You have hardened it following the necessary best practices. Now you can do one small thing for a little additional peace of mind: Set up Linux Pluggable Authentication Modules (PAM) to send a message to Mattermost (or Slack) on every successful SSH login. Here is how you can do it: Add a script to...

Allow External Keyboard to Wake Laptop
4 Oct 2023 | original ↗

My setup at my workspace isn’t much: a display and a few peripherals connected to a USB-C hub. This way, I can come in, plug in the hub to my laptop, and start working. But if my laptop goes to sleep, I can wake it up only by pressing a key on the internal keyboard or the trackpad. Since I keep the lid of my laptop closed, I have to take it out...

Over-engineered URLs vs. A Little Script
4 Oct 2023 | original ↗

One of the local courier services where I live will send you this helpful notification SMS with a tracking URL whenever they pick up a parcel for you. It is useful. At least compared to the hundreds of spam text messages we get here daily. It reads: [{Courier}] We have collected your parcel {ID} from {Vendor}. Track {MaskedURL}. The tracking URL...

Adding Icons for Go-built Windows Executable
30 Sept 2023 | original ↗

I have been using Windows for video games only for several years now. But that changed a little as I started working on Printd, Toph’s print server daemon. An executable file (.exe) on Windows can provide its icons. If you build a Go program for Windows you get the generic executable icon, which is fine. But sometimes fine isn’t enough....

Detect If Go Built Windows Executable Is Run From Command Prompt or File Explorer
30 Sept 2023 | original ↗

In Windows, unlike the Unix-like POSIX-compatible operating systems, there is this notion of an application subsystem: console vs. windows. If you build a Go program for Windows, it will, by default, use the console subsystem. When you start this program from File Explorer (e.g. by double-clicking its icon), Windows will show a console (like the...

Go Tidbit: Retain Cache to Speed up Go Builds in Docker
29 Sept 2023 | original ↗

If you are building Go binaries inside a Docker container, you can speed up the builds by retaining the cache that go build creates between builds. This tidbit is especially effective for large projects with several packages. Let’s take one of my Go projects as an example. Toph Platform, the Go project that powers the web application at toph.co...

Go Tidbit: Listing All Time Zones in Go
24 Sept 2023 | original ↗

I wanted to list all the time zones in Go. The standard library in Go comes with the time package. It also comes with the time/tzdata package. The standard time package in Go is very well-thought-out. It makes date-time manipulation deceptively simple. Yet, I could not find a way to list all the time zones. Time Zone Database The documentation...

Setup Dnsmasq and Systemd-resolved for *.local Hostnames
23 Sept 2023 | original ↗

I have lines like these in my /etc/hosts file: 127.0.0.1 toph.local 127.0.0.1 drafts.toph.local 127.0.0.1 quiz.toph.local I can run development servers locally and access them over .local hostnames (e.g. toph.local) instead of the loopback IP addresses (e.g. 127.0.0.1). It works fine. But every time I start working on a new project, I needed to...

Making an Auto Scroll Bookmarklet
22 Sept 2023 | original ↗

We have extensions and addons that add features and customizations to our web browsers. But it wasn’t always the case. During the the early 2000s (and even later) there were bookmarklets. Bookmarklets are short JavaScript scripts stored as bookmarks in your web browser. These were popular during the 2000s. However they started to decline in...

HTML Markup (and Hugo Shortcode) for the Modern Web
22 Sept 2023 | original ↗

I am by no means an expert in HTML and CSS. But I have been tweaking and tuning a few of my Hugo-powered websites, including this one. And, I had the opportunity to explore a few of the modern HTML and CSS features. Starting last month I made it a point to use more images in my blog posts. And, I am glad I did. When I wrote the blog post on...

Go Tidbit: Detect When the Terminal Is Resized
20 Sept 2023 | original ↗

I have been meaning to do a few short-form blog posts lately. This blog post is going to be one of them. In Go, on Linux, if you want to know when the terminal window is resized, you can listen for the SIGWINCH signal using the signal.Notify (or the signal.NotifyContext) function. The code will look something like this: 1 2 3 4 5 ch := make(chan...

Go Tidbit: Putting The Terminal Into Raw Mode
19 Sept 2023 | original ↗

I learned something new today. It helped solve a long-standing bug in Bullet. Bullet is an application deployment tool that I wrote several years ago. It is a simple tool that SSHs into a server and uses Docker to run applications. I use it in production for some of my projects. About the Bug Bullet can SSH into a remote server, spin up a one-off...

Go Tidbit: Waiting on Go Routines
17 Sept 2023 | original ↗

Concurrency is one of the central features of Go. And, to build concurrent programs in Go, you need goroutines. A goroutine is like a thread, but lighter. Much lighter. And, like any other built-in feature of Go, using it is dead simple: 1 2 3 4 5 6 7 package main func main() { go func() { println("Hello World") // Print "Hello World" from a...

Hiding Files in ZIP Archives
16 Sept 2023 | original ↗

I remember seeing a tool many years ago that could hide other files in BMP image files. I was a bit too young to understand how it worked, but I think I understand the trick now: Understand the structure of the file type at the byte level. Find a spot that can hold an arbitrary length of data. Sneak in whatever you want in there. As a proof of...

Make a Part of Form Non-interactable With CSS
15 Sept 2023 | original ↗

I have an HTML form. I want to make part of it non-interactable depending on certain conditions. I don’t want to remove that part entirely. There are so many reasons why you may want to do this. Screenshot of Contest Branding Settings Form from Toph In this screenshot, the form allows advanced features to pay customers only. Making that part...

5 Upkeep Tips for Arch Linux
12 Sept 2023 | original ↗

Yes, I am one of those guys: “I use Arch btw”. After distro-hopping for almost my entire time at the university, I found Arch Linux. I did momentarily switch to a MacBook after that, but I don’t think I have tried any other Linux distribution for over a decade. Arch Linux doesn’t do everything the way I like on a Linux device. But it doesn’t make...

Setup Multiple Passphrases for a LUKS Device
12 Sept 2023 | original ↗

Let’s say you have a computer at home shared by multiple people. And, you want to encrypt your hard drive with LUKS but not have to use the same passphrase. You can do that. LUKS has 8 key slots (LUKS1 does, LUKS2 can support more). When you set up a LUKS encrypted device you are configuring the first key slot only. But by running the following...

Building Multi-platform Docker Image for Go Applications
10 Sept 2023 | original ↗

I began the weekend writing a silly program: MGHSIAC. It’s the elegant abbreviation of “My GitHub Status Is A Clock”. It turns my GitHub status into a working clock. You can read more about it here. But as silly as it is, I am now committed to keep it running. I have an always-on Raspberry Pi with Portainer running on it already. If I could make...

Private Cloud on a Raspberry Pi: Hardware
9 Sept 2023 | original ↗

I don’t think I take privacy as seriously as people should. It is hard. Where I live, banks ask you to send documents over WhatsApp. I don’t use WhatsApp. When I ask for an email address instead, bank employees often take a few seconds before responding. But I also believe in taking baby steps. For the last few years, I have been storing bits of...

My GitHub Status Is A Clock
8 Sept 2023 | original ↗

On GitHub, you can set an emoji and a short message as your status. I don’t browse GitHub much. But through what little I do, I see so many profiles with “:dart: Focusing”. Why not make it a clock? An almost functional clock. That’s exactly what I did.: github.com/hjr265 Screenshot of my GitHub profile I wrote a Go program that I can leave...

Pregenerate Colorful Letter Avatars With Go
8 Sept 2023 | original ↗

Avatars (also known as profile images) are a great way to represent users in web applications (especially in the ones with social or collaborative features). It’s like icons, but for human beings. But as your application grows, you start to realize that not everyone is quick to upload an avatar for their account. If your application uses one of...

Making a Gnome Background Slide Show
7 Sept 2023 | original ↗

“Background Slide Show”. That is what Gnome uses in code to refer to its time-based dynamic backgrounds feature. Instead of having a static background, a Gnome Background Slide Show allows you to have a set of images that Gnome selects from based on the current time of the day. You can also configure the dynamic background to use transitions when...

Client-side Search in Hugo with Fuse.js
6 Sept 2023 | original ↗

Toph Help is built with Hugo - a static site generator. As you would expect with static sites, the pages are all generated ahead of time and hosted as plain HTML. You get all the benefits of static websites, but what about search? Client-side search is one way to work around this limitation of static websites. You build an array of objects...

Shell Script for the #100DaysToOffload Challenge
6 Sept 2023 | original ↗

I am getting quite close to my 1-year mark since I started the #100DaysToOffload challenge. Some quick mafs tell me that I can’t skip that many days if I want to make it to 100 blog posts by the end of the 365 days. I wrote a script that takes the date when I made my first #100DaysToOffload blog post and the number of blog posts I have written...

#100DaysToOffload Milestone: The 34th Blog Post
3 Sept 2023 | original ↗

What is #100DaysToOffload? #100DaysToOffload is an Internet challenge created by Kev Quirk. I don’t quite recall how I came across this challenge, probably through a front-page entry on Hacker News. But, I am glad I did. The goal of this challenge is simple: To encourage you to write. The whole point of #100DaysToOffload is to challenge you to...

Configuring Docker Health Check for Go Web Applications
2 Sept 2023 | original ↗

Docker has been providing a health check mechanism for quite some time. It is useful in identifying issues with programs that can fail in ways other than just outright crashing. And it is easy to set up. Docker health checks work periodically running a program within the container and observing its exit status. If it exits with a 0, the container...

Certbot-Name.com DNS Challenge Hooks
1 Sept 2023 | original ↗

With Certbot, for SSL certificates, I tend to use its DNS challenge over the HTTP challenge method. I find it a lot easier to automate. And, I can keep the certificate renewal details and mechanisms off the balancer or application servers. But I also have domains that are on Name.com. And, for some of them, I have their DNS records in the same...

Schedule MongoDB Backups with GitLab CI/CD
30 Aug 2023 | original ↗

GitLab CI/CD let’s you schedule pipelines. And, in a way, I find it such a convenient way to manage my Internet crons. One use of GitLab CI/CD schedules that I make is to backup MongoDB data. The pipeline, when run, SSHs into a server holding the MongoDB instance, runs mongodump and pipes it straight to s3cmd that then stores the dumped archived...

Spam Story 01: A Not-Quite-Ethical Hacker
29 Aug 2023 | original ↗

On April 3, 2023, I received an email from a “security researcher”. The “security researcher” and his/her “expert team” scanned one of my sites and found a “critical urgent” vulnerability. The web application in question links to a subdomain under the same domain from the footer without the rel="noreferer noopener" attribute. Some will say that a...

Makefile Recipe: Build with Docker and Export To A Gzipped Tarball
28 Aug 2023 | original ↗

I have been writing a lot of Makefiles lately. I find them simple and easy to like. And, as with all old-school things, I am starting to overlook its quirks. I needed to write a Makefile that lets me build something with Docker and then export the entire contents of the image to a gzipped tarball. The first part is easy: 1 2 3 .PHONY: build...

Presence Tracking with Redis
16 Jul 2023 | original ↗

Let’s say you are building a chat application. You have everything chalked out. The only thing left is that pesky green-yellow-grey indicator next to everyone’s avatar. With Redis, there is an easy way to track and display the presence of your users. All you need is a Redis sorted set. A Redis sorted set is a collection of unique strings...

Organizing Libvirt Hooks for Qemu
16 Jul 2023 | original ↗

Something I have been meaning to write about for a while is my KVM/VFIO-based gaming setup. Yes, I run Linux. And I run Windows, on Linux, in a virtual machine (VM). And it works! I game on it almost every day. But the longer post has to wait for another day. Today I am just sharing the short script that lets me keep my Libvirt hooks for Qemu a...

Simple Fixed-window Rate Limiter With Redis
1 Jul 2023 | original ↗

A while ago I needed a very quick rate limiter implementation. The application I was working on was already using Redis. Fixed-window rate limiting: This is a straightforward algorithm that counts the number of requests received within a fixed time window, such as one minute. Once the maximum number of requests is reached, additional requests are...

Hugo Footnote for the 100 Days to Offload Challenge
1 Jul 2023 | original ↗

Yesterday I posted my 25th blog post for the #100DaysToOffload. That’s 25% of the challenge. If it wasn’t clear by the post Showing GitHub Stars With Static Site Generator Hugo, I use Hugo for this site. All this time, I was manually adding a footnote to each of the blog posts: This post is {n}th of my #100DaysToOffload challenge. Want to get...

Makeshift CDN for Linode Object Storage with NGINX for Discourse
26 Jun 2023 | original ↗

If you use S3-like object storage for Discourse uploads, you will quickly realize that Discourse strongly recommends a CDN. Not using a CDN (or entering the bucket URL as the CDN URL) is likely to cause problems and is not supported. […] If you were to use Amazon S3, their Cloudfront service would be the easy solution. But not all cloud providers...

Memory Game in Less Than 100 Lines of JavaScript
24 Jun 2023 | original ↗

With Toph, for me, the line between work and fun blurs. I wanted to add a small in-browser game to Toph that would allow contest participants to pass the time while waiting for the contest to begin. The thing about 100 lines of JavaScript is arbitrary. I wanted to make the most out of modern CSS features and use JavaScript only where necessary....

Go Tidbit: Update Checker with GitHub Releases
24 Jun 2023 | original ↗

After building Printd, Toph’s print daemon, it became necessary to ensure that contest organizers were using the latest version of the software. Since Printd is open-source we host both the code and the release artifacts on GitHub. The following function uses the Go client library for GitHub to check the latest release and compare the tag with...

Generate SSH Known Hosts in Terraform
24 Mar 2023 | original ↗

I manage Toph’s infrastructure with Terraform. The setup is as multi-cloud as it gets. Beyond Terraform, I have several Ansible Playbooks for configuring and upkeeping the infrastructure. Something that I wanted to do with Terraform was to generate an SSH known_hosts file ahead of time as any changes are applied to the infrastructure. There isn’t...

Randomised Suffix in Terraform Resource Names
13 Mar 2023 | original ↗

I didn’t like how I named cloud resources for Toph. The resource names had sequential suffixes at the end. Let’s take Toph’s storage servers, for example, where MongoDB replicas are running. On Linode, while they were there, I had named the three storage servers as toph-storage-sgp-1, toph-storage-sgp-2 and toph-storage-sgp-3. But as I moved them...

Go Tidbit: Filtering Slices In-place
6 Mar 2023 | original ↗

At launch, Go did many things that felt out of place next to the other popular programming languages of the era. But now, those same language features feel so natural that I find it hard to think of a time without them. One such feature is the slice type. In Go, a slice is a view of an array. And naturally, you can have multiple slices backed by...

Making Ranked Leaderboards with MongoDB Aggregation Framework
11 Feb 2023 | original ↗

When I first added the leaderboard on Toph several years ago, I had to do most of the leaderboard-related things in application code. But then MongoDB introduced the $setWindowFields aggregation operator in MongoDB 5.0. And it simplified so much when it came to implementing ranked leaderboards. One of the things that I had to do in the...

Go Tidbit: Handling Signals, Exiting Gracefully
9 Feb 2023 | original ↗

Signals are standardized messages that an operating system can send your programs. Take Ctrl+C for example. When running a program from the terminal and you hit Ctrl+C, you expect the program to end immediately. How does that work, though? Ctrl+C is a shortcut for the POSIX signal SIGINT. By default, this signal causes your program to be...

Go Tidbit: Setting Variables in Go During Build
7 Feb 2023 | original ↗

Last week I was working on a Go program. I wanted it to print the closest Git tag and build time to logs at startup. I could write a small script that generates a Go file with these two variables set right before building the Go program. But, Go makes it easier. Ldflags Say you have the following Go code: 1 2 3 4 5 6 7 package main var hello...

Go Tidbit: Ellipsize Strings Without Breaking Unicode
6 Feb 2023 | original ↗

Strings in Go support Unicode. If you come from a programming language like C, you may think of strings as an array of (byte-sized) characters. In Go, you can convert a string to a byte slice, and access/manipulate each byte. But if you want to truncate or ellipsize the string to a specific length, you have to think of a string like a slice of...

Go Tidbit: Peek a Snippet From io.Reader
5 Feb 2023 | original ↗

You have an io.Reader, and you want to extract a small snippet from the beginning of the io.Reader and then put it back. Ideally, io.ReadSeeker would let you do that. But not all io.Readers can seek. And, like toothpaste from its tube, you cannot put something back once you read it from an io.Reader. But you can do the next best thing: 1 2 3 4 5...

Go Tidbit: How Much Was Read From io.Reader?
5 Feb 2023 | original ↗

You have an io.Reader, and you are about to pass it to some utility that will read from it. But the utility won’t tell you how much it has read from the io.Reader. How do you figure out how many bytes of data were in the io.Reader? Like this snippet of Go+AWS code: 1 2 3 4 5 6 7 8 9 func uploadToS3(r io.Reader) (int64, error) { _, err := s3manager.

Using Caddy to Indicate GitLab Repository for Go Module Path with Different Domains
21 Jan 2023 | original ↗

The self-hosted GitLab at my company, Furqan Software, is home to all the company Go projects. The domain where Furqan Software’s GitLab is accessible is different from the domain in Go module paths. That means go get doesn’t work out of the box for our Go projects. For example, let’s say you have a Go project with the module path...

Private and Secure Multi-cloud Network with WireGuard
17 Jan 2023 | original ↗

Can you make a private and secure network between servers on multiple cloud providers? Yes, with WireGuard, you can. The solution is fast and secure. It is easy to deploy/automate. And, best of all, it is cloud-agnostic. For convenience, I have created a demo repository with Terraform and Ansible that you can clone and try. The demo uses Linode...

Links for Social Network Share Dialogs
7 Jan 2023 | original ↗

You have a few options to add social network sharing buttons to your website or web app. One, you can embed their JavaScript operating systems SDKs. If your site needs 21st-century Internet bloat, this is what you are looking for. Two, you can use third-party share button JavaScript libraries. There are way too many of these out there. And they...

Embedding a JavaScript Library (KaTeX) in Go
24 Dec 2022 | original ↗

KaTeX is the fan-favourite way of doing math and equations on the web. The library is simple to use and easy to reason about. But it is JavaScript. How do you build a Go program that renders math and equations like KaTeX? You embed KaTeX in your Go program. Several Go packages allow you to run JavaScript from within Go. In this post, we will use...

Block All But One Website With Windows Defender Firewall
10 Dec 2022 | original ↗

How do you block access to all websites except one on a Windows device? On-site programming contest organizers need to ensure that the contestant workstations can access Toph but no other website. Toph recommends restricting the Internet through router/firewall configuration; sometimes, it is not a solution that the contest organizer can choose....

Preparing Myself to Learn Programming
8 Dec 2022 | original ↗

My first exposure to any programming involved writing Batch scripts - think shell scripts for Windows. The first time I used a computer was an IBM XT clone. It ran DOS. I was 11 when I got my second computer, a nifty Windows 95 machine. I kept all of my games organized on that second computer. One day, I thought of making a number-based menu for...

Adding target="_blank" to User-Generated HTML Anchors in Go
6 Dec 2022 | original ↗

Working with user-generated content is always a nightmare interesting. Let’s say you are building a blogging platform with Go. Your users write posts in Markdown that the platform then renders as HTML. And, you want to add target="_blank" and rel="noreferrer noopener" to all the external links. How do you do that? Annotated Code The steps are...

Bump Calendar Versioning (CalVer) Bash Script for Git
5 Dec 2022 | original ↗

For Toph, SemVer didn’t make much sense. CalVer did. Toph is closed-source and available to users as a SaaS. We are not trying to maintain or communicate backwards-compatible/incompatible changes to Toph with our users. With CalVer (short for Calender Versioning), the versioning would be tied to the release date. The pattern we wanted to use:...

Single Node MongoDB Replica Set with Docker Compose
4 Dec 2022 | original ↗

Toph needs a few MongoDB features that only work in replica set mode. Take Change Streams, for example. It is unavailable in standalone mode. To ease development, all of Toph’s application codebases come with Docker Compose files. With just a single docker-compose up, I can have any of Toph’s applications running in a development environment. But...

Grid Chart for Toph's One Million Submissions
30 Nov 2022 | original ↗

Toph recently reached a milestone my family and I have been looking forward to. One million submissions. It may be a small win, but it is that sweet reward of working on your favourite project. On the relevant Toph Blog post, we have a picture that is 3840×25982 pixels and has one million coloured squares on it. The squares represent the one...

Showing GitHub Stars With Static Site Generator Hugo
27 Nov 2022 | original ↗

Static site generators are one of my favourite things about the Internet. I remember when almost every website built around me was based on Joomla or WordPress. I dread that time. My website, which you are on right now, is built with Hugo. I have a page on this website listing some of my open-source projects. And I wanted an easy way to show the...

Passing A Vector of RedisModuleString to RedisModule_Call
26 Nov 2022 | original ↗

While building Redis Too (a recommendation engine module for Redis), I spent a good bit of time (and strands of hair) figuring out how to pass a variable number of arguments to a Redis command like “SUNION”. The format specified of the RedisModule_Call function accepts ‘v’ to denote “a vector of RedisModuleString”. But to use it, you need to pass...

Extracting Text From PDF Using Go
14 Nov 2022 | original ↗

TL;DR: Read all text values from PDF, ordered by Y-position. Make a state machine. The link to the complete code is at the end of the article. When it comes to extracting text from PDF, you will likely face one of these two scenarios: The PDF you generate or export from some software where all the text is still text. The PDF you scan from a...

Updating Creality CR-10 Smart Firmware
21 Oct 2021 | original ↗

There seems to be a lot of frustration with this 3D printer. And one of those frustration stems from how confusing the firmware update process is. The documentation is lacking in terms of some of the details. To keep things simple, here are the important bits: Updating the firmware of this 3D printer involves two separate steps. The first one is...

Stream Uploading Files to S3 with Object Writer
6 Jun 2021 | original ↗

The official AWS SDK provides an upload manager construct that allows you to upload to S3 from any io.Reader. Using it is straightforward, that is until you need to create and upload a potentially large ZIP file. The solution: use the upload manager with a pipe. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Open a pipe.

Using Language Servers with CodeMirror 6
28 Mar 2021 | original ↗

CodeMirror 6, a rewrite of the CodeMirror editor, brings several improvements. Toph has been using CodeMirror for its integrated code editor since its introduction. As CodeMirror 6 reached a stable interface with the promise of better touchscreen support, it was time for an upgrade! During which I wanted to introduce language server support. The...

Should I Even Eat That Onion?
27 May 2017 | original ↗

This is just a long overdue rant. A little over a year ago, I ordered a power bank from a very reputable online store. Compared to my previous experiences with other stores, they seemed super professional. I received a phone call from them to get the order confirmed, and a couple of days later they delivered it right to my doorstep. Amazing...

Building a Recommendation Engine
5 Feb 2015 | original ↗

Ever wondered how a recommendation engine works? I did. Turns out, the mechanics involved in generating recommendations is actually pretty neat! You can learn more about it in the article I wrote for Toptal on the anatomy of a simple recommendation engine.

tar
25 Aug 2014 | original ↗

Tar is a file format that allows you to archive files and directories while preserving flags and other file information. Tar is also the name of the Unix utility that manipulates these files and is also popular for being notoriously enigmatic. Did you know? Tar, the name, is derived from “tape archive”. But Ridwan, I don’t store my files on...

Using an external USB drive for the root file system of a Raspberry Pi
13 Jan 2014 | original ↗

By design, a Raspberry Pi always requires an SD card to boot from. But one can still have its root partition located on an external storage device. Be it for reasons involving speed improvement, or avoid challenging the write endurance of an SD card. The details in the following steps may vary based on the distribution of Linux being used, but...

Hello World
27 Dec 2013 | original ↗

Just a few hours ago I didn’t even know that I would suddenly have the urge to write. Heck! I didn’t even know that I would be creating a blog for that. But now that my first post is live, I guess I will have to make it a habit. The first post is definitely about saying “hello”. And I thought, what better way is there to say that than to say it...

↑ These items are from RSS. Visit the blog itself at https://hjr265.me/blog/ to find everything else and to appreciate author's digital home.