Skip to content

End of a good year, start of an even better one

The last week of 2025 and the start of 2026.

Started 2026 with a Park Run (jog) with a Strava time of 27 minutes 46 seconds, but that doesn't seem right as I think my fitness tracker got confused. My Park Run recorded time was 35 minutes and 25 seconds, which isn't bad considering I was a minute late to the start 🤣

My injuries continue to recover. I have some exercises to help with 'tennis elbow' and 'trigger finger' in my left arm and hand. An icy walk to the Podiatrist on Friday confirms that the diabetic ulcer has pretty much gone, so now I can start testing activities to see if any of them stop the ulcer from completely healing or getting worse.

Started the slow migration from Material for MkDocs to Zensical. The first step is to create a new book with Zensical before migrating existing books. I've started by creating Practicalli Cycling.

Preparing for a lot of cycling in the new year with some shopping for bicycle and general winter items.

  • Shimano R8000 Cassette, 11-32
  • Shimano HG701 Chain
  • Cospo Cadence sensor (the Garmin sensor got lost some where)
  • Insulated stainless steel water bottles - stop my water getting even colder during the winter months
  • neck warmers, with breathable mesh around mouth (stop the warmer getting too damp)
  • mini bike chain pliers - small enough to carry in top bag in case of issues with chain
  • XOSS XL400 light - a lighter weight light for shorter rides (up to 4 hours)
  • mini cycle saddle bag - a compact bag for TPU inner tubes which should not obstruct the rear light mounted on the seat post

Testing out the reliability of the NAS raid array by watching some classic movies via the DNLP server.

Practicalliλ︎

Goals for the year (so far).

  • Migrate all books and journal to Zensical (estimate: summer-winter)
  • Decommission books that will no longer be worked on (e.g. Doom Linux)
  • Automate dependency updates for all websites and Clojure projects
  • Sustainable Life: first major release
  • Software Engineering: first major release
  • Learning Clojure: first major release
  • Engineering Playbook: extend practices section
  • Clojure Web Services: rewrite book, drop older content

Practicalli Cyclingλ︎

Create a directory for Practicalli Cycling in ~/projects/practicalli/books-new/cycling/.

Using uv to manage Python packages within this project.

  • create a Python Virtual environment
  • activate the virtual environment
  • create a Python project (creates pyproject.toml file)
  • install Zensical package in virtual environment (zensical added to pyproject.toml file)
  • create a Zensical project from template (includes GitHub workflow for publishing)

Create Python Virtual Environment

uv venv
Output of creating Python Virtual Environment
❯ uv venv
Using CPython 3.13.11 interpreter at: /usr/bin/python
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate

Create Python project

uv init
Output of creating Python project
uv init
Initialized project `cycling`
Error if project not created before adding zensical
❯ uv add zensical
error: No `pyproject.toml` found in current directory or any parent directory

Add Zensical to Python project

uv init
Output of adding zensical to python project
❯ uv add zensical
Resolved 9 packages in 386ms
Prepared 2 packages in 2.21s
Installed 7 packages in 346ms
 + click==8.3.1
 + deepmerge==2.0
 + markdown==3.10
 + pygments==2.19.2
 + pymdown-extensions==10.20
 + pyyaml==6.0.3
 + zensical==0.0.15

Create Zensical project from template

zensical new .

GitHub CLI was used to create a remote repository from the local git repository (once files had been committed).

Before publishing the website on Github, the repository must be configured via Settings > Pages to use a GitHub workflow. No workflow needs to be added as the .github/workflows/docs.yml workflow is added when creating the Zensical project from the template.

Neovimλ︎

Time for another plugin and lsp update check.

After the update on 'rogueone' I noticed that the marksman tool was no longer installed via Mason, so I did not see heading prompts when auto-completing links starting with #.

Marksman was installed manually via the Mason menu, SPC p m, and navigating to the marksman tool, pressing i to install.

xclip Debian package allows text to be copied from the terminal to Neovim and vice versa. If xclip is installed after running Neovim, then Neovim must be restarted for the clipboard to work.

Sort lines of textλ︎

In the Post Debian install script I've created, I maintain a list of package names to install in a separate file.

As I evolve the packages list, I add new packages and maintain the list in alphabetical order. This makes it easy to find packages I have already added.

The Neovim :sort command will arrange a selected list of text in alphabetical order. Select the list and run the :sort command. The list updates so it remains in alphabetical order. Note that :sort will put capitalised characters before all lower case characters.

:sort is useful for organising tags in front matter of blog posts such as Practicalli Journal.

