1764421727

The path of knowledge is collection of explorations which reveal something greater than it’s individual elements, but only to those that wish to see it.

What follows is a collection of small, niche and rather unimportant solutions to some challenges we’ve faced. Each one may very well be irrelevant by the time it is stumbled upon again, but the hope is that it serves as a remainder of the path travelled and the patterns of thought behind it.


1764520956

To reinstall KOReader on a Kindle Paperwhite 2 (PW2) with firmware version 5.12.2 that was previously jail broken and then reset (Settings > Device Options > Reset):

  • Install MR Installer (MRI) by copying extensions and mrpackages to the Kindle root folder
  • Install KUAL (Coplate)
    • Copy Update_KUALBooklet..._install.bin to mrpackages
    • Eject the kindle
    • Execute the installer by typing :log mrpi on the default searchbar
    • Reboot twice, then repeat for Update_KUALBooklet_hotfix..._install.bin
  • Install JailBreak…FW-5.X.hotfix
    • Reboot twice
    • Copy Update_jailbreak_hotfix...install.bin to mrpackages
    • Eject the kindle
    • Execute the installer by typing :log mrpi on the default searchbar
  • Install KOReader
    • Copy koreader to the kindle root
    • Copy extension/koreader to the extensions folder under kindle root
    • Eject the kindle and launch KOReader (KUAL > KOReader > Start KOReader)

Follow the MobileRead threads very carefully (it is easy to misread instructions or do them in the wrong order). All required files can be found on the snapshots page.

If the jail break is not installed properly, KOReader will not launch.

  • Ensure the correct variant of KUAL is installed.
  • The crash log is stored in the koreader folder in at the kindle root as crash.log.
  • If the screen flashes but remains on the home page, the hotfix hasn’t been installed correctly and will log a could not open framebuffer error. Carefully follow the above instructions - reset to start from scratch if necessary.

Kindle root refers to the folder seen when the kindle is plugged in (USB Drive Mode) - it should contain the folders documents, extensions, mrpackages and so on.


1764696164

To generate a key using gpg:

gpg --gen-key

This will prompt for a name and email address, as well as a passphrase to encrypt the private key.

To print the public key:

gpg --armor --export name

Where name is the name provided when generating the key. The --armor flag is used to convert the binary format in which data is stored to base64 encoded text.

To encrypt text, pipe the text directly or provide the filename:

gpg --encrypt --armor -r recepient-name filename

Where recepient-name is the user ID or name of the key pair and filename is the name of the file to encrypt.

To decrypt text, provide the filename or pipe the text directly:

echo "-----BEGIN PGP MESSAGE----- ..." | gpg --decrypt

This automatically selects the correct key and prompts for the passphrase to decrypt the private key.

Encryption can also be done without public/private keys:

echo "Hello" | gpg --symmetric --armor --passphrase "secret-passphrase"

1765043334

To see which process is using a particular port on Linux:

sudo ss -tulnp | grep :portnumber
sudo lsof -i portnumber

Use kill(graceful) or kill -9(forceful) to stop the process.


1765212283

To move a qbittorrent instance, the following folders/files are sufficient:

  • ~/.local/share/qBittorrent/BT_backup
  • ~/.config/qbit/qbitdata.conf
  • ~/.config/qbit/qbit.conf

1770853147

Forgejo runners can be setup on linux machines to use docker containers to execute jobs. These job containers may have difficulty accessing the internet due to a misconfigured DNS; it may produce errors like unable to resolve host and ping: bad address. To resolve this, add a different DNS nameserver:

echo "nameserver 8.8.8.8" > /etc/resolv.conf

1771236153

To compare the output of two commands using git, process substitution can be used:

git diff <(exiftool imageA.jpg) <(exiftool imageB.jpg)

This is different from command substitution $(<command>) which executes the command and replaces with it’s output. Process substitution <(<command>) instead creates a temporary file descriptor containing the command’s output.


1772521864

Bash command chaining:
c1 && c2: execute c2 only if c1 succeeds
c1 || c2: execute c2 only if c2 fails
c1 ; c2: execute c2 after c1 (regardless of result)
c1 & c2: execute c1 and c2 in parallel; follow with wait

From reddit.


1772522569

To find and replace in vim (normal mode):

:%s/oldString/newString/g

: enters command mode
% sets range to entire file
s invokes substitution command
g replacs all occurrences in each line (omit for first occurrence only)

Use gc to ask for confirmation for each occurrence.


1773089881

To reset the root password for a Hetzner VM, navigate to the ‘Rescue’ tab for the server and ‘Reset Root Password’.


1773860522

To repopulate the Archlinux keyring (to resolve invalid signature errors) by resetting all the keys:

sudo rm -r /etc/pacman.d/gnupg
sudo pacman-key --init
sudo pacman-key --populate

The error: failed to commit transaction (invalid or corrupted package (PGP signature)) has a few causes - in this case, trying to reinstall the archlinux without updating the repository and cancelling the partial installation (after it hanged) caused corruption.


