Author Archives: Hong

About Hong

The maintainer of topbug.net.

Use Vial in Linux Without Configuring udev (and Remain Secure)

Last updated on April 6, 2025

Vial is a GUI program that can configure QMK input devices in real time. In Linux, the default configuration usually stops Vial from accessing the input devices. The official document suggests configuring udev rules. For someone who doesn't frequently configure via Vial, this seems to be overkilling and a bit insecure. After all, it opens up the access to the input devices to the user indefinitely, which may be exploited by malicious software.

In this post, I discuss a method that uses Vial in Linux without configuring udev. I believe this method is more secure than configuring udev. Furthermore, this method is arguably more convenient if you only use Vial occasionally.

Continue reading

Quickly Switch Between HTML and Plain Text in mu4e

Last updated on December 29, 2024

Mu4e defaults loading messages in HTML with shr. While this works well most of the time, sometimes a plain text version is more readable. Therefore, it is desirable to create a key binding to switch between these two versions.

I have the following in my Emacs configuration:

;; Quickly switching between plain text and HTML mime type.
(keymap-set mu4e-view-mode-map (kbd "K")
            (lambda ()
              (interactive)
              (gnus-article-jump-to-part 1)
              (gnus-article-press-button)
              (gnus-article-press-button)))

This binds key Shift+K to switch between plain text and HTML versions of a message, if the message has both versions available.

Convert PNG Images To WebP Images Losslessly Using cweb in GNU/Linux

Last updated on October 18, 2024

To losslessly convert a PNG image to a WebP image on GNU/Linux, run the following command:

cwebp -z 9 input.png -o output.webp

9 indicates the best effort to compress the image, resulting in the smallest image size. You can replace 9 with a smaller number if you prefer a less aggressive compression effort.

If you haven't installed cwebp yet, it is available in the webp package in Debian and Ubuntu.

View the TLS Certificate Details of a Website on the Command Line Using GnuTLS

Last updated on December 27, 2023

With GnuTLS, we can view the certificate details of a website with the following commands (replace "example.com" with the website of your interest):

gnutls-cli --print-cert example.com < /dev/null | certtool --certificate-info

In the command above, gnutls-cli --print-cert example.com < /dev/null prints the certificate of the website in PEM format to the standard output. Its output is then sent as the standard input to certtool --certificate-info, which prints information on the given certificate.

Continue reading

Platform Dependent Python Coverage Test with Tox

Last updated on December 20, 2020

When testing Python programs, coverage.py is often used in measuring code coverage, and enforcing 100% code coverage is regarded as a good practice:

# .coveragerc
[coverage:report]
# Enforce 100% coverage test
fail_under = 100
show_missing = True

However, if there are some lines of code that are platform dependent (i.e., they are never executed on at least one platform), code coverage tests usually fail. For example, the following code snippet would always lead to a coverage that is less than 100% on a platform other than Windows:

if os.name != 'nt':
    # Do something if the OS is not Windows...

You can ask coverage.py to ignore this block by adding a comment # pragma: no cover, but then coverage.py would ignore it on all platforms, including all non-Windows platforms. If you use tox for testing, this issue can be resolved cleanly.

Continue reading

Catching FileNotFoundError? Watch Out!

Last updated on October 3, 2020

In Python, FileNotFoundError is an exception that is raised when a requested file does not exist. Many people assume that when their programs fail to open a file in read-only mode or delete a file, FileNotFoundError must be raised and they should only need to process that. For example, some people would write code similar to:

def process_file(path):
    import sys

    try:
        f = open(path, 'r')  # or os.remove(path)
    except FileNotFoundError as e:
        print(f"File {path} not found!", file=sys.stderr)
        return
    # process the file...

However, this code may actually trigger unexpected errors. The reason is that, the failure to open a file in read-only mode or delete a file is not necessarily caused by the non-existence of the file. Very often, it's for different reasons: insufficient permission, or the file is a directory. In this case, PermissionError or IsADirectoryError would be thrown instead of FileNotFoundError. So, in the example above, one would want to catch all of them:

Continue reading

Makefile Template for a Shared Library in C (with Explanations)

