The Git Bash prompt in Windows is shockingly slow. I found this gist that speeds it up considerably. Simply place this in your user's .bash_profile file.

# Very very fast __git_ps1 implementation 
# 100% pure Bash (no forking) function to determine the name of the current git branch
# Modified from: https://gist.github.com/Ragnoroct/c4c3bf37913afb9469d8fc8cffea5b2f
# Which was inspired by https://gist.github.com/wolever/6525437
function __fastgit_ps1 () {
    branch=""

    local headfile head branch
    local dir="$PWD"

    while [ -n "$dir" ]; do
        if [ -e "$dir/.git/HEAD" ]; then
            headfile="$dir/.git/HEAD"
            break
        fi
        dir="${dir%/*}"
    done

    if [ -e "$headfile" ]; then
        read -r head < "$headfile" || return
        case "$head" in
            ref:*) branch="${head##*/}" ;;
            "") branch="" ;;
            *) branch="${head:0:7}" ;;  #Detached head. You can change the format for this too.
        esac
    fi

    if [ ! -z "$branch" ]; then
        branch="($branch)"
    fi

    # Edit to suit your needs. Note the branch will be wrapped in parenthesis if it's set. Completely empty otherwise.
    export PS1="\[\e]0;\W\a\]\n\[\e[32m\]\u@\H \[\e[33m\]\w\[\e[0m\] \[\033[36m\]$branch\[\033[0m\]\n\$ "
}
export PROMPT_COMMAND=__fastgit_ps1

Earlier this week Valve released a 20th (!!) anniversary update for Half Life 2. One of the major features added is developer commentary, which they shipped for Episode 1 and 2, but never for the original game. It's been very interesting to listen to the commentary so far (I'm only about half-way through the game), and I've learned several interesting things that I didn't previously know:

  • In the very first platform puzzle, if you try to throw all of the crates out of the window (breaking the puzzle in the process), a new crate is spawned in while you aren't looking; very clever!
  • Loot crates will typically drop whatever you're most in need of at the moment.
  • Eli winks at the player when he says that Alyx is the only thing Gordon can't handle; I've played this game countless times and I've never noted that detail!
  • If given long enough, seagulls will perch on the dune-buggy and poop on it! You can then clean the buggy off by driving through shallow water.

Also released was a 2-hour documentary on the making of the game, which I'm also about half-way through. It's always fun to peer behind the curtain on stuff like this.

Rebuilding I-40

Oct 1, 2024

The recent devastation in western North Carolina from hurricane Helene is truly mind-boggling. There is no doubt that it will be multiple years before the roads there are back to anything resembling "normal." I'm sure the death toll will also only go up from where it is now, which is heartbreaking. Watching on the news, one can't help but to feel utterly helpless.

One aspect of this ever-changing story that will be fascinating to watch will be how the North Carolina DOT chooses to repair the collapse of I-40:

Portion of I-40 which collapsed

In addition to the curved section shown above, a longer, straighter section also washed out, with the adjacent river coming perilously close to the road's edge. From a logistical perspective, it's going to be very interesting to see how they choose to fix this collapse. Is it better to cut into the neighboring rock and essentially shift the road away from the river's edge? Do you try to backfill the river somehow? I can only imagine the engineering challenges that await this repair.

A terrific YouTube channel to follow for this kind of content is Casey Jones - Professional Engineer. He often digs deep into stories such as this, providing his own insights as a certified civil engineer. The video below has some good footage of the damage the highway received, along with some brief commentary about the challenges ahead.

Here's an interesting video describing how the calories within food are determined.

I recently read, though I don't recall where, someone comparing Amazon to a giant flea market. That statement really struck me as profound, and I've been thinking about it quite a bit. Like Google before it, searches at Amazon have grown worse in recent years, with loads more noise and less signal.

For example, when I search for woodworking t-squares, the results I'm shown are rife with Chinese no-name brands. In fact, I have to browse to the 9th item in the list to see a name brand item (Irwin, in my case). The 39th item is a Woodpeckers branded item, the gold standard that most other companies try to copy. Comically, that item is only 3-inches in length!