1774501304

To create an email alias that doesn’t meet the email requirements in Gitea/Forgejo, create an alias that does meet the requirements (“user1@example1.com”) in Settings > Account > Add email address.

Then, connect to the database using user gitea or forgejo:

psql -u <user>

Ensure that the alias was created and update the email address:

SELECT id, uid, email FROM email_address WHERE email = 'user1@example1.com';
UPDATE email_address SET email = 'user1' WHERE email = 'user1@example1.com';

The goal was to ensure that commits without a valid email address appeared in the heatmap of Gitea/Forgejo. However, it seems the heatmap is generated from the service actions and not git itself; not commits. An attempt was made to use commit details to generate the heatmap, but the issues that arouse were deemed too complex for the added benefit.


1774525948

To delete your entire Neocities site using the neocities gem:

neocities list / | sed 's/\x1b\[[0-9;]*m//g' | tail -n +2 | grep -v '/' | while read -r f; do
  echo "Deleting: $f"
  neocities delete "$f"
  sleep 2
done
  • neocities list / lists all files in root recursively
  • sed strips ANSI color codes (deletes fail otherwise)
  • tail skips the first two header lines
  • grep filters out subdirectory files

Filtering out the subdirectory files and only deleting top level entries is necessary because neocities delete folder runs before neocities delete folder/file-in-folder.txt - the second delete fails because that folder no longer exists.

1774693997

All of this is unnecesary. Just use the prune flag:

neocities push --prune public;

1774532969

Makefiles can use variables from an environment file; this is particularly useful when it is tracked by git but sensitive information needs to be used.

.env

USERNAME="user1"
PASSWORD="pass1"

Makefile

-include .env
export

echo Username is $(USERNAME)
echo Password is $(PASSWORD)

1774681798

To stop highlighting after a search with /search-term in vim, run :noh.


1775718054

rsync can be used to both list and copy files.

List files:

rsync -havP --dry-run -e 'ssh -p 8080 -i ~/.ssh/auth-key' user@host:dir1/ .

To copy files that match a pattern:

rsync -havP --dry-run --include="PATTERN" --exclude="*" -e 'ssh -p 8080 -i ~/.ssh/auth-key' user@host:dir1/ .

This is not particularly novel - dry-run is used to see what files are available and the include and exclude flags are used to select a particular file. This pattern is quite useful because it does not rely on another process to list files and depend on a method of copying results - it is just one terminal based process.


1776418143

To reboot a phone from the Termux commandline with superuser privileges:

sudo -c "reboot"

1776419122

Onion sites use http, not https. If you try to use https, you will be “Unable to connect” with an NS_ERROR_CONNECTION_REFUSED error on Firefox.


1776456353

Using vim to create a file in a folder that doesn’t exist results in an error when saving: E212: Can't open file for writing: no such file or directory. Use the ++p flag (from v9.0) when writing to create the parent directory:

:w ++p

Source: https://neovim.io/doc/user/editing/#%2B%2Bp


1776680423

Use this pattern to operate on a list in parallel using Bash and xargs:

#!/bin/bash

process_item() {
    item="$1"
}
export -f process_item

find . -maxdepth 1 -type d | xargs -P "${JOBS:-$(nproc)}" -I {} bash -c 'process_item "$@"' _ {}
  • find returns a list of items that match the specified filters
  • xargs is used to build and execute commands
    • -P or --max-procs=N specifies the number of processes to use
    • -I or --replace is used to run the command once per line instead of passing everything as an input to one command
    • {} is a placeholder that is substituted with the input value (from the pipe)
    • ${JOBS:-$(nproc)} uses $JOB variable if set; else uses the output from $(nproc)
  • bash -c spawns a bash shell and executes the command that follows
    • $@ is a placeholder that expands positional arguments (just $1={} in this case)
    • _ is an empty placeholder; sets the value of $0
    • {} is a placeholder that is substituted with the input value (from xargs)

GNU parallel supports better output handling (groups and prints on completion instead of interleaving) and progress tracking, but is not installed by default on most Unix systems.


1776769776

The main section of a Hugo site is determined based on the section (folder under content) with most posts. This is quite unexpected - the output suddenly changes based on the state of these subfolders. To define sections explicitly, set mainsections=["section1", "section2"]. Posts from these sections will then be shown on the homepage. Leave it empty if none should be included.


1776785854

To see what commands a package (package_name) provides on Archlinux:

pacman -Ql package_name | grep '/usr/bin/'

1777165426

Use jq to create JSON strings in bash; it is particularly useful when the string contains single quotes and newlines. Special characters can usually be ignored using single quotes, but single quotes cannot be escaped.

data=$(jq -n \
        --arg       keyvar1     "value" \
        --argjson   keyvar2     '{"subkey": "value"}' \
    '{"key1": $keyvar1, "key2": $keyvar2}')

1778524400

To undo the last commit, but keep the changes staged:

git reset --soft HEAD~1