2025-10-23 03:36:59
Like any configuration obsessed nerd I have a collection of “dot files”; configurations for the variety of tools, command line and otherwise, that I use. Initially having these stored in a Git repository was convenient for experimentation, but over time I have come to appreciate being able to quickly setup my preferred tools with my configuration on a new computer.
When the new computer is one of my own, having a single source for these configurations was fine. As soon as I started using these tools, and their configurations, on work computers, I started running into minor edge cases. Maybe I wanted a different font size for the desktop at work than on my personal laptop. Or, the user specified in the Git configuration needed to be different between work and home.
For a long time I tried having a branch called work to isolate changes that
were work specific. But this was tedious at times and so I stopped using it.
Finally I decided to have two sets of dot files. I created a new GitHub
account, expressly for work. And in that account I made a fork of my dot files
repository. Not only did this simplify the management of of my dot files, it
also allowed me to eliminate configurations from the work side that I only used
in my personal computing.
With the new repository I needed to update the git remote on the local repository. Running this command updates the remote:
git remote set-url origin [email protected]:<work-account>/dotfiles.git
Furthermore, I could add an upstream remote to the original repository:
git remote add upstream [email protected]:<personal-account>/dotfiles.git
Changing the original remote via the set-url command has some advantages:
Symlinks stay intact. The directory hasn’t moved, so ~/.config symlinks
continue to work
History preserved. All the local commits and branches remain.
No re-setup required. Everything stays in place.
Cleaner workflow. It is easy to sync between personal and work repositories if needed.
As a final step after updating the remote, do a git fetch to update
remote-tracking branches.
2025-10-21 10:20:57
For the second time this year, I’ve had joint replacement surgery. In January my right knee was replaced, and at the end of September I had my left knee replaced.
My right knee had been deteriorating for some time. After a year plus on daily prescription pain killers, I was having to take Tylenol in addition to the Mobic, in order to keep the pain to a minimum.
The first surgery was a success, but was not without its challenges. Originally scheduled for Monday, January 6, it had to be delayed until Wednesday, January 8, as a major snow storm dumped some 15 inches of snow on Sunday, effectively paralyzing the city.
In the run up to joint replacement you are given a lot of information. Never having experienced this before you don’t always get the full meaning or import of some things you are told. Staying ahead of the pain with your prescription medications, for example. We did not do a good job initially of keeping up with my pain. As a result I had sleepless nights, and I think my recovery took longer.
The second time around we quickly settled on a 6 am - 12 pm - 6 pm - 12 am schedule for the primary prescription, Hydrocodone. And a 9 am - 3 pm - 9 pm - 3 am schedule for the secondary prescription, Tramadol. I also wasn’t shy about taking two Hydrocondone, especially at bed time. The result has been an almost pain-free recovery. Yes, there is some muscle pain, and stiffness, but I’ve had none of the awake in the night in pain experiences this time around.
Recovery from any major surgery is not a linear progressing. Some days you make progress and feel pretty good, other days you feel like crap and wonder if this will ever end. It helps to have a good support system. I am fortunate to have my wife, Sibylle, here to help me. Not only has she helped with physical things like bathing, or bringing cold packs for my knee, she has been the clear headed, as opposed to drugged, half of this adventure. I’m grateful beyond words for everything she’s done for me throughout both of these surgeries and recovery periods.
I am also lucky to have an outstanding physical therapist. We won the PT lottery when the first therapist my wife had for her first hip replacement was a complete disaster. Through see luck of the draw we found someone who worked with us, and made recovery possible and, if not enjoyable, at least bearable. She is able to hold you to an expectation without being the prototypical physical therapist everyone loves to hate.
My progress that past two weeks has been good. This past weekend was the first setback, and that was only a minor one. I managed to upset the calf in my surgery leg, and it was painfully tight for two days. Today’s PT session was harder as a result, but ultimately good. I managed to gain a degree of straightness by the end of the session.
My first knee is perhaps 95% recovered. I still feel a little pull in my quads going down stairs. And, after two weeks of relying on my right left to lift me up from a seated position, it is a bit sore. When they tell you it can take up to a year for a knee replacement to fully heal, they aren’t kidding.
On paper I have another four weeks of physical therapy. The goal is getting my leg 100% straight, i.e., 0 degree bend, and at least 120 degrees of flex. Currently I’m at about 2 degrees and 104 degrees respectively.
I am pleased with my progress so far. I hope that there aren’t any major setbacks or unexpected challenges in the coming weeks. It will be nice to be back to normal activity in time for the Christmas and New Year’s holidays, if not for Thanksgiving.
2025-10-18 08:46:34
These notes are a result of having both of my knees replaced, one in January and the other in September 2025. I am not a medical professional, I can’t even spell arthrop… orthop…. total knee replacement. While I am trying to be humorous, there is some valuable information here.
Most likely you will have been given a spinal block, and probably had some injections directly in your knee to deaden nerve pain, prior to the surgery. These blocks will last for a while after surgery. Some effect will still be in place up to 24 hours later. This means you’ll be feeling little or no pain. Do not be lulled into thinking you can wait to take your prescription narcotics. Once you fall behind the pain it is very hard to catch up.
This is not the time to be frugal or skimpy. Inexpensive walkers are cumbersome and, I felt, actually impeded my walking. For about $130 you can get a good, folding, walker with wheels that turn, and a handy pouch to carry things with. Worth every penny. I recommend the Stander Wonder Walker Plus
Get a cane that is adjustable and has a four legged foot. It will stand by itself, and provides a better grip on the floor. Using a cane takes some getting used to, maybe practice a little ahead of time. I recommend the BeneCane
Really. Pick a schedule that works for you and stick to it. Use sticky notes as reminders. Get family members to help remind you. What worked for me was a 6 - 12 - 6 - 12 schedule. Pain medication at 6 am, noon, 6 pm, and midnight. That was for the primary narcotic (hydrocodone in my case). I had a secondary pain mediation, tramadal, that I took in between the hydrocodone doses. Roughly 9 am, 3 pm, and 9 pm. If I was up in the night (bathroom) around 3 or 4 am, I’d take a tramadal then too.
You will not be stable, or able to stand comfortably on your surgery leg for a few days. Get a shower seat, preferably one with handles/arm rests. You will not want to climb into and out of a tub. A walk-in shower is best. Ideally you’ll have a care giver who is willing to help you bathe.
Take them. Gradually ease back on the amount and frequency. Don’t be surprised if you have a set back or bad day that leaves you hurting more. When that happens, take more pain medication.
It will be a while before lowering yourself to the normal height of a toilet seat will be easy. Even with a raised seat that adds 3 inches to the height you’ll struggle at first to sit and to get up again. And, once you are used to the higher seat, you’ll likely keep it after your recovery is over.
They’re good drugs. The slightly fuzzy, floating feeling will honestly help you fall asleep.
As a prevention against blood clots, you’ll get to wear TED hose, or Thrombo-Embolic Deterrent stockings, for four weeks following your surgery. Getting one onto your non-surgery leg will be a nice workout. Getting one onto your surgery leg will require more effort. It is possible to have someone help, but pulling the sock up your leg and over your knee will be better controlled by you.
When the prescription says 1-2 every 4-6 hours, believe them.
Your leg is going to be one large bruise from mid-thigh down to your foot. At first there won’t be much, but within a day or two of getting home you’ll be astonished at the amount and size of your bruising. Any bruised spot that is warm to the touch needs to be iced.
Narcotic pain meds can’t be renewed without an okay from the doctor. If you are running low and will need more before the weekend is over, call your doctor by Thursday to ask for more. Insurance is sticky about paying for more than a 7 day supply.
Get some good reusable cold packs to put on your leg and knee. An old fashioned ice bag works well too. Fill it partially with crushed ice and a little water. It’ll mold to your knee or leg nicely that way. These Rester’s Choice flexible ice packs are superb.
Use pillows to elevate your leg as much as possible. Getting the knee above your heart several times a day for 45 minutes is the goal. Every minute will help.
Narcotics can make you nauseous which is miserable on top of being in pain. Doesn’t need to be a whole meal, but something in your stomach will help.
Take pain meds before PT. Plan on being tired afterwards. The goal is regaining flexibility and strength. Some of the quads are cut during the surgery and those muscles need to be strengthened. Your hamstring will be sore and tight. At first you won’t be able to get your leg 100% straight and it’ll only bend about 80-85°. The goal is 0° - I.e., completely straight, and about 120° bent.
Eventually you’ll be able to get by without the prescription pain medication, and can manage with over-the-counter meds. Be prepared to take a prescription one if you have a bad day.
My first knee surgery was nine months ago and I can still feel a slight pull in the quads going downstairs. I was told it can take a year to completely recover from knee replacement surgery.
Lean on your medical team. They want you to succeed, they want your quality of life to be improved following the surgery. They have answers for your questions.
2025-10-16 05:06:10
For work I have both a desktop (Mac Mini) and a laptop (MacBook Pro). As one would expect I use the laptop when I need to be away from my desk and the desktop computer. A considerable amount of my work happens in the terminal. By using tmux I’m able to create a session on the desktop and then remotely access it from my laptop.
This work fantastically, until the desktop gets a new IP address and I can’t remote in. If I’m at home I can walk to the other computer, and check its IP address. Annoying but no big deal. When I’m not at home, I’m stuck.
I created a bash script that checks the current IP address against a saved one. If they match nothing happens. If they are different the script creates a draft email that has the new IP address in it. And it posts a notification that the IP address has changed.
I used a draft email since I can access my mailbox from either computer; no need to send it, just open the draft and copy the new IP address.
The script is managed through a Launch Agent. It runs every five minutes. Worst case scenario is I’d have to wait 5 minutes to get the updated IP address. I think the only time I lose the current IP address is when my Aruba RAP (remote access point) loses power and reboots, so I’m not expecting to get IP address changes email drafts too often.
Here’s the bash script. It needs to be on the PATH and executable for this to work.
1#!/usr/bin/env bash
2# vim: ft=bash
3
4# File to store previous IP
5IP_FILE="$HOME/.current_ip"
6
7# Get current local IP (adjust interface if needed)
8CURRENT_IP=$(ipconfig getifaddr en0)
9
10# Fallback if en0 doesn’t work (e.g., on Ethernet it might be en1 or enX)
11if [ -z "$CURRENT_IP" ]; then
12 CURRENT_IP=$(ipconfig getifaddr en1)
13fi
14
15# Read stored IP
16if [ -f "$IP_FILE" ]; then
17 STORED_IP=$(cat "$IP_FILE")
18else
19 STORED_IP=""
20fi
21
22# Compare and notify
23if [ "$CURRENT_IP" != "$STORED_IP" ]; then
24 echo "$CURRENT_IP" > "$IP_FILE"
25
26 # Create and save a draft email with the IP address
27 osascript <<EOF
28tell application "Mail"
29 set newMessage to make new outgoing message with properties {subject:"Desktop IP Changed", content:"The new IP address is $CURRENT_IP", visible:true}
30 tell newMessage
31 make new to recipient at end of to recipients with properties {address:"[email protected]"}
32 end tell
33end tell
34EOF
35
36 osascript -e "display notification \"IP changed to $CURRENT_IP\" with title \"IP Monitor\""
37fi
Instead of using a cron job to manage the running of the script, the MacOS
preferred way is to use a Launch Agent.
The Launch Agent requires a plist file to define it.
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertiesList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>Label</key>
6 <string>com.user.ipmonitor</string>
7
8 <key>ProgramArguments</key>
9 <array>
10 <string>/Users/USERID/bin/bash/ip_monitor</string>
11 </array>
12
13 <key>StartInterval</key>
14 <integer>300</integer>
15
16 <key>RunAtLoad</key>
17 <true/>
18
19 <key>StandardOutPath</key>
20 <string>/tmp/ipmonitor.log</string>
21
22 <key>StandardErrorPath</key>
23 <string>/tmp/ipmonitor.err</string>
24</dict>
25</plist>
You’ll need to substitute your account ID for USERID on line 10.
The plist defines the script location, sets the interval for how often to execute it (5 minutes (300 seconds)), and defines locations for logging and error messages.
The plist needs to be copied to the user’s Library/LaunchAgent directory. I
had to create this directory on my computer.
cp com.user.ipmonitor.plist ~/Library/LaunchAgents/com.user.ipmonitor.plist
To launch the agent:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist
The start/enable the service:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist
To check if the service is running:
launchctl list | grep ipmonitor
To kick the service, if it is already loaded:
launchctl kickstart gui/$(id -u)/com.user.ipmonitor
Logs can be viewed:
tail -f /tmp/ipmonitor.log /tmp/ipmonitor.err
Make sure the plist file path is correct. Verify with:
ls -la ~/Library/LaunchAgents/com.user.ipmonitor.plist
Verify you updated the user name in the plist.
Check plist syntax
plutil -lint ~/Library/LaunchAgents/com.user.ipmonitor.plist
Ensure the script is executable:
chmod +x ip_monitor
If you still get errors after bootstrap, run:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist 2>&1
This will show the actual error message, which will help troubleshoot the issue.
I have a Git repository with the script, plist, and a detailed README: ip_monitor
2025-09-02 20:10:49
I am using both GitHub and Codeberg for my Git repositories. It is possible to setup multiple push URLs for a given repository. This allows you to interact with both remotes with a single command. Here’s how.
# Set up origin at GitHub
git remote add origin [email protected]:zanshin/repo.git
# Add Codeberg as a second push URL to origin
git remote set-url --add --push origin ssh://[email protected]/zanshin/repo.git
git remote set-url --add --push origin [email protected]:zanshin/repo.git
Once the push URLs are set, running git remote -v will show one remote as the
fetch remote and both as push remotes.
origin [email protected]:zanshin/repo.git (fetch)
origin [email protected]:zanshin/repo.git (push)
origin [email protected]/zanshin/repo.git (push)
With this configuration, git pull will only pull from the fetch remote, in
the example above, GitHub. git push will push to both remotes.
Using Jujutsu, jj, you can push to all URLs using
jj git push --all-remotes
Using git for repository interactions there may be drift between the remotes,
since pulls are only from the fetch remote. Periodic pulls from the other
remote will be necessary to stay in sync.
Using Jujutsu, jj, for repository interactions allows you to use
jj git fetch --all-remotes
which will fetch from multiple remotes simultaneously.
The key point is that git pull only uses the fetch URL, while git push uses
all push URLs.
2025-05-10 20:57:38
I’m 64 years old, so 64 albums. In no particular order.
Genesis - The Lamb Lies Down on Broadway
The Beatles - Let It Be
Rush - Moving Pictures
Boston - Boston
Marillion - Script for a Jester’s Tear
John Denver - Live
Phil Collins - In the Air Tonight
Peter Gabriel - Security
Tony Banks - Curious
Mike Rutherford - Mike and the Mechanics
Pablo Casals - Bach Cello Suites
Yo-Yo Ma - Bach Cello Suites
Truls Mørk - Bach Cello Suites
Janos Starker - Bach Cello Suites
Mistislav Rostropovich - Bach Cello Suites
Zöe Keating - Into the Trees
Styx - Suite Madam Blue
Yes - Yesshows
Led Zeppelin - How the West was Won
Peter Gabriel - i/o
Evanescence - The Open Door
Mike Oldfield - Tubular Bells
Kate Bush - Hounds of Love
Sol Gabetta - Prayer
Johnny Cash - American IV: The Man Comes Around
Film & the BBs - Tricycle
The Beatles - Let It Be (Naked)
Alannah Myles - Alannah Myles
Steve Winwood - Back in the High Life
Supertramp - Crime of the Century
Paul Simon - Graceland
The Nylons - Happy Together
Martin Page - In the House of Light and Stone
Michael Penn - March
Yes - Fragile
ZZ Top - Antenna
Boston - Boston
Melissa Etheridge - Brave and Crazy
Dire Straits- Brothers in Arms
Pink Floyd - Delicate Sound of Thunder
Anthony Phillips - The Geese and the Ghost
Fleetwood Mac - Greatest Hits
Rodrigo y Gabriela - Rodrigo y Gabriela
U2 - Songs of Innocence
Jethro Tull - Thick as a Brick
Queen - Classic Queen
Eagles - The Very Best Of
Heart - The Essential Heart
Styx - The Grand Illusion
The Police - Synchronicity
Atomic Blonde - Atomic Blond Soundtrack
The Beatles - Love
Oblivion - Oblivion Soundtrack
Daft Punk - Iron Legacy Soundtrack
Tracy Chapman - Tracy Chapman
Nigel Stanford - Automatica
Massive Attack - Mezzanine
Afro Celt Sound System - Further in Time
Lorenna McKennitt - Nights from the Alhambra (Live)
Nancy Griffith - One Fair Summer Evening (Live)
Leonard Bernstein, Wiener Philharmoniker - Beethoven Ninth Symphony
REO Speedwagon - The Hits
Mike Oldfield - The Songs of a Distance Earth
K. D. Lang - Absolute Torch and Twang