Nearly every other search I've performed recently has been similar: drawer slides, children's star lamp, etc. Every search results in junk; and I mean junk! Some of the reviews on these things are comical. I've started using the Fakespot browser plugin to try and help weed through the junk, but it's still a struggle.

As a result, I have been turning elsewhere to find reliable products. Home Depot and Ace Hardware are two of the go-to websites recently for product comparisons (I shop for mostly home improvement stuff these days). I am still guilty of using Amazon for the convenience of quick shipping, but I've also been shopping locally more and more. Local shops just don't have that skeezy feeling to them.

I've been listening to a lot of The Moody Blues recently. They definitely have a sound, but I like it! The following album, On the Threshold of a Dream, is a particularly strong entry, though many of their albums from this period are equally as good, including Days of Future Passed and A Question of Balance.

Give it a listen.

USPS is the Worst

Jul 29, 2024

I have a shipment coming in two parts that I'm excited to get. The first part came via Amazon shipping and arrived mid-day. I looked at the other part and saw this:

Shipped with USPS

Inevitably, this means that the shipment is delayed by at least one day. I know this is a first world problem, but I'd love to have an option to avoid using USPS as a means of shipment. Certainly Amazon can do that?

Adventures in Milling

Jul 16, 2024

Last month I was fortunate enough to purchase a Dewalt 735x thickness planer. My goal with this addition to the shop was two-fold:

  1. Make it possible to mill my own lumber from rough stock
  2. Easily thickness the lumber I have

In all my previous woodworking projects, I've used either S4S (surfaced-four-sides) or S2S (surfaced-two-sides) lumber; that is, all (or most) of the milling work has already been done for you. Buying S4S material is the most expensive way to purchase lumber. The cheapest way to purchase it is in the rough; the boards have been cut by the sawmill, but none of the faces are clean, square, or parallel. It's up to you, the woodworker, to fix that.

As an introductory step into the world of milling, I purchased enough rough Sapele lumber to build two patio side-tables. Each table is a modified version of the California Casual Patio Table that I made over five years ago, which is now all but falling apart.

Since I don't have a jointer, I built myself a jointing sled for the planer. It's an incredibly simple jig: a sheet of MDF with a small cleat glued to one end. Just stabilize the lumber that you want to joint on the sled with shims, then send it through the planer, taking off just a hair at a time. Eventually, the entire surface will be planed and the face will be both flat and parallel to the sled's reference surface (which is also flat). The lumber can then be sent through the planer to get the opposite face parallel (and flat). Combine this with an edge-jointing jig, which I built a while back for my table saw, and I can now convert rough lumber to S4S!

As with most things, there has been a learning curve. I've first learned that milling is typically at least a two-day process. The first step is to mill the lumber to rough thickness (7/8", for example, if the final thickness is to be 3/4"), and then let it rest for a night or two. The next milling process will take it to final thickness, and remove any warping that occurred after the first round. Rushing the process will yield warped lumber, which is a problem I ran into with the first table. Happily, the warpage was minimal, so I was able to recover.

I've also learned that milling creates a ton of sawdust. I'm amazed at how much sawdust results from the thickness planer; bags and bags of it!

All in all, this has been an enjoyable area of woodworking to learn and explore. The results speak for themselves, I think; the lumber I've milled for these side tables has been among the best quality I've worked with so far. It's a joy to construct something and have it come together so neatly. I look forward to using these skills in upcoming projects.

Here's a terrific video from Rick Beato on why music is getting worse. He's a music producer (and has a terrific channel), so if anyone knows the ins and outs, it's him. Check it out.

Arctic Outpost AM 1270

Jun 13, 2024

I found a terrific radio station today on Radio Garden: Arctic Outpost AM 1270, "broadcasting from the top of the world." Based out of Longyearbyen, Norway, the radio station is truly way up North. They play 78's from 1902 to 1958, including this truly hilarious ditty I hadn't heard before:

Be sure to check out this station. It's commercial free and definitely worth a listen!

I've mentioned once before some of the packages I use in Sublime Text, but it's also useful to keep track of the customized settings I use in a few of them. This post will help me track that kind of thing.

FileDiffs

I like WinMerge for doing visual diffs, so that's what I configure here.

{
    "cmd": ["C:\\Program Files (x86)\\WinMerge\\WinMergeU.exe", "$file1", "$file2"]
}

LSP

I like seeing my diagnostic counts in the status bar.

{
  "show_diagnostics_count_in_view_status": true,
}

LSP-ruff

To stay current, I use a custom installation path, which I can keep up to date with the latest release.

{
    "initializationOptions": {
        "globalSettings": {
            "logLevel": "info",
            "path": ["C:\\Python\\Python31203\\Scripts\\ruff.exe"],
            "interpreter": ["C:\\Python\\Python31203\\python.exe"]
        }
    }
}

MarkdownPreview

Just the vanilla parser for me, thanks.

{
    "enabled_parsers": ["markdown"]
}

TodoReview

This config adds a few extra locations to ignore when looking for TODOs:

{
    "exclude_folders": [
        "*.git*",
        "*junkyard*",
        "*logs*",
        "*sample-data*",
        "*venv*",
    ]
}

ripgrep

Apr 17, 2024

For years now, I've been using ack to search for stuff via the command line (it's so much better than grep!). One of its drawbacks, however, is its reliance on having an installed Perl interpreter. In fact, ack is the only reason I have Perl installed these days. Also, like seemingly so many other projects in recent times, ack development appears to have stopped altogether. Several months ago, I stumbled upon ripgrep, a Rust-powered tool that is orders of magnitude faster than ack and friends.

I haven't been using it for long, but it looks like a worthy replacement for my previous tool of choice. For posterity, here's how I have my global configuration set up; the default colors leave a bit to be desired, especially when using a dark terminal theme, and sorting is disabled by default:

# Change the default colors
--colors=path:fg:cyan
--colors=path:style:bold
--colors=line:fg:green
--colors=line:style:bold
--colors=match:none
--colors=match:fg:0x00,0x00,0x00
--colors=match:style:bold
--colors=match:bg:yellow

# Sort by default (slows things down a bit, but awfully handy)
--sort=path

I placed the file (named .ripgreprc) in my home directory, created an environment variable named RIPGREP_CONFIG_PATH, and then assigned to that variable the path to the config file. Lots of stuff appears to be moving to Rust for performance, and I'm thoroughly impressed with how fast this searching tool is. Be sure to check it out.

Now that I am fully managing this website's back-end, I've had to educate myself on configuring nginx. Here are a few of the things I've learned since starting down this path:

Using try_files

At first, I couldn't figure out the magic for having nginx serve a static file if it was actually present on the server, but fall back to my Django application if it wasn't. The answer is to use try_files, a handy built-in resource for this exact use case. I found this via this helpful entry in the Pitfalls and Common Mistakes article (which itself is a treasure trove of information). The specific entry ended up looking like this:

server {
    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        # Typical proxy-pass stuff here
    }
}

Shortcutting Known Bad Paths

Don't let your Django app handle paths you know are bad; let nginx offload that processing work for you! I was seeing plenty of accesses against .php files in my server access logs, so I wrote a quick block to reject them:

server {
    location ~* \.php$ {
        return 404;
    }
}

Enabling Strict-Transport Security

Until recently, I didn't even know that HTTP Strict Transport Security was a thing, but it turns out to be pretty easy to implement. Once you have your SSL stuff ironed out and working, you simply need to enable the appropriate header:

add_header Strict-Transport-Security "max-age=5184000; includeSubDomains";

Blue LEDs

Mar 20, 2024

I really enjoyed this video detailing the surprising history of blue LEDs (and why they were so difficult to produce).