AstroNvim update 29 December 2025
  Total: 71 plugins

  Updated (7)
    ○ aerial.nvim  User AstroFile
        5c4e2da chore(master): release 2.7.0 (#483) (10 days ago)
        14102dc fix: navigate to symbol with Snacks in scratch buf (#499) (10 days ago)
        8bb8697 feat: support javascript prototype-attached fns (#495) (5 weeks ago)
        3c42785 refactor: fetch lspkind symbol directly from table (#494) (6 weeks ago)
        5e687b5 feat(yaml): treesitter name array elements symbol based upon "name" key (#485) (3 months ago)
        99a5fb8 feat: treesitter queries for editorconfig, hcl, ssh_config (#484) (3 months ago)
        c7cbbad fix: wait until buffer wipeout to clean up data (#476) (4 months ago)

    ● astrocommunity 0.05ms  start
        65fcdbe feat(file-explorer): add yazi.nvim (#1706) (2 days ago)
        123596f feat(avante-nvim): add missing keybinds (#1705) (3 days ago)
        5095951 feat(utility): added support for nvzone-menu plugin (#1691) (3 days ago)
        32ea083 feat(git): add vscode-diff.nvim.plugin (#1704) (8 days ago)
        03f6c2e feat(just): add just-lsp (#1702) (8 days ago)
        2916a11 feat(colorscheme): Add Alabaster colorscheme (#1701) (8 days ago)
        be1df9e fix(rustowl): fix build failure (#1695) (8 days ago)

    ○ conjure  racket  hy  scheme  guile  julia  lisp  rust  sql  clojure  lua  python  janet  fennel
        90e7dbd Merge branch 'Stansom-main' (7 days ago)
        04dde53 Update broken link to "conversational software development" blog (7 days ago)
        330fe45 Fix link to post in README (7 days ago)
        b549fa1 Fix link to S7 (7 days ago)
        1fcf758 Add newer clients to README (7 days ago)
        b173884 JS: body-contains-forbidden-keyword refactor (3 weeks ago)
        1d89a4a JS: Improve error handling in transformers (6 weeks ago)
        9913945 JS fix namespace import bug (6 weeks ago)

    ○ gist.nvim  GistCreate  GistCreateFromFile  GistsList
        2d4bc31 docs: center image (3 days ago)
        bebbc37 docs: update readme (3 days ago)

    ○ grug-far.nvim  GrugFar  GrugFarWithin
        74eef26 remove repro dir (6 days ago)
        3ecc8f4 adding test (6 days ago)
        a65b75d fixing the issue (6 days ago)
        ecefcac repro dir (6 days ago)
        bc589a1 astgrep-rules fixing replace for operate-within-range (11 days ago)
        e3c3e61 not passing --lang for rules based search (11 days ago)

    ○ octo.nvim  Octo
        09ff70e fix(window): use a single float instead of two floats for title and content (#1403) (11 days ago)
        113d7aa feat(timeline): show repository in cross repo references (#1405) (11 days ago)
        2d82fb4 implement blocking and blockedby (#1388) (11 days ago)

    ○ schemastore.nvim
        60f1b3d Update SchemaStore catalog (3 days ago)
        5ed01fc Update SchemaStore catalog (5 days ago)
        8b92ea8 Update SchemaStore catalog (10 days ago)
        806187c Update SchemaStore catalog (11 days ago)
        2e88a46 Update SchemaStore catalog (11 days ago)

QNAP RAID serverλ︎

Its taken a bit of time to stabalise the RAID arrays on the QNAP NAS server, but after checking the hardware and the file system it seems stable. I may want to copy files across again to make sure they are all okay.

I had copied a large amount of files to the new RAID6 arrays as an initial test. The copying seemed to be successful at the time. However, on a reboot the /dev/md0 RAID array was showing unmounted in the Storage Manager panel (QNAP web app).

I ran a bad block check to check the hardware of each drive. All drives completed their check successfully, which took about a day to complete.

Then ran a file system check and repair. This did highlight and fix some issues with the partition, but all seems good now.

I have a new 4TB drive I will swap with an older 3TB drive, which I think will fail some time this year (although it seems to be good for the moment).

Bad block check on all drivesλ︎

Using the QNAP web app, I selected each drive in turn within the Storage Manager > Volume Management panel, pressing the 'Scan Now' button to initiate the bad blocks check. After a brief pause for a UI refresh, the next drive in the list was set to scan for bad blocks.

Took most of the day and completed successfully across all drives.

One of the RAID arrays was still showing as unmounted.

Check and fix raid array partitionλ︎

SSH onto NAS

Check status of unmounted RAID
[~] # mdadm --detail /dev/md0
/dev/md0:
        Version : 01.00.03
  Creation Time : Thu Dec 25 00:21:41 2025
     Raid Level : raid6
     Array Size : 5857395072 (5586.05 GiB 5997.97 GB)
  Used Dev Size : 2928697536 (2793.02 GiB 2998.99 GB)
   Raid Devices : 4
  Total Devices : 4
Preferred Minor : 0
    Persistence : Superblock is persistent

    Update Time : Tue Dec 30 11:32:41 2025
          State : clean
 Active Devices : 4
Working Devices : 4
 Failed Devices : 0
  Spare Devices : 0

     Chunk Size : 64K

           Name : 0
           UUID : db736564:54a89199:2a50ccda:2c209b95
         Events : 17

    Number   Major   Minor   RaidDevice State
       0       8       67        0      active sync   /dev/sde3
       1       8       83        1      active sync   /dev/sdf3
       2       8       99        2      active sync   /dev/sdg3
       3       8      115        3      active sync   /dev/sdh3

Started checking partition. Seems to have found lots of errors...

Check ext4 partition on raid array
[~] # e2fsck_64 -fp -C 0 /dev/md0
/dev/md0: One or more block group descriptor checksums are invalid.  FIXED.
/dev/md0: Group descriptor 24896 checksum is 0x35a9, should be 0x7229.  FIXED.
Inode 34865161 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 34865163 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 34865169 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 45777004 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 45777193 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 48824345 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 49316034 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 49610821 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 50724865 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 51281921 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 53084172 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 53706761 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 54263809 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 54985702 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 55050316 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 55051133 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 55051991 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 55052209 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 55054947 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 55083721 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 55116533 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 56262664 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 58130433 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 58982401 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Inode 62193665 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 62291970 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
/dev/md0: Inode 62292100 has INDEX_FL flag set on filesystem without htree support.
HTREE INDEX CLEARED.
Duplicate or bad block in use!
/dev/md0: Multiply-claimed block(s) in inode 34865162: 131072
/dev/md0: (There are 1 inodes containing multiply-claimed blocks.)

/dev/md0: File /Multimedia/Movies/The Great Wall.mkv (inode #34865162, mod time Thu Oct 23 20:54:03 2025)
  has 1 multiply-claimed block(s), shared with 1 file(s):
/dev/md0:   <filesystem metadata>
/dev/md0: MULTIPLY-CLAIMED BLOCKS CLONED.
/dev/md0: 30914/91523072 files (1.7% non-contiguous), 471488935/1464348768 blocks

Debian Linuxλ︎

I am optimising the space used by my Debian Linux install, so its not wasting space with files I will not look at.

The Debian Wiki has suggestions for clearing up disk space

Check file system usageλ︎

Check usage across local partitions

df --hlT

Flag meanings

  • h or --human-readable shows file use using K, M, G to simplify, in powers of 1024
  • l or --local only show local partitions, including removable media, but not remotely mounted partitions
  • -T print file system type of partitions, e.g. ext4
❯ df --human-readable --local -T
Filesystem           Type                       Size  Used Avail Use% Mounted on
udev                 devtmpfs                    15G     0   15G   0% /dev
tmpfs                tmpfs                      3.0G  2.4M  3.0G   1% /run
/dev/nvme0n1p2       ext4                       444G  417G  4.7G  99% /
tmpfs                tmpfs                       15G   16K   15G   1% /dev/shm
efivarfs             efivarfs                   154K   67K   83K  45% /sys/firmware/efi/efivars
tmpfs                tmpfs                      5.0M   16K  5.0M   1% /run/lock
tmpfs                tmpfs                      1.0M     0  1.0M   0% /run/credentials/systemd-journald.service
tmpfs                tmpfs                       15G  8.0K   15G   1% /tmp
/dev/nvme0n1p1       vfat                       975M  8.8M  966M   1% /boot/efi
tmpfs                tmpfs                      3.0G  4.1M  3.0G   1% /run/user/1000
/dev/sda1            vfat                        15G   11G  4.8G  68% /media/practicalli/6565-3835
/dev/sdc1            exfat                      954G  952G  2.2G 100% /media/practicalli/6637-3132
nvim-0.11.5.appimage fuse.nvim-0.11.5.appimage  9.7M  9.7M     0 100% /tmp/.mount_nvimbMgJCn

Or simplify the output to specific file system types, e.g. ext4 is typically used for the main file space for system and user files, e.g. / and /home/practicalli/

File usage on main partition

df --human-readable --local --type=ext4

Output of File usage on main partition

Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  444G  417G  4.6G  99% /

System Logsλ︎

A lot of information can be logged to files in /var/log and unless something is seriously wrong then these logs are rarely viewed.

In fact, unless something issue happens whilst I am using the computer I am unlikely to spend time fixing issues. Usually it is far less time consuming to re-install Debian Linux from scratch than to debug an issue that is not immediately obvious.

System logs are managed by journalctl

According to /etc/logrotate.conf the default rotation is every 4 weeks. I changed this to every day, so that journalctl should delete all the rotated logs after 1 day.

Check disk usage by system logs

sudo journalctl --disk-usage

Set logs to rotate daily and remove older logs

sudo journalctl --rotate
sudo journalctl --vacuum-time=1d
Output from rotating and vacuuming logs
❯ sudo journalctl --disk-usage
Archived and active journals take up 852.3M in the file system.

❯ sudo journalctl --cacuum-time=1d

❯ sudo journalctl --rotate

❯ sudo journalctl --vacuum-time=1d
Vacuuming done, freed 0B of archived journals from /run/log/journal.
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@8e133b0d80ca4d5d9c376648aebc03fc-00000000000288ee-000644b980192f0f.journal (11.6M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-0000000000028905-000644b98c33898f.journal (6.9M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@8e133b0d80ca4d5d9c376648aebc03fc-000000000002dcb8-0006455ae0a80c53.journal (7.4M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-000000000002dcbb-0006455ae0cb0de2.journal (83.8M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-000000000006d083-000645610b746488.journal (83.3M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-00000000000ab885-00064562a535bc56.journal (57.1M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@8e133b0d80ca4d5d9c376648aebc03fc-00000000000ccc44-000645827f677255.journal (9.6M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-00000000000ccc7e-000645828de47e13.journal (84.5M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-000000000010c0ba-000645868da56476.journal (83.2M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-000000000014ab3c-0006458c1161009d.journal (83.7M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-0000000000189be8-0006458e19582fb3.journal (81.1M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@0006467be5219895-175a231dd5dba9d1.journal~ (40M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/user-1000@8e133b0d80ca4d5d9c376648aebc03fc-00000000001c70df-000645e6ee14869f.journal (34.1M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@8e133b0d80ca4d5d9c376648aebc03fc-00000000001dc114-0006467be6fc450b.journal (51.4M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@8e133b0d80ca4d5d9c376648aebc03fc-00000000001ef8ff-000646a472870713.journal (51.9M).
Deleted archived journal /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a/system@8e133b0d80ca4d5d9c376648aebc03fc-0000000000203ead-000646c62168fc4d.journal (38.2M).
Vacuuming done, freed 808.5M of archived journals from /var/log/journal/49f1458ea6dd4f33a6bfc2b0d4bf810a.
Vacuuming done, freed 0B of archived journals from /var/log/journal.

Java installλ︎

Install the default-jdk package seems to be the simplest way to automate the install of the current Long Term Support (LTS) version of Java in Debian Linux.

This package also installs certificates required for running Java, from its package dependencies.

visualvm package is fairly recent version in the Debian Linux packages (2.10 package, the latest being 2.2 on the VisualVM website which supports features in Java 24 onward).

Install Java via Practicalli Debian Post Install Script

===========================================
Install default-jdk
===========================================

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  ca-certificates-java default-jdk-headless default-jre default-jre-headless java-common libatk-wrapper-java libatk-wrapper-java-jni libice-dev libsm-dev libxt-dev openjdk-21-jdk
  openjdk-21-jdk-headless openjdk-21-jre openjdk-21-jre-headless
Suggested packages:
  libice-doc libsm-doc libxt-doc openjdk-21-demo openjdk-21-source visualvm fonts-ipafont-gothic fonts-ipafont-mincho fonts-wqy-microhei | fonts-wqy-zenhei fonts-indic
The following NEW packages will be installed:
  ca-certificates-java default-jdk default-jdk-headless default-jre default-jre-headless java-common libatk-wrapper-java libatk-wrapper-java-jni libice-dev libsm-dev libxt-dev openjdk-21-jdk
  openjdk-21-jdk-headless openjdk-21-jre openjdk-21-jre-headless
0 upgraded, 15 newly installed, 0 to remove and 0 not upgrad

Cyclingλ︎

Planning for cycling in 2026 has started, even though its too cold (icy) to actually ride for the next week or so.

A good training plan for the Dragon Ride in June will ensure I can complete in a timely fashion (and hopefully be a little quicker than my friends also doing the ride).

Statistics by yearλ︎

Stats from only cycling activities for each year I have been on Strava (since June 2018)

Stats 2025 2024 2023 2022 2021 2020 2019 2018
Activities 97 55 37 28 47 39 222 138
Distance (km) 6,092.5 2,322.3 1,777.7 1,373.0 2,185.3 2,204.2 8,070.7 2,741.3
Elev Gain (m) 61,706 25,985 19,244 15,872 15,697 15,866 60,000 16,690
Time 280h 41m 105h 31m 86h 15m 64h 38m 91h 42m 103h 33m 395h 49m 218h 28m

Thank you.

🌐 Practical.li Website

Practical.li GitHub Org practicalli-johnny profile

@practicalli@clj.social @practical_li