Last updated on October 28, 2019

tl;dr: Save the following file as Makefile and change the source files to the ones that you intend.

# Makefile template for a shared library in C
# https://www.topbug.net/blog/2019/10/28/makefile-template-for-a-shared-library-in-c-with-explanations/

CC = gcc  # C compiler
CFLAGS = -fPIC -Wall -Wextra -O2 -g  # C flags
LDFLAGS = -shared   # linking flags
RM = rm -f   # rm command
TARGET_LIB = libtarget.so  # target lib

SRCS = main.c src1.c src2.c  # source files
OBJS = $(SRCS:.c=.o)

.PHONY: all
all: ${TARGET_LIB}

$(TARGET_LIB): $(OBJS)
	$(CC) ${LDFLAGS} -o $@ $^

$(SRCS:.c=.d):%.d:%.c
	$(CC) $(CFLAGS) -MM $< >$@

include $(SRCS:.c=.d)

.PHONY: clean
clean:
	-${RM} ${TARGET_LIB} ${OBJS} $(SRCS:.c=.d)

The above code snippet is also available on GitHub gist.

Continue reading

Pitfalls in Using a Standard “Global” C++ Function: Its C Counterpart May Be Camouflaging

Last updated on September 30, 2019

A large number of C++ functions in the standard library are extended from standard C functions, such as qsort(), memcpy(), etc. Among these functions, many have overloaded their C counterparts. For example, abs() in C++ is overloaded for both integral and floating-point types, while it is only defined for int in C. These functions, however, are often unwittingly misused as global functions and produce unexpected results.

Continue reading

Automatically Conceal Sender’s IP Address in Email Clients via SSH Tunneling

Last updated on May 5, 2021

Desktop email clients, such as Thunderbird and Claws Mail, are preferred over their web counterparts by many professionals and power users due to their additional convenience and security. However, one big downside is that they often expose the sender's IP address to the receivers, since many SMTP servers record the sender's IP address and put it in the header, something similar to Received: from [xxx.xxx.xxx.xxx] (my.example.com. [xxx.xxx.xxx.xxx]). This, unfortunately, puts the sender's privacy in great jeopardy, as an IP address can reveal so much information including location, ISP, and institution names.

To address this issue, one simple solution is to let the email client connect via a proxy. While a system-widely available proxy works for many users, some of us just want our email clients, but not other programs, to go through a specific proxy. In this post, I'll demonstrate how to use an email client automatically via SSH tunneling. The instructions are specifically tailored for GNU/Linux and MacOS users, as it involves some uses of UNIX commands and bash scripts; if you are on Windows, you can still follow the instructions with the help of Cygwin.

Continue reading

Nikola: How to Deploy Compiled Webpages to a Different Git Repository

Last updated on November 18, 2018

Nikola is one of the most popular static website generators. It compiles source files into final publishable webpages offline and then uploads those files to a web host. Compared to dynamic websites such as those powered by PHP or Ruby on Rails, static websites offer better security and faster page loading.

Nikola provides some utilities to ease the deployment procedure (i.e., uploading compiled webpages), especially for deploying as GitHub pages. Unfortunately, Nikola does not (and its team does not plan to) provide a direct way to deploy the compiled webpages to a git repository that is different from the one that hosts the source files. This is often useful when you want to hide the source files in a private git repository and leave the git repository that hosts the compiled webpages public. Luckily, Nikola provides customizable deploying commands. Assuming output is the directory where the compiled webpages are located, change the value of DEPLOY_COMMANDS using the following in conf.py (replace me@example.com with your email address, https://xuhdev@github.com/xuhdev/xuhdev.github.io.git with your designated git repository on GitHub/GitLab/BitBucket/etc., and master with your designated branch):

DEPLOY_COMMANDS = {
    'default': [
        "cd output && git init && git config user.email me@example.com && touch .nojekyll && git add .",
        "cd output && git commit -a -m 'Nikola'",
        "cd output && git push -f https://xuhdev@github.com/xuhdev/xuhdev.github.io.git master",
    ]
}

Now running nikola deploy should deploy the compiled webpages to your designated git repository and branch.