A 2018 article on how Joel Spolsky broke IT recruiting randomly popped up in my news feed today. I particularly enjoyed the section that discussed IT recruiting, though the bits relating to StackOverflow haven't aged well; that site is beyond having jumped the shark.

I'm not a people manager, but I have assisted in hiring a number of folks over the years. Some of them turned out to be great developers, while others turned out to be terrible. It's so hard to vet folks based on a handful of interviews. Back when in-person interviews were more of a thing, it was easier. Today's online-only world makes that nearly impossible, especially given that some candidates are no longer local.

Having an actual apprenticeship program would make the process so much easier. New candidates could come aboard for a trial period; 6 or 12 months. Financially, it would be treated like a contract position. During this period they could then be evaluated over time:

  • Is the candidate reliable?
  • Are their development skills what they said they were?
  • Can they communicate effectively?
  • Do they complete deliverables on time?

After the apprenticeship is up, they'd become a "journeyman" and a full-time employee. A program of this sort would greatly reduce the ridiculous speed bump some employers put in the way of hiring developers. It would also make it really easy to get rid of the downright awful developers who occasionally creep in.

This really needs to become a thing.

New Backend

Mar 18, 2024

This website is now running on a DreamCompute instance. One perk of this is that I can run the software stack of my choosing, rather than having to rely on whatever the shared stack is. One drawback, however, is that I'm now in total control; if there's a problem, I have to solve it.

Migrating to this has been fairly rough so far, but I got there in the end. I'll likely have another post in the near future detailing some of the headaches I ran into. There are still a ton of loose ends to tie up, but at least this site is back on the air. Let me know if you spot something broken. Note that I will likely pull down my photos subdomain, as I don't really keep it up to date, and it's not worth migrating in my opinion.

Online Radio Scanners

Mar 15, 2024

What a world we live in.

A few moments prior to my writing this, I heard fire engine sirens outside my house. Looking out my office window and through our neighbor's trees, I could see multiple units responding to a house across the nearest main street. I wondered to myself: "Could I determine what problem they were responding to?" A quick google for "Raleigh fire scanner" returned several hits, one of which was OpenMHz. I pulled up the site, saw that I could filter on "EMS Fire Alerts Only," and selected that option.

Clicking backwards through the playlist, I found the corresponding entry: a gas leak! Cross referencing the reported address, I verified that the house was indeed near our neighborhood. Success!

It's amazing what is possible through the internet. As an aside, this website appears to be a really neat way to listen to what's going on in the area. I can listen to the airport (there was a reported ash-can fire this morning), Raleigh police, or a general overview of all channels (a multiple-vehicle crash occurred a few minutes ago down near Fuquay Varina). Other filters are also available; pretty neat!

Django Web Hosting?

Feb 2, 2024

The web host I've used since the inception of this site will be dropping support for Python (and by extension Django) based applications at the end of March. As such, I'm wondering what alternatives exist. Is anyone familiar with a host that supports Python / Django applications? I'd appreciate any suggestions.

Python dict to tuple

Feb 1, 2024

I had no idea Python could do this, but Ruff taught me something new this morning. Suppose I want to transform a dict into a set of tuples. You can do it in a single line, with no comprehension required!

mydict = {
    'a': 123,
    'b': 456,
    'c': 789,
}
myset = set(mydict.items())
# myset is now: {('a', 123), ('b', 456), ('c', 789)}

I love stumbling upon little hidden gems like this!

High Quality Work

Dec 31, 2023

The Essential Craftsman channel on YouTube occasionally has great philosophical videos (I've featured a few here on the site before). Today's video on "The Mindset of Doing High Quality Work" is worth a watch. In the new year, one of my professional goals will be to improve the quality of my work. In recent times, I've become much more lax in testing the code that I write. This has led to bone-headed bugs that ended up needing a hot-fix, often something that I could have caught had I spent some time testing.

One of the comments in this video really resonated with me: "Strive for perfection, settle for excellence." I think that will be my mantra in 2024 for my professional work.