# Matt Michie — Full Blog Content
> Site Reliability Engineer with 20+ years of experience building and operating large-scale distributed systems.
> Source: https://mattmichie.com/llms.txt
---
## A Universe from Three Sectors
- URL: https://mattmichie.com/2026/07/14/a-universe-from-three-sectors/
- Date: 2026-07-14
- Categories: reverse-engineering, programming, nostalgia
Tell me the sector numbers of StarDock, Terra, and Rylos in your TradeWars 2002 game, and I'll hand you back the entire map. All thousand sectors. Every warp lane between them. The location and class of all three hundred and eighty ports. Not a good guess. The exact map, the same one your BBS generated the night it ran Big Bang.
That shouldn't be possible. The map felt like the one unknowable thing about the game, the part you spent turns and whole evenings charting by hand. But it was sitting in plain sight the entire time.
This is the same game I've been [reconstructing from its binaries](/2026/02/05/reconstructing-a-dos-game-from-binary/) for the better part of a year. TradeWars 2002, the BBS door I lost too many teenage nights to. That project is what made this one possible, so I'll start there.
## Big Bang
Every TradeWars game began the same way. Before the door ever opened to callers, the sysop ran a program called BIGBANG.EXE. It laid out the universe: picked the special sectors, strung a thousand-odd warp lanes between random sectors, scattered the ports across the map, and wrote the whole thing into the game's data files. Then the sysop deleted it, or didn't, and the universe stood frozen until the next re-bang months later.
The map was random because Big Bang seeded a random number generator and let it run. Everyone knew this much: same seed, same universe. The docs said so, and warned sysops to change the seed every re-bang or they'd get the same galaxy back. The seed was a knob you turned at creation. Forward only. Nobody talked about turning it the other way, because turning it the other way looked pointless. The universe was already sitting in the data files. If you wanted to know it, you explored it.
And explore it people did. A whole ecosystem of helper tools grew up to do exactly this. TWX Proxy, the zero-turn-map scripts, the CIM reports: they sat between you and the game, watched the sectors scroll past as you moved, and quietly filed away everything they saw. That was the state of the art for thirty years. To know the map, walk the map. It works, it's clever, and it completely sidesteps the question I want to ask, which is: where did the seed go?
## Where the seed went
When the sysop left it set to randomize, Big Bang didn't reach for anything exotic. Turbo Pascal's `Randomize` reads the DOS clock. The hour, the minute, the second, the hundredths of a second, packed into one 32-bit value. That's your seed. From there a plain linear congruential generator grinds it forward, one step at a time:
```
RandSeed := RandSeed * 134775813 + 1
```
Every call to `Random` turns the crank once and hands back a slice of the result. Pick two sectors to warp together, two turns of the crank. Place a port, another turn. By the time Big Bang finishes it's cranked a few thousand times, and every one of those cranks was fixed, completely, by where the crank started.
So the universe is a function of one 32-bit number. That part is obvious. The non-obvious part is how little of that number is real. It came from a clock, and a clock only reads so many values: twenty-four hours, sixty minutes, sixty seconds, a hundred hundredths. Multiply it out and you get 8,640,000 possible seeds. Every TradeWars universe ever generated with a randomized seed is one of those 8.64 million. That's about twenty-three bits. And really it's fewer, because the DOS clock's sub-second field is coarser than it looks. It ticks about eighteen times a second, not a hundred, so a lot of those 8.64 million never actually come up.
Call it twenty-odd bits. The whole thousand-sector galaxy fits in a number smaller than a single frame of a JPEG. You can try every possibility faster than you can read this paragraph. The only question is what you check each guess against.
## Three sectors is enough
You need something observable. Something Big Bang produced early, that you can read off the map without charting all of it.
The landmark sectors are the place to look. The very first thing Big Bang does, before a single warp lane, is roll for the special sectors: StarDock, Terra, Rylos, and the Ferrengi homeworld. Those are literally the first four numbers it produces. And they're exactly the sectors a player knows. You dock at StarDock constantly. You find Terra and Rylos early and never forget where they are. They're the most-remembered coordinates in the game.
They're also safe to read, because the map is the one thing that never moves. Ports get busted, ships come and go, sectors change hands, mines and beacons get dropped and cleared. But the warp lanes and the port locations are frozen the instant Big Bang finishes. Those landmarks aren't game state you have to catch in a particular moment. They're generator output, fixed for the life of the universe.
So the recovery is brute force, nothing subtler. For each of the ~8.64 million clock seeds, run Big Bang's opening moves and check whether it puts StarDock at 431, Terra at 186, Rylos at 244. Throw away the seeds that don't. On my machine this takes a few seconds, in Python, single-threaded, no cleverness.
The whole recovery is a couple dozen lines. This is the core of it, the generator's opening rolls and a sweep over every reading the clock could give:
```python
MULT = 0x08088405 # Borland's LCG multiplier: RandSeed = RandSeed*MULT + 1
def landmarks(seed):
# Big Bang's opening rolls: StarDock, Terra, Rylos.
# Each is Random(990)+11, re-rolled to stay distinct.
s = seed & 0xFFFFFFFF
def roll():
nonlocal s
s = (s * MULT + 1) & 0xFFFFFFFF
return (s >> 16) % 990 + 11
a = roll()
b = roll()
while b == a: b = roll()
c = roll()
while c in (a, b): c = roll()
return a, b, c
def clock_seeds():
# every value the DOS clock can hand Randomize: hh:mm:ss.cc packed into 32 bits
for h in range(24):
for m in range(60):
for sec in range(60):
for cs in range(100):
yield ((sec << 8 | cs) << 16) | (h << 8 | m)
target = (431, 186, 244) # StarDock, Terra, Rylos, straight off the map
print([hex(seed) for seed in clock_seeds() if landmarks(seed) == target])
# -> ['0xc00']
```
One seed falls out. Turning that seed back into the full map is the long part, the part that needed the byte-exact reconstruction, so it's not here. This much just finds the number.
How many seeds survive? I ran that across every possible universe, not just mine:
| Landmarks you know | Universes with a unique seed |
| --- | --- |
| 2 (StarDock, Terra) | 0.005%, about 8,700 candidates each |
| 3 (+ Rylos) | 99.984% |
| 4 (+ Ferrengi home) | 99.999% |
Two landmarks isn't enough; you're left with thousands of candidate seeds. But the third one collapses it. StarDock, Terra, and Rylos together pin the seed uniquely for all but a sliver of possible universes, and the Ferrengi homeworld, or any single sector you've actually charted, mops up the rest. Three sectors and the whole thing falls open.
And once you have the seed you don't stop at the landmarks. You keep cranking. Replay the warp passes and you get every sector's connections. Keep going into the port pass and you get every port's sector and class. The seed doesn't give you part of the map. It gives you all of it, in the order Big Bang built it.
## Proving it wasn't a fluke
It's easy to write a program that reproduces one universe you already have and call it a day. That proves nothing. So I held this to the same standard as the rest of the project: it has to match the original binary, exactly.
I generated a fresh universe with the real, unmodified BIGBANG.EXE, cracked its seed from the landmark sectors alone, and rebuilt the map from scratch. Then I compared, sector by sector, against what the original actually wrote.
All thousand sectors' warps matched. All thousand sectors' ports matched too. The full class distribution, seventy-six class-1 ports on down to nineteen class-8s, each in exactly the sector Big Bang chose. There's no partial credit in a thousand-out-of-a-thousand match. Across that many independent draws, either your model of the generator is exact or it desynchronizes into garbage a few sectors in. It didn't desynchronize. And the recovered seed decoded right back to the clock the run started on: noon, on the dot.
## The honest part
I want to be careful about what this is, because it would be easy to oversell.
This is not cryptanalysis. A 32-bit linear congruential generator seeded from a clock is about the weakest randomness you can build, and brute-forcing a few million possibilities was easy in 1994 and is trivial now. If the whole story were "I brute-forced a small seed space," a security person would rightly shrug.
The hard part, the part that took months and isn't really in this post, was recovering the exact sequence of `Random` calls Big Bang makes. Which sector it rolls first. When it re-rolls a collision. How the passes that repair connectivity decide to add a warp, and precisely how many times they crank when they do. Get any of that wrong by a single draw and the rebuilt universe scrambles into noise almost immediately. That sequence only exists inside a byte-exact reconstruction of BIGBANG.EXE, and building that reconstruction is the real work. The seed crack is the easy last mile on a long, unglamorous road.
A couple of caveats, so I don't overstate the reach. A careful sysop could type in a full 32-bit seed by hand instead of letting the clock choose; a few did. Then the search is the whole four billion instead of a few million. Still minutes on a modern machine, but no longer instant. Almost nobody bothered, because the program told you to randomize and people randomized.
And this is the early DOS line specifically, though all of it. I checked versions 0.98, 1.01, and 1.03, and they carry the same generator: the same tool cracks and rebuilds every one without a change. Under the same clock, 1.01 and 1.03 produce byte-identical universes, and 0.98 differs only in one planet's stats, with the entire warp map and every port in the exact same place. The later branches I haven't tried: the 1995 v2, John Pritchett's 1997 v3 rewrite, the TWGS server that grew out of it. They kept the same bargain, randomize a seed and the universe is fixed, so the weakness plausibly follows. But rebuilding those maps exactly would mean reversing each generator the way I did this one.
## What I couldn't find
I went looking for whether anyone had done this before, and I couldn't find it. The forward direction is documented everywhere: same seed, same universe. Recovering the state of a weak generator from its output is a known trick in general. Exploration-based mapping is the whole helper-tool tradition. But not the specific inverse. Take a real TradeWars universe, recover its discarded clock seed from a few sectors, rebuild the exact map. I found no record of anyone doing it. I can't prove a negative; some sysop in 1996 may have done exactly this and never written it down, and if that's you, I'd love to hear about it. But as far as the public record goes, the map was always something you walked, never something you solved.
## What it means
Not much, practically. The boards are mostly gone, the sysops randomized their seeds like the docs told them to, and the helper tools solved the real problem, knowing where to trade, a long time ago. Nobody needs this.
But I like what it says about the map. For thirty years it was the one part of TradeWars that felt genuinely yours to discover, the fog you cleared one jump at a time. The fog was never thick. A thousand sectors, three hundred and eighty ports, every warp lane you charted at two in the morning: all of it folded up inside a wristwatch reading from the night your BBS ran Big Bang. It just took reconstructing a dead compiler's output to the byte before you could unfold it.
The universe was twenty-three bits the whole time.
---
## Resurrecting the Nirvana Collage Book
- URL: https://mattmichie.com/2026/07/14/resurrecting-the-nirvana-collage-book/
- Date: 2026-07-14
- Categories: nostalgia, infrastructure
Two months ago a stranger sent me a message on Reddit. I found it last week, buried in a chat requests tab I did not know existed:
> Do you have a working link to that Kurt Cobain/Courtney Love/Nirvana book you posted about? I'm very curious about it but the link you posted no longer works. I really appreciate seeing effort being made to preserve media like this.
The book in question: on a rainy night in Seattle, in a pile of items marked "free" in my building's laundry room, I found a handmade book. Black cover, holographic dolphin and cherub stickers, duct tape spine. Inside were hundreds of magazine clippings of Nirvana, Courtney Love, and Kurt Cobain, glued together page after page by someone who clearly loved this band. I took it home, scanned all 52 pages, and published them in March 2023 at fishnofeelings.com, a domain named for the "Something in the Way" lyric.
Then I let the domain lapse.
The book survived three decades, a move to a laundry room, and a free pile. My website about preserving it survived two years. The stranger asking for a working link was pointing at exactly the kind of link rot I thought I was fighting.
## The Recovery
Everything still existed in the Wayback Machine. Not thumbnails, not a half-broken mirror: all 52 scans at full resolution, 166 MB, plus the original writeup. The CDX API tells you exactly what the archive holds for a domain:
```
curl "http://web.archive.org/cdx/search/cdx?url=fishnofeelings.com*&output=json&collapse=urlkey"
```
That returned 116 captured URLs, including `nirvanabook-01.jpg` through `nirvanabook-52.jpg`. Every page of the book. Add `id_` after the timestamp in a snapshot URL and the archive hands back the original bytes, no Wayback toolbar injected:
```
http://web.archive.org/web/20241229024123id_/https://fishnofeelings.com/nirvanabook-01.jpg
```
Fifty-two downloads later, with a two-second sleep between requests to be polite, the book was back. Zero pages lost.
## The Server That Outlived the Site
Setting up redirects surfaced something I did not expect: the site's original CloudFront distribution was still running in an old AWS account. Enabled, certificate expired, faithfully configured to serve a website that no longer had a domain pointing at it. Nobody told the server the site died.
So I re-registered fishnofeelings.com ($16 a year), gave the old distribution a fresh certificate and a redirect function, and now every old URL returns a 301 to the book's new permanent home. Deep links to individual scans land on the exact page file. The link the stranger clicked works again, exactly as originally posted.
The scans live at [/archive/fishnofeelings/](/archive/fishnofeelings/) now, on the same domain as my other recovered artifacts. They are also in a git repository, and still in the Wayback Machine that saved them the first time. Three copies, none of them dependent on me remembering to renew a domain.
## Link Rot Comes for Everyone
The uncomfortable part of this story is that I was the rot. I preserved someone else's artifact with real care, then lost my own infrastructure around it through plain neglect. URLs are promises, domains lapse silently, and the person who made that book never got a say in any of it.
The Internet Archive is the only reason this had a happy ending. I owe them a donation. If you have ever let a domain lapse, you probably do too.
I also replied to the stranger, two months late. The link works now.
---
## Using PowerShell over SSH, Twenty Years Later
- URL: https://mattmichie.com/2026/07/11/powershell-over-ssh-twenty-years-later/
- Date: 2026-07-11
- Categories: windows, microsoft, tooling
Twenty years ago this month I published [instructions for wiring PowerShell to SSH with Cygwin](/2006/07/03/using-powershell-through-ssh/). It involved a mirror hunt, an environment variable named `ntsec`, and a shell that gave you no prompt and no output when it started. The post ended with a plea to Microsoft: just use SSH. "Please don't invent a proprietary Microsoft only tool to do this. Please please please please!"
They invented the proprietary tool anyway (WinRM), and for a while [my Cygwin kludge was the #1 Google result for "PowerShell SSH"](/2008/03/30/a-real-solution-to-powershell-ssh-remoting/), which says more about the state of the ecosystem in 2008 than about the post. But the story has a good ending: Microsoft joined OpenSSH development, shipped it in Windows 10 in 2018, and as of Windows Server 2025 the SSH server is preinstalled on every box. The begging worked. It only took twelve years.
Here is the current state of PowerShell and SSH, as of mid-2026. This is the guide I wish had existed at any point in the last two decades.
## What Ships Where
The OpenSSH client (`ssh`, `scp`, `sftp`, `ssh-keygen`, `ssh-agent`) has been in the box since Windows 10 build 1809 and Windows Server 2019. If you are on anything modern, typing `ssh` in a terminal just works. No PuTTY required (pour one out for a faithful friend).
The OpenSSH server is where the 2025 change landed: on Windows Server 2025, `sshd` is preinstalled. The service is present but stopped until you start it. On Windows 10, 11, Server 2019, and 2022 it remains an optional capability:
```powershell
# Only needed before Server 2025
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
# Everywhere: start it and keep it started
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
```
The firewall rule for port 22 is created automatically when the capability is installed. The in-box build trails upstream OpenSSH; if you want current releases, the [Win32-OpenSSH project](https://github.com/PowerShell/Win32-OpenSSH/releases) ships standalone MSIs, including a 10.0 preview that picks up upstream's post-quantum key exchange (`mlkem768x25519-sha256`). Yes: the operating system I once had to trick into running a remote shell now ships quantum-resistant key agreement. It is allowed to feel a little vertiginous.
## Make SSH Drop You Into PowerShell
Out of the box, sshing into a Windows machine lands you in `cmd.exe`, which is a time machine with none of the charm. The default shell is a registry value:
```powershell
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" `
-Name DefaultShell `
-Value "C:\Program Files\PowerShell\7\pwsh.exe" `
-PropertyType String -Force
```
Point it at PowerShell 7 (`pwsh.exe`), not Windows PowerShell 5.1. PowerShell 7.6 is the current LTS release, it is a separate install from the OS, and everything below assumes it.
## Keys, and the Gotcha That Bites Everyone
`ssh-keygen` on Windows defaults to Ed25519 now. Generate a key, then put the agent to work. The agent service exists on every modern Windows machine and is disabled by default, which is why nobody knows it exists:
```powershell
# Run as administrator, once
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
# As yourself
ssh-keygen -t ed25519
ssh-add $env:USERPROFILE\.ssh\id_ed25519
```
Deploying the public key to a Windows server is where confident assumptions go to die. For a standard user, the key goes where Unix habits expect: `C:\Users\username\.ssh\authorized_keys`. But if the account is a member of the Administrators group, sshd ignores that file entirely and reads `C:\ProgramData\ssh\administrators_authorized_keys` instead. And that file must have a locked-down ACL (SYSTEM and Administrators only), or key authentication silently fails and you fall back to password prompts with no explanation.
There is no `ssh-copy-id` on Windows. This pair of lines is the equivalent for an admin account, ACL fix included:
```powershell
$authorizedKey = Get-Content -Path $env:USERPROFILE\.ssh\id_ed25519.pub
ssh username@hostname "powershell Add-Content -Force -Path $env:ProgramData\ssh\administrators_authorized_keys -Value '$authorizedKey'; icacls.exe ""$env:ProgramData\ssh\administrators_authorized_keys"" /inheritance:r /grant ""Administrators:F"" /grant ""SYSTEM:F"""
```
If key auth ever works from one account and not another on the same box, this split is almost always why. It cost me an afternoon before it became a reflex.
## PowerShell Remoting over SSH
This is the part 2006 me was actually asking for. PowerShell 7's `Enter-PSSession`, `New-PSSession`, and `Invoke-Command` all take SSH parameters, and they work across Windows, Linux, and macOS in any direction:
```powershell
# Interactive session
Enter-PSSession -HostName server01 -UserName matt
# One-shot command with key auth
Invoke-Command -HostName server01 -UserName matt `
-KeyFilePath ~\.ssh\id_ed25519 `
-ScriptBlock { Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 }
# Persistent session
$s = New-PSSession -HostName server01 -UserName matt
Invoke-Command -Session $s -ScriptBlock { Get-Service sshd }
```
Unlike plain `ssh`, this is full object-pipeline remoting: what comes back is deserialized objects, not text. The target machine needs PowerShell registered as an SSH subsystem in `C:\ProgramData\ssh\sshd_config`:
```
Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs
```
The `progra~1` is not a typo: a Win32-OpenSSH bug rejects subsystem paths containing spaces, so you use the 8.3 short name. Microsoft's newer suggestion is a symlink next to the ssh config, which survives PowerShell upgrades and spares you explaining `progra~1` in a code review:
```powershell
New-Item -ItemType SymbolicLink -Path C:\ProgramData\ssh\ -Name pwsh.exe `
-Value (Get-Command pwsh.exe).Source
```
Then the subsystem line becomes `Subsystem powershell c:/ProgramData/ssh/pwsh.exe -sshs`, no short names required. Either way, `Restart-Service sshd` afterward: sshd only reads its config at service start.
## What Still Does Not Work
Honesty section. SSH remoting is transport-level, so everything WinRM does at the endpoint layer is missing: no Just Enough Administration, no session configurations, no endpoint constraints. Sessions do not load your `$PROFILE`. `sudo` does not work inside a remote session to Linux. Key-based sessions have no user credential attached, so they cannot authenticate onward to a file share (the classic second-hop problem persists in a new costume, though `Enter-PSSession` from inside a session works fine since PowerShell 7.1). Windows OpenSSH also does not support `AuthorizedKeysCommand`, so you cannot fetch keys dynamically from Active Directory the way you might on Linux, and Entra ID accounts do not do key auth at all.
If you need JEA or constrained endpoints, WinRM is still the answer. For everything else, SSH is simpler, cross-platform, and uses the keys, agents, and config files you already have.
## The Arc
In 2006 I administered Windows through a Cygwin compatibility layer and typed PowerShell commands into a shell that would not even echo a prompt back. In 2026 I can sit on a Mac, `Enter-PSSession` into a Windows Server that shipped with sshd preinstalled, and pipe objects back out, authenticated by an Ed25519 key held in a Windows service, over a channel that will happily negotiate post-quantum crypto.
Twenty years is a long time to wait for someone to take "just use SSH" seriously. But they did, and they did it properly: real OpenSSH, upstream, not an embrace-and-extend imitation. The kid begging in 2006 would not believe it. He would also want to know what took so long.
---
## Chasing a Phantom Compiler
- URL: https://mattmichie.com/2026/06/30/chasing-a-phantom-compiler/
- Date: 2026-06-30
- Categories: reverse-engineering, programming, nostalgia
I set out to rebuild a 1990s DOS game's executable byte for byte. Not a working clone. Not "close enough." The same bytes. Feed my reconstructed source through a compiler and get back a file whose SHA-256 hash matches the original, all thirty-three thousand-odd bytes of it, exactly.
That goal is how I ended up spending weeks chasing a compiler that, it turned out, never existed.
## Why Byte-for-Byte
There's a reason to set the bar that high. A clone that behaves the same only proves you understood the behavior. A byte-for-byte match proves you understood the *toolchain*: the exact compiler, the exact flags, the order it laid things out in memory, every quirk of how it turned Pascal into machine code. You can't hand-wave it. Either the hash matches or it doesn't. It's the most honest test of understanding I know, because the binary keeps no secrets and grants no partial credit.
The game was written in Turbo Pascal, the compiler every DOS hobbyist had a pirated copy of. The runtime library stamped into the executable read 1990, which pins it to Turbo Pascal 6.0. So I dug up a copy of TP 6.0, reconstructed the source one function at a time, and started compiling. Function by function, the bytes lined up. It was slow and tedious and occasionally thrilling, in the way that watching a diff shrink to nothing is thrilling if you're the kind of person this post is for.
And then the bytes stopped lining up. In exactly two places.
## The Copy With the Seatbelt Cut
The two holdouts were both string copies.
In Turbo Pascal, a string is a length byte followed by its characters. When you assign one string to another, the compiler emits a little copy routine. Stock TP 6.0 always emits the *careful* version: it pushes the destination's maximum length onto the stack and calls a bounds-checked copy that refuses to overflow the buffer.
```
; the careful copy stock Turbo Pascal emits
mov ax, 4 ; the destination can hold at most 4 bytes
push ax
call StringCopyChecked
; the copy in the original binary
push dest ; no maximum length pushed at all
push src
call StringCopyBlind
```
My target called a *different* copy routine. One that took no maximum length and just blindly moved the bytes. A string copy with the seatbelt cut.
I could not get the stock compiler to emit it. Not with any combination of optimization switches. Not with a tiny `string[3]` or a full `string[255]`. Not with typed constants, not with function results, not with concatenation. I tried every shape of source I could invent, and TP 6.0 produced the careful, checked copy every single time. The original used the blind one. Two places, both wrong, and no source I could write would close the gap.
## The Wrong Compiler
So I assumed I had the wrong compiler.
This is a perfectly reasonable assumption, and I chased it hard. I tracked down the 6.01 beta. Turbo Pascal 7, and Borland Pascal 7 after it. TPCX, the protected-mode "Professional" compiler that's a pain to even run today. I compiled the same probe with each one and classified the output. Every last one emitted the careful copy. None of them did the blind one.
Then I found the detail that should have been a much bigger clue than I let it be. There was an *older* build of the game, from 1990, compiled with Turbo Pascal 5, a whole major version earlier. It had the blind copy too.
So whatever produced this wasn't a feature of one compiler release. It spanned at least two major versions, across a span of years. That killed the entire "I just need the right Turbo Pascal" theory in one stroke. The thing I was looking for was older and more stubborn than any single compiler.
## The Tool That Wasn't There
Which left a more romantic explanation, and I'll admit I liked it: the author had a *secret tool*.
Picture it. Some sharp assembly programmer in 1990 writes a little post-processor, a program that walks over the finished executable and rewrites those safe string copies into fast unsafe ones, shaving off the bounds check because he knows it'll never overflow. People absolutely did things like that back then. Cycles were scarce and bragging rights were real. It fit.
So I went looking for the tool. Archive.org. Old shareware CD dumps. The Garbo and SimTel mirrors. Usenet threads from the early nineties. I actually found things, which was encouraging and then deflating: a couple of genuine period Pascal optimizers, including a string-aware peephole optimizer named Sally that did almost exactly the right *kind* of thing. I got it running and fed it the case I cared about. It optimized the copy, all right, by inlining it directly instead of calling the blind routine, and it ignored the one situation that mattered to me entirely. Wrong mechanism. Every tool I found missed.
Meanwhile the binary kept quietly insisting it was legitimate. DOS executables carry a relocation table, a list of addresses the loader has to patch when it places the program in memory. I checked where the blind-copy calls sat in that table. They were threaded in, in load order, perfectly interleaved with everything else, exactly the way a *linker* writes them. Not bolted onto the end the way a patch tool leaves its fingerprints. Whatever did this did it *before* the linker ran, not after.
And the rebuild itself argued against a general-purpose optimizer. Every other byte in the file was plain stock TP 6.0 output. Only this one transform was alien. If the author had run some broad optimizer over the whole program, it would have rewritten the boring code too, and nothing would have matched. The weirdness was surgical. It knew about Turbo Pascal's string routines specifically and touched nothing else.
I'd been at this for weeks. I had a wall of evidence and a culprit I couldn't name. To keep moving, I wrote my own little post-processor that replayed exactly that one transform, just so my rebuild would match, and told myself I'd identify the real thing eventually.
The real thing was a compiler flag.
## It Was a Flag
Here's what I'd missed, and it's embarrassing the way the best bugs are. Every test I'd run, every probe, every "does the stock compiler emit this" experiment, was a plain standalone program. The actual game wasn't. The game used *overlays*.
Overlays are a memory trick from when memory was the constraint that governed everything. A DOS program had roughly 640 KB to live in, and a big program didn't fit. So you split the code into chunks that took turns. Only the chunk you needed right now sat in RAM; the rest waited on disk, and an "overlay manager" swapped them in and out as you called between them. It's virtual memory, hand-rolled, years before the hardware would do it for you.
Now think about a string constant living inside overlaid code. That constant sits in a code chunk the overlay manager is free to evict at any moment. If you pass a pointer to it across an overlay boundary, you're holding a live grenade: the manager might swap the chunk out from under you mid-call, and your pointer now aims at whatever got loaded in its place.
Borland knew this. So when Turbo Pascal compiles overlay-aware code and you pass a string constant to another routine, it doesn't pass the pointer. It first copies the constant into a temporary on the stack, which is always resident and never swapped, and passes *that*. And because the temporary is freshly made and exactly the right size, there is nothing to bounds-check. So the compiler uses the blind copy.
That was it. That was the whole mystery. The "impossible" instruction was stock Turbo Pascal doing something completely ordinary and correct, in a context I had never once tested.
It got sharper still. You don't even have to actually overlay the program. The trigger is a single directive at the top of the source:
```pascal
{$O+} { overlays allowed }
```
Flip that on and the compiler, not knowing whether a given unit will end up overlaid, plays it safe and emits the resident-copy-then-blind-copy everywhere. The author had built the game's shared library units with overlays allowed. That one directive, inherited by everything that linked against those units, was the entire fingerprint I'd spent weeks chasing.
I added the flag, rebuilt, and the alien instructions appeared on their own. Stock compiler, no tricks. My custom post-processor, the one I'd written to forge the mysterious transform, ran and found nothing left to do. It had become a no-op. The phantom tool I'd hunted across twenty years of shareware archives was a checkbox in the compiler I'd had open the entire time.
The part that stings a little: it wasn't even rare. Once I knew the fingerprint, I could see it in other DOS games of the same vintage built with the same compiler. They all carried the blind copy, for the exact same reason. It was never a secret. It was a documented feature behaving precisely as designed.
## The Anticlimax
There's a particular flavor of anticlimax in reverse engineering where the answer, once you finally have it, makes the entire preceding hunt look a little foolish, and is somehow more satisfying for it. I'd built up this whole story about a clever author and a lost tool. The truth was that the compiler was being careful and I was being ignorant. The mystery was never in the binary. It was in my assumptions about how I'd tested it.
The byte-for-byte match works now, which is its own quiet reward: a hash that comes out identical, proof that there's nothing left in those thirty-three thousand bytes I don't understand. But the thing I'll actually keep is the shape of the mistake. Every experiment I ran was clean, rigorous, reproducible. Every one of them was also quietly testing the wrong thing in the same way, for weeks, without my noticing. The hardest bugs aren't in the code. They're in the variable you didn't know you were holding fixed.
Some flags cast very long shadows.
---
## Writing a Shell in Go
- URL: https://mattmichie.com/2026/03/15/writing-a-shell-in-go/
- Date: 2026-03-15
- Categories: go, programming, side-projects
I wrote a shell. Not a wrapper around bash. Not a configuration layer. A shell. Parser, pipeline executor, job control, signal handling, the works. Twenty-two thousand lines of Go that can run my dotfiles and not crash immediately.
The sane response to "I wish my shell did X" is to write a shell function. The insane response is to write a new shell. I chose the second one.
## The Problem with Pipes
Unix pipes are one of the best ideas in computing. Take the output of one program, feed it to the next. Simple, composable, elegant. Except the data flowing through those pipes is unstructured text. Every program in the pipeline has to parse whatever the previous program decided to print, and they all decide differently.
I've written enough `awk '{print $3}'` followed by `sed 's/,//g'` followed by `sort -n` to know that this is fine for quick tasks and miserable for anything complex. The moment you need to filter JSON, aggregate by a field, or join two data sources, you're reaching for Python or jq or giving up and opening a Jupyter notebook.
I wanted a shell where structured data could flow through pipes as naturally as text. Records with fields, not lines with whitespace. Something that still felt like a shell when you needed to `ls` and `grep` and `cd`, but could handle real data processing without switching to a different tool.
## Records Through Pipes
The core idea is record streams. When a command produces structured output, it emits JSON records tagged with a binary marker so the next command in the pipeline knows it's getting records, not text. Commands that understand records can filter, transform, and aggregate them. Commands that don't just see normal text output. Backward compatibility preserved.
In practice it looks like this: you pipe the output of a command that produces records into a transformation, and the transformation operates on fields by name instead of column positions. No more counting whitespace to figure out which field you want. No more sed gymnastics when a column contains spaces.
The record system was the second big feature I built. The first was the Lisp.
## The Lisp Inside the Shell
The shell embeds an interpreter for a language I've been building called M28, a Lisp with Python-like syntax. It handles the data processing side of things: list comprehensions, lambda functions, generators. When you need to do something more complex than a simple pipeline, you can drop into M28 inline.
The integration goes both ways. M28 can call shell commands and capture their output. Shell pipelines can include M28 transformations. The parser has heuristics to figure out whether a parenthesized expression is a shell subshell or a Lisp expression, which was a more interesting problem than I expected. A lot of shell syntax looks like valid Lisp if you squint.
This is where the project gets opinionated. Most modern shell alternatives pick one approach: Nushell has its own expression language, PowerShell has .NET objects, Oil has its own syntax extensions. I went with embedding an existing language because I wanted the shell to be a shell and the programming language to be a programming language. Keep the strengths of both and let them talk to each other.
## Everything Else a Shell Has to Do
Building the exciting features is fun. Building the boring ones is where the time goes.
Job control with proper signal handling. Background processes that get their own process groups. `pushd` and `popd` with a directory stack. `trap` for signal handlers. `set -e` for strict mode. Here-documents. Command substitution. Extended test expressions with regex support. Tab completion backed by a SQLite database that learns which arguments you use with which commands.
Each of these features has edge cases that only become apparent when you try to use the shell for real work. `cd -` should take you to the previous directory, obviously. But what about `cd` with no arguments when `HOME` isn't set? What about `CDPATH` lookups? What about symlink resolution? Every builtin has a story like this, a seemingly simple behavior with a long tail of special cases that bash handles and you didn't know about until yours didn't.
I have new respect for the bash maintainers. They've been handling these edge cases for decades.
## Where It Stands
The shell is functional enough that I use it for development sessions. Parser handles the common cases. Pipelines work with proper file descriptor management. Job control is solid. The record stream system is new and still finding its shape. M28 integration works but the boundary between shell and Lisp could be smoother.
It's not a replacement for bash. It might never be. But it's a useful tool for the specific thing I built it for: processing structured data without leaving the command line. And like all side projects that involve building something from scratch, the real value is in what I learned along the way. How shells actually work is different from how you think shells work, and the only way to find out is to build one.
The code is on [GitHub](https://github.com/mmichie/gosh).
---
## Dropping Starship for plx
- URL: https://mattmichie.com/2026/03/09/dropping-starship-for-plx/
- Date: 2026-03-09
- Categories: rust, terminal, tooling
When I [open-sourced plx](../open-sourcing-plx/) yesterday, it was still a Starship plugin. Three subcommands (`path`, `git`, `tmux-title`) that rendered powerline segments as raw ANSI, hooked into Starship via `[custom]` modules. Starship handled the rest: exit status, command duration, background jobs, the prompt character, and the shell integration that wires it all together.
That's a lot of machinery to render a `$ `.
## Why Remove Starship
Starship was doing two things for me. First, shell integration: registering `precmd` and `preexec` hooks, capturing `$?` and elapsed time, setting `PROMPT`. Second, rendering the segments I wasn't handling myself: the error indicator, duration, job count, and prompt character.
The shell integration is about 15 lines of zsh. The remaining segments are trivial compared to git status parsing. And Starship's overhead (its own binary startup, config parsing, spawning subshells for each custom module) was the dominant cost in prompt rendering. I was paying for a framework to host four format strings.
## What Changed
plx now renders the entire prompt in a single invocation. One binary call, no subshells, no config file. The shell just passes four values:
```zsh
PROMPT="$(plx prompt 20 $exit_status $duration_ms $job_count) "
```
The `prompt` subcommand chains every segment internally:
```
username → hostname → nix-shell → path → git → status → duration → jobs → character → reset
```
Each segment follows the same pattern: take the current background color, render content, return the next background color. The git segment transitions from path's dark grey to its own green or pink. The status badge (when exit code is non-zero) pops out as a red powerline segment. Duration and job count render as inline yellow text on the current background. No arrows, no transitions, just information. The prompt character is white on success, red on failure. A final reset segment draws the closing arrow and clears all attributes.
The git segment was the interesting refactor. It previously ended every path with a reset escape, because it was the last thing in the chain. Now it just transitions to bg(236) and leaves the reset to whatever comes after it. The standalone `plx git` subcommand still works. It appends its own reset.
## Shell Integration
`plx init zsh` outputs the hooks:
```zsh
_plx_preexec() { _plx_cmd_start=$EPOCHREALTIME }
_plx_precmd() {
local exit_status=$?
local duration_ms=0
if [[ -n "$_plx_cmd_start" ]]; then
duration_ms=$(( ($EPOCHREALTIME - _plx_cmd_start) * 1000 ))
duration_ms=${duration_ms%.*}
unset _plx_cmd_start
fi
local job_count=${(%):-%j}
PROMPT="$(plx prompt 20 $exit_status $duration_ms $job_count) "
}
autoload -Uz add-zsh-hook
add-zsh-hook precmd _plx_precmd
add-zsh-hook preexec _plx_preexec
```
`preexec` records the time before a command runs. `precmd` calculates the duration, grabs the exit status and job count, and calls plx. The `20` is the max directory name length for path truncation.
One thing I got wrong on the first pass: raw ANSI escapes in `PROMPT` break zsh's line length calculation. The cursor jumps around because zsh counts escape sequences as visible characters. The fix is wrapping every `\x1b[...m` sequence in `%{...%}`, which tells zsh "this is non-printing, don't count it." plx does this wrapping automatically when rendering prompt output.
## Performance
This is the part I was most curious about. plx replaces both Starship and powerline-go, so the relevant comparison is against powerline-go with equivalent modules:
| Prompt | Mean | Min | Relative |
|---|---|---|---|
| **plx** | **9.1ms** | 5.9ms | 1.0x |
| powerline-go | 37.4ms | 28.1ms | 4.1x slower |
Measured with `hyperfine --warmup 10 --runs 100` on the same repo. Both rendering the full segment chain: username, hostname, nix-shell, path, git, exit status, duration, jobs, prompt character.
The 4x gap comes from three things. Go's runtime startup is heavier than Rust's. powerline-go shells out to git for status; plx uses libgit2 directly. And powerline-go resets ANSI attributes between every segment transition, while plx only sets what changes.
For context, the [Starship migration post](../migrating-from-powerline-go-to-starship/) benchmarked Starship + plx custom modules at 36ms. That included Starship's own startup, config parsing, and spawning bash subshells for each custom module. Removing Starship from the loop cut prompt rendering by 75%.
## Visual Comparison
The clean repo case (no errors, no long commands, no background jobs) is pixel-identical to powerline-go. Same colors, same arrows, same segment order.
The error case is intentionally different. powerline-go renders exit status as a pink badge with a text label (`ERROR`, `SIGINT`). plx uses a red badge with the numeric code (`1`, `130`). Duration and jobs are inline text instead of full powerline segments. The prompt character changes foreground color on error instead of background. These felt like reasonable simplifications. Less visual noise for information I glance at rather than study.
## Dotfiles Changes
The Starship config, the `starship.toml` with all the custom module definitions, is now dead code. The shell init went from `eval "$(starship init zsh)"` to `eval "$(plx init zsh)"`. The [dotfiles flake](https://github.com/mmichie/dotfiles) pins plx from GitHub and nix-darwin puts it on PATH.
```nix
inputs.plx.url = "github:mmichie/plx";
```
Starship is still installed. Other tools reference it, and removing it is a separate cleanup. But it no longer touches my prompt.
## The Arc
This has been a longer journey than I expected. It started with [powerline-go](../migrating-from-powerline-go-to-starship/), a Go binary someone else wrote. I migrated to Starship with bash helper scripts, then [rewrote those in Rust](../migrating-from-powerline-go-to-starship/) for speed. [Split the Rust code into its own repo](../open-sourcing-plx/). [Moved everything to Nix](../nixifying-my-dotfiles/) for cross-platform builds. And now removed the last external dependency from prompt rendering entirely.
The whole thing is about 600 lines of Rust across a handful of modules. It renders a terminal prompt. Sometimes the right amount of code for a problem is exactly as much as it takes and no more.
The source is at [github.com/mmichie/plx](https://github.com/mmichie/plx).
---
## Open Sourcing plx
- URL: https://mattmichie.com/2026/03/08/open-sourcing-plx/
- Date: 2026-03-08
- Categories: rust, terminal, tooling
In the [Starship migration post](../migrating-from-powerline-go-to-starship/) I wrote about building a Rust binary called `starship-segments` to render powerline-styled prompt segments. It started as a way to match my old powerline-go setup exactly, and ended up 40% faster than both the bash scripts and the Go binary it replaced. The code lived inside my dotfiles repo.
That worked fine for a while. Then I [moved the dotfiles to Nix](../nixifying-my-dotfiles/) and the binary became a Crane derivation built from a subdirectory. Also fine. But the dotfiles repo was accumulating Rust build artifacts, a `Cargo.lock`, and test fixtures that had nothing to do with shell configuration. And if someone wanted to use the prompt segments without adopting my entire dotfiles setup, there was no clean way to do that.
So I split it into its own repo and renamed it [plx](https://github.com/mmichie/plx).
## What It Does
plx has three subcommands:
**`plx path`** renders a powerline-styled working directory. It collapses `$HOME` to `~`, splits the path into components, shows the first on a blue background and the rest on dark grey with thin separators. Deep paths get truncated to five components with an ellipsis.
**`plx git`** renders the entire git status as a series of colored segments with proper powerline arrows between them. Green branch for clean repos, pink for dirty. Each status type gets its own segment: staged files on dark green with a checkmark, modified on orange with a pencil, untracked on dark red with a plus, conflicted on bright red, stashed on dark blue. It also shows ahead/behind counts and detects rebase, merge, cherry-pick, and bisect states.
**`plx tmux-title`** generates compact tmux window titles. A house emoji for home, a folder for regular directories, and a branch icon with repo name and dirty indicator for git repos. The output uses tmux color codes instead of ANSI escapes.
The key design decision is that all git operations go through [libgit2](https://libgit2.org/) via the `git2` crate. No subprocess calls. No `git status`, no `git branch`, no `git stash list`. Just library calls. That's where the speed comes from. The git subcommand runs in about 25ms compared to 52ms for an equivalent bash script that shells out to git.
## 376 Lines
The entire implementation is a single `main.rs`. I thought about splitting it into modules (`path.rs`, `git.rs`, `tmux.rs`) but it didn't feel justified. Each subcommand is one function. The shared code is two ANSI color helpers and a few constants. There's no state, no traits, no abstractions. Just functions that take strings and return strings.
The test suite is another 200 lines in the same file. Tests create temporary git repos with `tempfile`, stage files, modify them, and assert on the ANSI output. They caught a real bug where conflicted files were being double-counted as both staged and modified.
## Building with Nix
The repo has a `flake.nix` so it builds with `nix build` or `nix run . -- path`. My dotfiles consume it as a flake input:
```nix
inputs.plx.url = "github:mmichie/plx";
```
And add it to packages:
```nix
home.packages = [ inputs.plx.packages.${system}.default ];
```
Crane handles the Rust compilation and pins libgit2 in the Nix store. No system-level dependency on libgit2, no Homebrew, no `pkg-config` at build time. It just works on both macOS and Linux.
You can also build it with `cargo build --release` if you don't use Nix. The only dependency is the `git2` crate.
## Integration
plx is designed to work with [Starship](https://starship.rs/) custom modules. The config is minimal:
```toml
[custom.path_segment]
command = "plx path"
when = "true"
format = "$output"
shell = ["bash", "--nologin"]
[custom.git_segment]
command = "plx git"
when = "true"
format = "$output"
shell = ["bash", "--nologin"]
```
The `format = "$output"` is important. It passes raw ANSI escape codes through to the terminal, which is how the colored segments and powerline arrows render correctly. Starship's built-in modules can't do the multi-segment color transitions because the format strings are static. They don't know which segments will be present at render time.
## Why Split It Out
Three reasons. First, the dotfiles repo should be config files and Nix modules, not a Rust project with its own build system and test suite. Second, the flake is cleaner as an input than as a subdirectory build. Third, someone might want fast powerline segments without caring about my shell aliases or tmux config.
The name `plx` doesn't mean anything in particular. Short, easy to type, not taken on crates.io. Good enough.
The source is at [github.com/mmichie/plx](https://github.com/mmichie/plx).
---
## CS Homework from the Turn of the Millennium
- URL: https://mattmichie.com/2026/03/03/cs-homework-from-the-turn-of-the-millennium/
- Date: 2026-03-03
- Categories: programming, nostalgia, nmsu
I pulled a backup of my old home directory off a server recently. `/home/ugrad5/mmichie/class/`, New Mexico State University, mostly 2001-2002. Twenty-five directories spanning a full CS degree: data structures, algorithms, compilers, operating systems, networking, parallel computing, assembly, graphics, and a couple of contest entries. About 770 files, mostly C, some Java, a handful of 68HC11 assembly.
This is the sequel to [learning Pascal in the Canal Zone](/2026/02/24/learning-pascal-in-the-canal-zone/). Same person, six years later, different country.
## Hello, My Name Is
CS 171. The first assignment. `Name_Tag.java`, the whole thing:
```java
// Matt Michie
// CS 171
// Lab 5 - Name Tag Program
// Prints a command line argument.
class Name_Tag {
public static void main (String[] args) {
System.out.println ("Hello. My name is " + args[0]);
} // method main
} // class Name_Tag
// -=-=-=-=-
// Output
// -=-=-=-=-
// bear[2] java Name_Tag Matt
// Hello. My name is Matt
```
The output is pasted right into the source file as a comment. The hostname was `bear`. The program is twelve lines including blanks.
## Registers and RAM
CS 273 was embedded systems, programming a Motorola 68HC11 microcontroller in assembly. `hw1.asm` implements a comparison and swap routine:
```asm
* system constant
RAM equ 0
STACK equ $ff
EEPROM equ $f800
RESET equ $fffe
* data area
org RAM
a rmb 1 * int a ;
b rmb 1 * int b ;
c rmb 1 * int c ;
tmp rmb 1 * int tmp;
* code area
org EEPROM
n1 fcb 3 * a = 3;
n2 fcb 2 * b = 2;
n3 fcb 1 * c = 1;
start
* program code
ldaa n1
ldab n2
staa a
stab b
```
Every line has a C equivalent in the comments. `ldaa` becomes `a = 3`. `stab` becomes `b = 2`. The mapping between high-level intent and raw register manipulation is spelled out instruction by instruction, the way you have to think when there are no abstractions left.
## Red-Black Trees
CS 372, Data Structures and Algorithms. The extra credit assignment was a red-black tree implementation. `redblack.c`, dated November 15, 2001:
```c
RedBlackTree *Insert(int key)
{
RedBlackTree *current, *parent, *x;
current = root;
parent = 0;
while (current != NIL) {
if (key == current->key)
return (current);
parent = current;
if (key < current->key)
current = current->left;
else
current = current->right;
}
x = (RedBlackTree *) malloc(sizeof(*x));
x->key = key;
x->parent = parent;
x->left = NIL;
x->right = NIL;
x->color = red;
```
Full insert with rebalancing, left and right rotation, delete with fixup. The sentinel node's key is `666`. The tree prints itself with parenthesized inorder notation. This was the assignment where you first internalize that a data structure isn't just a concept from a textbook; it's memory you allocate, pointers you maintain, invariants you restore after every mutation.
## Building a Compiler
CS 370 was compilers. The work started with `token1.c`, a tokenizer that recognizes words, numbers, periods, comments, strings, and reserved words. Each character maps to a code via a 256-entry lookup table:
```c
for (ch = 0; ch < 256; ++ch) char_table[ch] = SPECIAL;
for (ch = '0'; ch <= '9'; ++ch) char_table[ch] = DIGIT;
for (ch = 'A'; ch <= 'Z'; ++ch) char_table[ch] = LETTER;
for (ch = 'a'; ch <= 'z'; ++ch) char_table[ch] = LETTER;
```
By lab 8, there's a full compiler that parses function definitions and goal expressions, then emits C code. `compiler.c` generates `#include` headers, a `read_number()` function, and a `main()` that prints the result of evaluating the goal expression. The compiler tracks function names, parameter indices, and recursion state. It's a tiny language, but it's a real compiler: source in, executable out.
## FireSHell
CS 474 was operating systems. The big project was FireSHell (FSH), a Unix shell built with [Eric Zeitler](/eric-zeitler/) and Daniel Foesch. The README opens with a warning:
> A new shell being designed with the goal of producing a shell that bridges the gap between GUI and CLI. This is a primitive ***ALPHA*** and should not be used unless you are secure about your system. Note this is a big warning! If your system goes down because you used FSH, and can't do anything from a console anymore, we're really sorry, but that's tough nuggets!
The architecture is clean for a student project. `parse.c` tokenizes the command line, handling quoted strings. `interp.c` is the main loop: read a line, parse it, dispatch. Built-in commands (cd, pwd, set, unset, exit) are handled internally. Everything else goes to `execute.c`:
```c
int execute(char *filename, char* argv[], int deamonize)
{
pid_t child;
int status;
child = fork();
if(!child)
{
DEBUG("I am a child executing in a new environment\n");
execvp(filename, argv);
perror("fsh");
exit(-1);
}
if(!deamonize)
{
DEBUG("I am a parent waiting away");
waitpid(child, &status, 0);
/* flush std buffers in case the child is dumb */
fflush(stdout);
fflush(stderr);
fflush(stdin);
}
else
DEBUG("program deamonized, so I continue...");
return 0;
}
```
Fork, exec, wait. The comment "flush std buffers in case the child is dumb" is the kind of defensive programming you learn from experience. The TODO file lists what they never got to: pipes, redirection, aliasing, configurable prompts. The CREDITS file names Eric's "Q&D Shell" (Quick and Dirty) as the foundation. The shell script `test.fsh` starts with `#!/bin/fsh -f` and runs two commands: `ls` and `echo hello`. They shipped what they had.
## Network Othello
CS 484 was networking. The assignments built up from raw sockets to a protocol with checksums, NAK/ACK framing, and error codes. `program2/server.c` implements a server that accepts TCP connections, parses framed packets, and validates checksums:
```c
void setupSocket(int server_port);
int parsePacket(char *buff, char *tokens[]);
int computeChecksum(char *data);
void readFrame(char *buffer);
int sendNAK(char *frame_id, char *error_code);
int sendACK(char *frame_id, char *message);
```
The final project was an Othello game server. Two clients connect, choose colors, and play a full game of Reversi over TCP, with the server managing the board state, validating moves (checking all eight directions for outflanking), and announcing the winner. Socket programming, process forking per client, game state machine, protocol design. It's a lot of moving parts for a class project.
## Parallel Mandelbrot
CS 491 was parallel computing with MPI. `mandelbrot.c` distributes the computation of the Mandelbrot set across multiple processors. The master opens an 800x800 X11 window, sends row numbers to workers, and draws points as results come back:
```c
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
MPI_Comm_size(MPI_COMM_WORLD,&mysize);
if(myrank == 0)
{
/* ... open X11 display, create window ... */
for (num=1; num < mysize; num++)
{
MPI_Send(&row,1,MPI_INT,num,data_tag,MPI_COMM_WORLD);
count++;
row++;
}
do
{
MPI_Recv(&rowstruct,X_RESN+2,MPI_INT,MPI_ANY_SOURCE,
MPI_ANY_TAG,MPI_COMM_WORLD,&status);
count--;
if (row < Y_RESN)
{
MPI_Send(&row,1,MPI_INT,rowstruct.procnum,
data_tag,MPI_COMM_WORLD);
row++;
count++;
}
/* ... draw points ... */
} while (count > 0);
}
```
Each worker receives a row number, iterates `z = z^2 + c` up to 100 times per pixel, and sends back which points are in the set. The master uses a work pool pattern, sending new rows to whichever processor finishes first. The iteration itself is the standard escape-time algorithm:
```c
do
{
temp = z.real*z.real - z.imag*z.imag + c.real;
z.imag = 2.0*z.real*z.imag + c.imag;
z.real = temp;
lengthsq = z.real*z.real+z.imag*z.imag;
k++;
} while (lengthsq < 4.0 && k < 100);
```
The same class had `montecarlopi.c`, which estimates pi by throwing random points at a circle and counting how many land inside. Also parallelized with MPI, also using a master-worker pattern. The formula is right there in the comments: `pi = 4 * amount in circle / amount total`.
## Dots-n-Boxes
The ACM programming contest entry. `prototype.c`, a Dots-n-Boxes AI. The header sets the tone:
```c
// Matt Michie
// mmichie@linux.com
// ACM entry
// Thanks / greets go out to:
// PI the soundtrack
// Astral Projection
// ezeitler
// dcook
// the milkman
// truefluke
// This program sucks. I ran out of time so I'll submit what
// I have.
// Although if i wake up early maybe i'll work on it (yeah right).
```
The AI tracks a 2D board of lines (vertical, horizontal, or both), looks for three-sided boxes it can close, and falls back to random moves when it can't find one. The `MakeMove` function is self-described as "Full of UGLY HACKS!!!!!!!!!!!" and includes a goto labeled `Fucked:`. The three-sided box finder returns `666` when it finds one. He submitted what he had.
The greets section is a snapshot of the NMSU CS social circle circa 2001: ezeitler (Eric Zeitler, the FireSHell co-author and later a Signalnine collaborator), dcook, the milkman, truefluke (Darren Morrin, Signalnine's most prolific poster). The email is `mmichie@linux.com`, because that's where I was volunteering at the time.
## The Arc
CS 171 to CS 491 is roughly the shape of an undergraduate CS education. You start by printing your name. You end by distributing fractal computation across a cluster and rendering it in real time. In between, you learn that a shell is just parse-fork-exec in a loop, that a compiler is just recursive descent with code generation, that a red-black tree is just a binary tree that refuses to become a linked list, and that every network protocol is just framing, checksums, and state machines.
The code quality is uneven in the way that student code always is. There are elegant implementations sitting next to hacks held together with gotos. There are meticulous comments in one file and none in the next. The FireSHell team divided the work cleanly but never finished the TODO list. The ACM entry was submitted half-done at midnight with Astral Projection playing in the background. That's what learning looks like.
The [featured files are here](/archive/nmsu/): the programs referenced in this post, from Name_Tag.java through the Mandelbrot renderer. The full archive is in the repo.
---
## Building a Programming Language for Fun
- URL: https://mattmichie.com/2026/02/26/building-a-programming-language-for-fun/
- Date: 2026-02-26
- Categories: programming, go, side-projects
I've been building a programming language. It started as an experiment and turned into sixty thousand lines of Go. That's what happens when you try to answer the question: what would a language look like if Lisp and Python had a kid?
## The Premise
I've always liked two things about Lisp that most people hate: the parentheses and the homoiconicity. Code is data, data is code. It's a simple idea with deep consequences. Macros work because you're manipulating the same structures the interpreter reads. There's an elegance to it that never wore off for me.
But I also write a lot of Python. Python gets things right that Lisp never bothered with: readable syntax for common operations, a pragmatic standard library, data structures that do what you expect without ceremony. Python's dict comprehensions are nicer than anything Lisp has for the same task.
So I built a language that tries to have both. S-expressions when you want them, Pythonic syntax when you don't. The same interpreter handles both:
```
# Lisp style
(def factorial (n) (if (<= n 1) 1 (* n (factorial (- n 1)))))
# Pythonic style
def factorial(n): (if (<= n 1) 1 (* n (factorial (- n 1))))
```
You can mix them freely. The parser desugars the Pythonic forms into the same AST. Under the hood, it's all S-expressions.
## What I Actually Built
The interpreter is written in Go, which turned out to be a good choice for a language runtime. Go's interfaces map cleanly to the kind of type dispatch a dynamic language needs. The garbage collector handles memory management for hosted objects without me having to think about it.
The feature list got long. Classes with inheritance and method resolution order. A protocol system with Python-style dunder methods so you can define `__add__` and `__getitem__` on your own types. Exception handling with proper tracebacks. Generators with yield. List comprehensions, context managers, f-strings. Most of the Python features I actually use day-to-day.
The protocol system was the most satisfying piece to design. Operator dispatch goes through three tiers: check for a dunder method first, then a protocol implementation, then fall back to type-based defaults. It means the language is extensible in the same way Python is. Define `__iter__` and `__next__` on your class and for-loops just work.
I also spent time on Python standard library compatibility. Pure Python stdlib modules can run directly when possible. For C extension modules, I wrote Go stubs that provide the same interface. The goal isn't perfect compatibility. It's enough compatibility that useful code works without modification.
## The Architecture Rabbit Hole
At some point I started thinking about what this could become if the architecture was right. The idea is a multi-frontend, multi-backend design: multiple source languages parse into a shared intermediate representation, which can target multiple backends.
Right now there's one frontend (M28's hybrid syntax) and one backend (a tree-walking interpreter). But the architecture is designed so a Python frontend could parse into the same IR, and a bytecode VM or LLVM backend could execute it. Solve the problem once in the middle layer and every frontend/backend combination benefits.
I've designed the bytecode VM on paper. Register-based, targeting a 3-10x speedup over the tree walker. Haven't built it yet. The interpreter is fast enough for everything I use it for, and there's always another language feature that's more interesting to implement than making the existing ones faster.
## Why Build a Language
People don't ask "why" as much as you'd expect. Maybe because the answer is obvious: because it's interesting. You learn things building an interpreter that you can't learn any other way. How scoping actually works. Why tail call optimization matters. What makes a type system feel good to use versus feel like it's fighting you.
Every language is a set of opinions about how programmers should think. Building one forces you to articulate your own opinions and then live with the consequences. I think operator overloading should use protocols. I think immutable data should be the default. I think S-expressions are underrated. Now I have a language that embodies those opinions, and I can see where they work and where they don't.
It's also the longest-running side project I have. Languages are never done. There's always another feature, another optimization, another edge case in the parser. It's the kind of project that rewards showing up for an hour on a Tuesday night, making one thing slightly better, and closing the laptop.
The code is on [GitHub](https://github.com/mmichie/m28) if you're curious. It's a toy in the sense that I wouldn't deploy it to production. But it's the most instructive toy I've ever built.
---
## Learning Pascal in the Canal Zone
- URL: https://mattmichie.com/2026/02/24/learning-pascal-in-the-canal-zone/
- Date: 2026-02-24
- Categories: programming, nostalgia, panama
I found a zip file on a backup drive. `pascal.zip`, 927 KB, containing every file from my first programming class. Turbo Pascal, Balboa High School, Panama Canal Zone, 1993-1994. I was fifteen.
Balboa was a DODDS school (Department of Defense Dependents Schools) serving American military families stationed at the bases along the Panama Canal. The school closed in 1999 when the U.S. handed the Canal back to Panama under the Torrijos-Carter Treaties. Everything in this archive, the `.MIL` email addresses, the Panama phone numbers in the BBS dialing directory, the JROTC references, comes from a place that no longer exists in that form.
The archive spans two years: Pascal I starting September 1993, Pascal II ending June 1994. About a hundred source files organized into chapter directories, plus games, a BBS door program, sorting benchmarks, and some documents that have nothing to do with programming but everything to do with being a teenager in Panama in 1994. I've preserved the [featured files](/archive/pascal/) on this site.
## The First Program
`EX8CH1.PAS`, dated September 14, 1993. It calculates the area of a circle:
```pascal
Program CircleArea (Input, Output);
Uses crt; {Tells the computer to use the monitor}
Begin {main}
clrscr;
writeLn ('This program calculates the are of a circle with a radius of 21!');
write ('The area is');
writeLn (3.14 * 21 * 21);
writeLn;
writeLn ('Please press enter now....');
readLn {Waits until the computer presses enter}
End.
```
The comment `{Tells the computer to use the monitor}` is the kind of thing you write when you have no idea what a `uses` clause does but your teacher said you need one. The comment on `readLn`, `{Waits until the computer presses enter}`, suggests I thought the computer was the one pressing keys. The grading rubric is embedded in the file header: Header 5pts, Program Description 5pts, Presentation 5pts, Run of Program 5pts. Twenty points per assignment, every file stamped with the same template.
## Blackjack
By January 1994, Chris Goodno and I built a blackjack game. The first version (`GAMESCH3.PAS`) was a straightforward text-mode card game. Then we got ambitious. The second version (`GAME.PAS`) opens with turtle graphics, spirographs drawn with `TurnRight` and `Forwd` calls, then switches to Gothic and Triplex fonts for the title screen before dropping into the actual game. Every single line of text output randomizes its color:
```pascal
textcolor (random(14)+1);
write ('Computer draws: ');
for computer := 1 to cardnum do
begin {for loop}
number := random(11) + 1;
delay (100);
textcolor ((random(14)+1));
write (number:2:0,' ');
counterc := counterc + number;
end; {for loop}
```
The end-of-game messages are the best part. If you lose:
```
Cash can be paid up front to the disk drive, thank you
```
```
Ode to my Winnings By: C.P.U.
On the outside I look like a sad little computer.
But only if you could see the inside of me....
I would be laughing at your lost....
```
If you win:
```
Good Job, now go away so that I may cheat in peace...
```
The goodbye sequence in the earlier version prints "Thank You For Playing..." one character at a time with `delay(200)` between each letter, then scatters farewell messages in different languages at random screen positions: "Au Revoire", "Chow Bombino", "Adios", "Hasta Luego", "Hasta La Bye-bye", "Syonara", "Gruss Dis", "Gutten Tag", "Salut." This is what happens when two fifteen-year-olds learn about `gotoxy` and `delay` at the same time.
## The BBS Door
`TRIVIA.PAS` in the Chapter 9 directory is not a homework assignment. It's a BBS door program, a game that runs through a bulletin board system over a modem connection. It uses `rmdoor` for remote I/O, detects DesqView for multitasking, identifies the CPU type, and reads the caller's baud rate:
```pascal
program TriviaDoor (Input, Output, Diskfile);
uses rmdoor, crt, desqview, dos, equipment;
{...}
rmwrite('Your baudrate: ');
rmwritel(baudrate);
rmWriteLn('');
rmsetcolor (3, 0);
rmwrite ('This BBS runs DOS ');
rmwriteLnI (dosversion);
rmWrite('Running on a ');
Case Processor of
0: rmWriteLn('What?');
1: rmWriteLn('8088 or 8086');
2: rmWriteLn('80186');
3: rmWriteLn('80286');
4: rmWriteLn('80386');
5: rmWriteLn('80486');
else rmWriteLn('Unknown');
End;
```
It has a configuration program (`CONFIG.PAS`) that supports PCBoard, GAP, SpitFire, RBBS, Wildcat, TriBBS, and WWIV, seven different BBS platforms. The config tool uses a spinning cursor animation while waiting for input, cycling through `|`, `/`, `-`, `\`. It lets callers both play trivia and submit their own questions, which get appended to a data file with attribution: `(Question by: username)`.
I was running a BBS in Panama at fifteen. The evidence is right there in the code.
## The ProComm Dialing Directory
`PROCOMM.DIR` is a binary dialing directory for ProComm, the terminal program I used to call BBSes. The readable strings reveal the local scene:
- **Huracan por Racsapac**, 636641, 1200 baud
- **PCC BBS**, 52-4405, 1200 baud
- **Building 861**, 86-3862, 1200 baud (a military building number as a BBS name)
- **Panama Jack's**, 864784, 2400 baud
- **PC User's Group**, 696180, 2400 baud
- **Mickey Unix**, 52-2013, 2400 baud
Panama phone numbers, 1200 and 2400 baud. This was the entire online world available to me. Each call was a local connection to someone else's computer, probably in a spare bedroom on one of the bases.
## The Email
`MATT.DOC` is a text file, not a program. It's an email I wrote, or was preparing to write, from `pbaca@DODDS-PANAMA.ARMY.MIL`:
> Hey what's up Oscar? I am writing this letter to find out a little bit more about the school you are going to and a little bit more about yourself. I have heard that you are going there on an ROTC scholarship. If so can you tell me a little bit about that. Right now I am considering doing the same thing.
> I am heavily into BBS's at the moment and InterNet is the next step. I am currently a second year cadet in the JROTC program and other than that my main interests are computers. I'm 16 and a Sophomore.
The signature block lists three addresses:
```
Write to me at pbaca@DODDS-PANAMA.ARMY.MIL
OR at bacap@alpha.acast.nova.edu. (Care of Paula Boca)
Or at Matt.Michie@f5.n920.z4.fidonet.org
To read next message press CTRL-ALT-DEL
```
A `.MIL` address, a borrowed university account, and a FidoNet address. Three different networks, none of which is what we'd recognize as being "online" today. The FidoNet address (zone 4, net 920, node 5) places this squarely in Latin America. Zone 4 covered Central and South America. The CTRL-ALT-DEL sign-off is the kind of joke you make when you've been spending too much time around DOS machines.
## The Internet Essay
`MICHIE.DOC` in the TEMP directory is a WordPerfect document, an essay about how the Internet will affect education, written circa 1994:
> The Internet has had and will have a great effect on the way information flows in our society. This network of computers passing information swiftly and from many different sources around the world will have a tremendous effect on education.
> The Internet allow students to gather information with the minimum of work. This not only helps people make new discoveries that would have taken years of work it allows students to get viewpoints on a topic from anywhere in the world. The Internet will also make learning fun, instead of listening to a lecture for a hour a they could be on-line finding out what's going on themselves. An example of this would be chatting via E-Mail or conversing real-time with someone from Russia finding out exactly what the conditions are like.
This was written before the World Wide Web was mainstream, before Google, before Wikipedia. A sixteen-year-old in Panama arguing that the Internet would transform education. The predictions are vague in the way that predictions from that era always are. Nobody could have imagined the specific shape it would take. But the core thesis was right.
## Sorting Benchmarks
`TIMESORT.PAS` is something different from the homework. It's a benchmarking program that compares three sorting algorithms: a Shell sort (PBSort), a Selection sort (KDSort), and a QuickSort. The timing mechanism reads the BIOS tick counter directly from memory:
```pascal
TickCount : LongInt Absolute $0040:$006C;
Procedure StartTiming;
begin
TStart := TickCount;
{start at the beginning of a tick!}
Repeat Until TStart <> TickCount;
TStart := TickCount;
end;
```
The comments contain benchmark results from a 386 running at 33MHz:
```
500 Elements - 0.1 Seconds
1000 Elements - 0.8 Seconds
1500 Elements - 1.4 Seconds
2000 Elements - 2.6 Seconds
3000 Elements - 5.1 Seconds <- Peak efficiency reached
5000 Elements - 15.8 Seconds
```
And the QuickSort results:
```
500 Elements - 0.1 Seconds
1000 Elements - 0.2 Seconds
1500 Elements - 0.4 Seconds
2000 Elements - 0.6 Seconds
3000 Elements - 0.9 Seconds
5000 Elements - 1.8 Seconds
```
The commentary is from someone posting in the Pascal echo of FidoNet, discussing how `Succ()` and `Pred()` are marginally faster than `+1` and `-1`, how range checking doubles execution time, and how OPRO's `ExchangeLongInts()` saves two instructions per iteration. This is the kind of low-level performance obsession that only makes sense when your machine runs at 33MHz and every cycle counts.
## Evolution
The most interesting thing about the archive is watching the code change over nine months.
September 1993 (`EX8CH1.PAS`): no procedures, no variables, hardcoded constants, comments that explain what a monitor is.
April 1994 (`EX23CH5.PAS`):
```pascal
procedure SumUp (N:integer;
var total:integer);
{Pre: N is assumed to be a positive integer although no checking is done ;) }
{Post: Total is modified to be the sum of all integers up to and including }
{ the number entered using recursion }
begin {SumUp}
if n > 0
then
begin {if then}
SumUp (N - 1, total);
total := total + N;
end; {if then}
end; {SumUp}
```
Procedures with parameters. Pre and post conditions. Recursion. A winky face in a formal comment. By Chapter 6, there are typed arrays, enumerated types, and proper data structures. The waffle sales tracking program uses a two-dimensional array indexed by an enumerated type:
```pascal
WaffleType = (Plain, OatBran, RaisinBran, BlueBerry);
SalesDataType = Array [Min..Month, Plain..BlueBerry] of Integer;
```
By Chapter 9, there's file I/O, external libraries, and a real application that talks to modems.
Nine months from `{Tells the computer to use the monitor}` to writing BBS door software. That's the arc.
## Looking Back
These files survived on a backup drive for thirty-two years. The school that produced them closed in 1999. The BBS phone numbers are long disconnected. FidoNet zone 4 is gone. The `.MIL` email domain for DODDS-Panama doesn't exist anymore. The Canal Zone itself was handed back to Panama on December 31, 1999, the same day everyone else was worrying about Y2K.
But the code still reads fine. Pascal is verbose enough to be self-documenting even when the comments are wrong. You can look at `GAME.PAS` and see exactly what two kids thought was cool in January 1994: turtle graphics, rainbow text, snarky AI dialogue. You can look at `TRIVIA.PAS` and see someone who'd already outgrown the curriculum, building real software for a real BBS. You can look at `MATT.DOC` and see a kid trying to bootstrap himself onto the Internet through a borrowed `.MIL` account and a FidoNet node.
The [featured files are here](/archive/pascal/): the programs referenced in this post, the trivia data, the ANSI art, the ProComm dialing directory. It's not useful code. It was never meant to last. But as a record of how someone learned to program in a place that doesn't exist anymore, it's worth keeping.
---
## Rediscovering the Signalnine Source Code
- URL: https://mattmichie.com/2026/02/18/rediscovering-signalnine/
- Date: 2026-02-18
- Categories: programming, nostalgia, side-projects
In 2002, a few of us built a blogging platform. We called it Signalnine, or sig9 on SourceForge, because "Signal Nine" is SIGKILL, the Unix signal you send when something absolutely has to die. The tagline was "The Mozilla of Blogs." The unofficial slogan, coined by truefluke, was "Where v1.0 is a myth." WordPress wouldn't exist for another year.
I found the source code again recently. The original tarball, Sig9-M3-20021113, timestamped November 13, 2002. I pushed it to GitHub mostly as an archival exercise, the way you'd scan an old photograph. I didn't expect to find it interesting. I was wrong.
## The Team
We all studied CS at New Mexico State University. There were three of us as SourceForge project admins: me, Cassandra Bayer (who went by Krach42 back then), and Eric Zeitler. Eric went by EBNF, a nickname he picked up in compilers class, after Extended Backus-Naur Form. Cassandra wrote most of the heavy infrastructure: the ACL system, the template parser, an entire inline documentation system she modeled after Unix man pages. Eric was prolific on the site itself, posting .plan entries and articles with the kind of energy that made the whole thing feel alive.
The three of us wrote the code, but the community around Signalnine was bigger than that. Several of us had come from volunteering at Linux.com, and Signalnine was partly a reaction to that experience. We wanted to build something like it but under our own control, run the way we thought a community site should be run. Terry Warner (keerf) hosted our CVS server at nuthouse.org and kept the infrastructure running. Darren Morrin, posting as truefluke, was the site's most prolific contributor. Ten of the fourteen articles on a typical front page were his. Tom D came over from Linux.com too. We had an IRC channel on EFNet, #signalnine, because that's what you did in 2002.
Eric passed away some years ago. Finding his posts preserved in the Wayback Machine archives, his .plan entries, his jokes about "confidential signalnine documents leaked," was not something I was prepared for when I started this project.
The live site was a Slashdot-style community portal. Not just a blog engine but a place with user registration, article submission, comment threads, polls, daily comics, and sidebar widgets you could minimize and rearrange. We had over a hundred registered users. People posted tech news, argued about Linux distributions, complained about phpBB security holes. The usual.
## What the Code Looks Like
It's PHP 4. Constructors are methods named after the class. Properties are declared with `var`. Sessions use `session_register()`, which was deprecated years ago and eventually removed entirely. There's a `get_magic_quotes_gpc()` call. A manual `srand()` with a comment that says "this srand is from richart@zend.com... trust the developers." It's a time capsule.
But underneath the period-specific PHP, the architecture is more thoughtful than I remembered.
The heart of the system is the "box" architecture. Everything on the page is a box: login forms, article lists, sidebars, Google search, the comment system. Each box is a self-contained `.box` file that gets loaded dynamically. Users could configure their own sidebar layout with a string like `left(login,google,whatis);bottom(comic)` stored in their profile. Boxes had minimize and close buttons, like desktop windows. This was years before WordPress widgets or iGoogle.
The database layer supported both MySQL and PostgreSQL through a hand-rolled abstraction with separate driver files. Queries used a builder pattern (`$query = new query("articles"); $query->Constrain("type=1"); $query->Limit(0, 10);`) which was pretty clean for 2002 PHP. Passwords used `crypt()` for cross-database compatibility, which turned out to be the right call.
The ACL system was genuinely sophisticated. Field-level permissions on database columns, with cascading rules from user to group to global. 43 ACL entries in the seed data. The permission type drove form rendering: a `theme` field automatically generated a dropdown of available themes, a `password` field rendered a password input. It was more granular than what most CMSes offer today.
## The Vision Document
The Wayback Machine preserved something I'd almost forgotten: a [design document](/archive/sig9/design.html) I wrote, hosted on our CVS server. It opened with "Sig9 Stuff. Yah bahbe." and was marked "Signalnine Confidential. Your eyes only." with a grin emoticon. It was not confidential.
The interesting part is the ambition. The document describes wanting to make the content exportable via XML so that independent sites running the same code could share articles with each other. A network of web-based BBSes, each with its own focus (one for open source, one for agriculture, whatever) federated through a common protocol. I was describing ActivityPub fifteen years before Mastodon existed.
We actually built part of it. The export system generated content with MD5 hashes for integrity verification, and the import system could pull articles from other instances. It was rudimentary, but the plumbing was there.
## What We Got Right, What We Didn't
The architecture was ahead of its time in some ways. Widget-based layouts. Database abstraction. Content federation. Full internationalization with gettext, including Japanese translations, which still surprises me. Output format switching between HTML 4.01 and XHTML 1.0.
What killed Signalnine wasn't the code. It was timing and focus. WordPress launched in May 2003 with a simpler pitch: install it, write posts, done. We were building a community platform with IRC integration and federated content sharing. We were overengineering exactly the way three CS students would overengineer a side project. The market wanted easy. We were building interesting.
## Looking Back
The Wayback Machine has 113 captures of signalnine.com between 2001 and 2025. The earliest is a "Coming Soon" page from April 1, 2001. We launched on April Fool's Day and adopted it as our anniversary, a convenient excuse to push code updates every year. The codebase went through four incarnations: a bare-bones preM1, then Milestone 1, 2, and 3, each a progressively more ambitious rewrite. Signalnine was also loosely associated with Starport, a sister site where the first M3 code went live. The November 2002 captures show the site at its peak: articles flowing in, polls running, users logged in. The query counter in the footer reads "23 SQL queries." We were proud of that number, though I'm not sure why.
Reading this code twenty-four years later is a strange experience. I can see the fingerprints of three people figuring things out in real time. Cassandra's careful documentation system sitting next to my quick-and-dirty article renderer. Eric's poll widget bolted onto the sidebar framework. The comment at the top of the config file that says `// EDIT ONLY IF YOU KNOW WHAT THE HELL YOU ARE DOING`. We didn't always know. We did it anyway.
The [code is on GitHub](https://github.com/mmichie/signalnine) if you want to look at it. It won't run without a time machine and a PHP 4 interpreter. But as a record of what three people thought the web should look like in 2002, before the platforms won and the blogosphere became five websites reposting each other, it's worth a read.
---
## Bootstrapping My Dotfiles
- URL: https://mattmichie.com/2026/02/17/bootstrapping-my-dotfiles/
- Date: 2026-02-17
- Categories: dotfiles, tooling
I've had a dotfiles repo since 2013. I got a new laptop, couldn't remember how I'd configured my shell, and decided to put everything in Git. The usual story.
Four hundred and eighty commits later, the repo manages my shell, editor, terminal, window manager, Git config, macOS defaults, and about 126 Homebrew packages. This week I finally rewrote the bootstrap process, so here's how the whole thing works.
## The Structure
The repo is organized by topic. Each directory maps to one tool: `zsh/` for my shell, `nvim/` for Neovim, `git/` for Git, `tmux/` for tmux. Twenty directories, each mirroring the structure of the home directory.
[GNU Stow](https://www.gnu.org/software/stow/) handles symlinks. It takes a directory like `git/` and creates symlinks from its contents into `$HOME`. `git/.gitconfig` becomes `~/.gitconfig`. `zsh/.zshrc` becomes `~/.zshrc`. No template engine, no runtime. Just symlinks pointing back into the repo.
The stow script is twelve directories in an array and a for loop:
```bash
stow_dirs=(
aerospace bin ghostty git karabiner
nvim osx ssh system tmux wezterm zsh
)
for dir in "${stow_dirs[@]}"; do
stow "$dir" -t ~
done
```
Some directories are deliberately left out. `bash/` is there for machines where I don't have zsh. `yabai/` is an older tiling window manager I replaced with AeroSpace. `vim/` is the pre-Neovim config. They're in the repo for reference but I don't symlink them anymore.
## The Old Bootstrap
For years, setting up a new Mac meant running a script called `install_dotfiles.sh` for the symlinks, then a separate `.brew` script that ran individual `brew install` commands with flags Homebrew deprecated years ago, then manually applying macOS defaults. Three scripts, right order, manual intervention.
The `.brew` script had enough bitrot that I couldn't run it without editing it first. Deprecated flags, packages that changed names, casks that moved taps. Every new machine was an archaeology exercise.
## The New Bootstrap
`bootstrap.sh` does everything: installs Xcode CLI Tools if missing, installs Homebrew if missing, runs `brew bundle` against a Brewfile, initializes git submodules, calls `stow.sh`, and optionally applies macOS defaults. One command from bare Mac to working environment.
`stow.sh` is the symlink-only script for when you've added a config file or changed the list. It doesn't touch packages.
The real improvement is the Brewfile. Instead of imperative `brew install` commands:
```ruby
brew "ripgrep"
brew "fd"
brew "fzf"
brew "zoxide"
cask "ghostty"
cask "docker-desktop"
```
`brew bundle` is idempotent. Run it on a fresh machine or one that already has half the packages and it does the right thing.
The Brewfile ended up at 345 lines organized into sections: core CLI, shell experience, editors, language toolchains for Go, Rust, Python, and Node, infrastructure, network, media, GUI apps, fonts. About half the lines are commented out. Packages I've used at some point but don't need everywhere. They're there so I remember they exist.
## Lazy Loading
I open new terminal windows constantly. A 500ms startup delay on every one adds up. The worst offenders are nvm (sources a massive shell script), pyenv (needs shims in PATH), and Google Cloud SDK (its own init process).
I defer all of them until first use:
```zsh
_lazy_load() {
local init_callback=$1
shift
local cmds=("$@")
for cmd in "${cmds[@]}"; do
eval "
$cmd() {
unset -f ${(j: :)cmds}
$init_callback
$cmd \"\$@\"
}
"
done
}
_lazy_load _init_nvm nvm node npm npx yarn
```
First time I type `node`, the wrapper initializes nvm, removes itself, and runs the real binary. Every call after that goes straight through. Same pattern for `gcloud`, `gsutil`, and anything else that's slow to init.
## PATH Management
PATH on macOS is a mess. `/usr/libexec/path_helper` runs early in shell startup and builds a PATH from `/etc/paths` and `/etc/paths.d/*`. Then Homebrew wants its prefix at the front. Then language version managers want their shims at the front. Then your personal scripts should probably be at the front too.
I wrote a priority-based path manager. Groups: user scripts at 1, language toolchains at 2, dev tools at 3, system paths at 4, OS defaults at 5. Each module registers its paths, and `path_build` sorts by priority and deduplicates.
```zsh
path_add --user "$HOME/bin" "$HOME/.local/bin"
path_add --language "${GOBIN:-$HOME/workspace/go/bin}" "$HOME/.cargo/bin"
path_add --tools "$brew_prefix/bin" "$brew_prefix/sbin"
path_add_system # preserve existing paths from path_helper
path_build
```
More machinery than most people need. But I never have to think about the order of my `.zshrc` or worry about a tool being shadowed by a system binary.
## The Rest of It
`aerospace/` configures my tiling window manager in a DWM-style master-stack layout. `karabiner/` remaps my keyboard. `osx/.osx` sets about a hundred macOS defaults: key repeat speed, Finder behavior, Dock placement. `git/.gitconfig` has a decade of aliases and GPG signing through 1Password.
`bin/` has personal scripts and pre-compiled binaries with platform variants for macOS and Linux. There's a wifi geolocation tool I wrote in Go and various shell utilities I've accumulated.
tmux has its own plugin ecosystem through git submodules: tpm for plugin management, resurrect for session persistence, continuum for automatic saves. The layout is DWM-inspired, matching how I think about window management.
## Why Bother
I've set up enough machines to know the pain of doing it manually. Consulting means regular rotations between client machines and personal machines. A one-command setup saves real time.
But honestly I just like having a system. Every tool has a place, every config is version-controlled. Change a setting, commit it. Something breaks, bisect it. Try a new tool and don't like it, revert. Thirteen years of shell configuration, all diffable.
The bootstrap rewrite was overdue. The old setup worked but required institutional knowledge I kept in my head. The new version is something I could hand someone and say "clone this, run `bootstrap.sh`" without caveats.
**Update:** I've since [migrated the whole setup to Nix](../nixifying-my-dotfiles/). nix-darwin and home-manager replace the Brewfile, stow, and the macOS defaults script. The bootstrap is now `just switch` on either macOS or Linux.
---
## Migrating from Powerline-Go to Starship
- URL: https://mattmichie.com/2026/02/14/migrating-from-powerline-go-to-starship/
- Date: 2026-02-14
- Categories: linux, terminal
I've been using [powerline-go](https://github.com/justjanne/powerline-go) as my shell prompt for years. It's a Go binary that renders a nice powerline-style prompt with segments for username, hostname, current directory, git status, and more. It works great, but I've been on a bit of a dotfiles cleanup kick and wanted to see if [Starship](https://starship.rs/) could replace it.
Starship is a Rust-based prompt that's become the de facto standard. It's fast, cross-shell, and highly configurable through a single TOML file. The question was whether I could make it look identical to my powerline-go setup.
## The Easy Part
Getting a basic Starship config that roughly matches powerline-go is straightforward. Starship has built-in modules for everything powerline-go shows: username, hostname, directory, git branch, git status. You can set background and foreground colors using 256-color codes, and the powerline arrow characters work in format strings.
```toml
[username]
show_always = true
style_user = "bg:240 fg:250"
format = "[ $user ]($style)"
```
Within an hour I had something that looked close. The colors matched, the segments were in the right order, and the basic git info was there.
## The Hard Part
The devil is in the details. Powerline-go does several things that Starship's built-in modules can't replicate:
**Path rendering.** Powerline-go splits the current directory into segments. The first component (usually `~`) gets a blue background, while the remaining directories get a darker grey background with thin powerline separators between them. Starship's `[directory]` module renders the whole path as one block. There's no option to split it up or use different colors for different components.
**Git status segments.** In powerline-go, each git status type gets its own colored segment with proper powerline arrows between them: staged files on dark green (bg:22), modified on orange (bg:130), untracked on dark red (bg:52), conflicted on bright red (bg:9), stashed on dark blue (bg:20). The arrows transition smoothly from one color to the next. Starship's `[git_status]` module renders everything in one block. I tried using separate background colors per indicator, but the arrows between segments created ugly color artifacts since Starship doesn't know which segments will be present at render time.
**Clean vs dirty branch.** Powerline-go shows the branch name on a green background when the repo is clean and pink when it's dirty. Starship's `[git_branch]` module doesn't have this concept.
## Custom Scripts to the Rescue
The solution was to replace Starship's built-in modules with custom shell scripts that output raw ANSI escape codes. Starship's `[custom]` modules let you run a command and insert its output into the prompt. If you set `format = "$output"`, the raw terminal escape codes pass straight through.
I wrote two scripts:
**`path.sh`** handles the directory display. It splits `$PWD` into components, shows the first on blue, transitions with a powerline arrow to grey, then renders the remaining components with thin separators between them.
**`gitstatus.sh`** handles the entire git display. It runs `git status --porcelain=v2 --branch` to get branch info, ahead/behind counts, and file status in a single command. Then it builds the output with proper ANSI-coded colored segments and powerline arrows that transition correctly from one color to the next. Since the script knows which segments are present, it can calculate the arrow colors dynamically. Something Starship's static format strings can't do.
The clean/dirty branch coloring was the easiest part of the script. Just check if any counters are non-zero and pick green (bg:148) or pink (bg:161).
## UTF-8 Gotcha
One thing that tripped me up: getting the powerline arrow character (U+E0B0) right in bash. I initially used `$'\xee\x80\xb0'` which seemed correct but rendered as diamonds. Turns out the proper UTF-8 encoding for U+E0B0 is `\xee\x82\xb0`, not `\xee\x80\xb0`. The middle byte is `0x82`. I only caught this by hex-dumping Starship's own output and comparing it byte-for-byte with my script's output.
## Performance
The whole point of switching was to modernize, so I wanted to make sure I wasn't paying a performance penalty. Here's the initial benchmark with bash scripts:
| Prompt | Median |
|---|---|
| powerline-go | 58ms |
| starship + bash scripts | 59ms |
Essentially identical. The bash scripts add overhead compared to Starship's built-in Rust modules (which clock in around 13ms), but the result is on par with the Go binary it replaces. Most of the time is spent spawning bash and running `git status`.
## Going Further: Rewriting in Rust
The bash scripts worked, but I couldn't stop thinking about the overhead. Each prompt render spawns bash processes and shells out to git. What if the custom scripts were a compiled Rust binary using [libgit2](https://libgit2.org/) instead?
I wrote a small Rust binary called `starship-segments` with subcommands for each segment type: `path`, `git`, and `tmux-title`. The path command is just string manipulation. The git command uses the `git2` crate to read repository state directly through libgit2, avoiding all subprocess overhead. No `git status`, no `git branch`, no `git stash list`. Just library calls.
The result:
| Prompt | Median |
|---|---|
| starship + Rust binary | **36ms** |
| starship + bash scripts | 59ms |
| powerline-go | 58ms |
**36 milliseconds.** About 40% faster than both the bash version and powerline-go. (Later I shaved another ~6ms off by eliminating redundant `git rev-parse` subprocess spawns from the Starship config — see below.) The Rust git subcommand alone runs in 25ms compared to 52ms for the bash script. Eliminating subprocess spawning and using libgit2 directly makes a real difference.
The binary is about 2MB after LTO and strip. Not nothing, but it's a static binary with libgit2 linked in. It lives alongside the starship config and gets symlinked into place by stow.
## Bonus: Faster Tmux Window Titles
Once the Rust binary existed, I realized I had the same subprocess problem elsewhere. My tmux setup automatically sets window titles based on the current directory: a house emoji for home, a folder emoji for regular directories, and a git branch icon with the repo name and branch for git repos. The shell hook that generates these titles was spawning four git subprocesses on every prompt: `git rev-parse --git-dir`, `git branch --show-current`, `git rev-parse --show-toplevel`, and `git status --porcelain`. That's 30-60ms of overhead every time you hit enter.
Since `starship-segments` already had all the git machinery via libgit2, I added a `tmux-title` subcommand. It outputs tmux-formatted strings directly: `#[fg=colour39]` for a cyan branch icon on clean repos, `#[fg=colour67]` for muted blue on dirty ones, with a pencil indicator for uncommitted changes. The entire shell function went from 25 lines of git commands to a single binary call with a fallback.
## Squeezing Out the Last Milliseconds
Even after the Rust rewrite, I noticed two remaining `git rev-parse` subprocesses hiding in the Starship config. The `custom.gitstatus` module had `when = "git rev-parse --is-inside-work-tree"` and `custom.dir_end` (which renders the closing arrow outside git repos) had the negated version. Both fire on every prompt, each costing ~3ms.
The fix was simple: since the Rust binary already calls `Repository::discover()` via libgit2, I made it output the closing arrow itself when it's not in a repo. Now `gitstatus` runs unconditionally with `when = "true"` and `dir_end` is gone entirely. That's **~6ms saved per prompt** with zero visual change.
While I was at it, I applied the same caching pattern to two shell startup costs. Both `atuin init zsh` (~3.4ms) and `vivid generate` (~1.4ms) produce static output that only changes when the binary is updated, so I cache their output to `~/.cache/zsh/` and regenerate only when the binary is newer than the cache file:
```zsh
if command -v atuin >/dev/null 2>&1; then
local cache="$SHELL_CACHE_DIR/atuin-init.zsh"
local atuin_bin="${commands[atuin]}"
if [[ ! -f "$cache" || "$atuin_bin" -nt "$cache" ]]; then
atuin init zsh --disable-up-arrow --disable-ctrl-r > "$cache"
fi
source "$cache"
fi
```
The cached reads come in at ~0.3ms, saving about **4ms total on shell startup**.
## Was It Worth It
Honestly, the built-in Starship config with some compromises would have been fine for most people. But I wanted an exact visual match to powerline-go, and the custom approach got me there. Then the Rust rewrite made it faster than the original.
The config and source are in my [dotfiles](https://github.com/mmichie/dotfiles/tree/master/starship) if anyone wants to take a look.
The real win is that Starship is actively maintained, works across shells, and the TOML config is a lot easier to reason about than the powerline-go command line flags I had scattered across my zshrc. And now it's faster too.
---
## Nixifying My Dotfiles
- URL: https://mattmichie.com/2026/02/14/nixifying-my-dotfiles/
- Date: 2026-02-14
- Categories: dotfiles, nix, tooling
I wrote about [bootstrapping my dotfiles](../bootstrapping-my-dotfiles/) a few days ago. Homebrew, GNU Stow, a bootstrap script. It works on my Mac. The problem is I also use Linux, and the Brewfile is worthless there. Every time I SSH into a Linux box I end up cloning the repo, running `stow.sh` for the configs, and then installing packages by hand for twenty minutes. Same tools, different package managers, nothing shared.
I'd been putting off trying Nix because it looked like a lot of ceremony for what is fundamentally `brew install` plus symlinks. But the cross-platform thing kept nagging at me, so I made a branch and started experimenting.
## The Stack
nix-darwin handles system-level macOS configuration: defaults, Homebrew casks, system packages. home-manager handles user-level everything: packages, dotfile symlinks, shell setup. Both are configured through Nix's functional language and the whole thing is pinned with a flake.
On macOS, `darwin-rebuild switch` applies the entire stack. On Linux, `home-manager switch` handles the user side. Same repo, same package list.
## Restructuring
The old repo had one directory per tool in stow's expected layout: `zsh/.zshrc`, `nvim/.config/nvim/init.lua`, `git/.gitconfig`. Stow would symlink each directory's contents into `$HOME`.
I moved everything into a `configs/` directory and let home-manager handle the symlinks with `mkOutOfStoreSymlink`:
```nix
home.file.".zshrc".source =
config.lib.file.mkOutOfStoreSymlink "${dotfiles}/zsh/.zshrc";
```
`mkOutOfStoreSymlink` is important. Without it, Nix copies files into `/nix/store/` and the symlink points there, read-only. With it, the symlink points back to the git working tree, so I can edit configs and see changes immediately. Same behavior as stow.
## Packages
The 345-line Brewfile became a home-manager module. All CLI tools go in one list:
```nix
home.packages = with pkgs; [
ripgrep sd fd fzf zoxide
eza bat dust duf procs
xh delta difftastic hexyl
starship atuin vivid gum
hyperfine just watchexec tealdeer tokei
shellcheck neovim tmux
];
```
Plus another 80 or so for Go, Rust, Python toolchains, infrastructure tools, network utilities, media processing. Everything was in nixpkgs. Two packages had different names: `git-delta` is `delta` in nixpkgs, and `dust` is `du-dust`. Everything else matched.
GUI apps can't come from Nix on macOS because `.app` bundles don't work well in the Nix store. nix-darwin has a Homebrew integration module that manages casks declaratively:
```nix
homebrew = {
enable = true;
onActivation.cleanup = "zap";
casks = [
"ghostty" "wezterm" "google-chrome"
"docker-desktop" "slack" "1password"
"aerospace" "spotify" "vlc"
];
};
```
`cleanup = "zap"` removes any cask that isn't in the list. So if I install something to try it and don't add it here, it gets cleaned up on the next rebuild. The cask list becomes the source of truth instead of whatever accumulates on the machine over time.
## macOS Defaults
The `osx/.osx` script was 165 lines of `defaults write` commands. nix-darwin replaces it with typed options:
```nix
system.defaults.dock = {
tilesize = 57;
autohide = true;
autohide-delay = 1000.0;
mru-spaces = false;
};
```
These get applied on every `darwin-rebuild switch`. If a macOS update resets something, the next rebuild puts it back. I don't have to remember to re-run a script.
## The Rust Binary
My custom `starship-segments` binary was previously compiled locally with the Homebrew-provided libgit2 and the resulting binary committed to the repo. With Nix, [Crane](https://github.com/ipetkov/crane) builds it as a proper derivation:
```nix
starshipSegmentsFor = system:
let
craneLib = crane.mkLib nixpkgs.legacyPackages.${system};
in
craneLib.buildPackage {
src = craneLib.cleanCargoSource ./starship-segments;
strictDeps = true;
buildInputs = pkgs.lib.optionals pkgs.stdenv.isDarwin [
pkgs.apple-sdk_15 pkgs.libiconv
];
};
```
This actually caught a real problem. The old binary linked against `/opt/homebrew/opt/libgit2/lib/libgit2.1.9.dylib`. When I removed Homebrew packages in favor of Nix, that library vanished and Ghostty wouldn't even open because the tmux launch script called `starship-segments` during prompt setup. dyld error, immediate crash. The Nix-built version pins its own libgit2 in the store, so the dependency is always satisfied.
Crane also handles cross-platform automatically. The flake defines the build for `aarch64-darwin` and `x86_64-linux`, so the binary gets compiled for whatever system you're on.
## The Flake
The `flake.nix` defines two entry points:
```nix
darwinConfigurations."mims-mbp" = nix-darwin.lib.darwinSystem { ... };
homeConfigurations."mim@linux" = home-manager.lib.homeManagerConfiguration { ... };
```
Both import the same shared modules. The darwin config adds system defaults and Homebrew casks. The linux config just sets the home directory. A `justfile` wraps the platform detection:
```bash
# Apply everything — auto-detects macOS vs Linux
just switch
```
Bootstrap on a new machine is three commands:
```bash
curl -sSf -L https://install.determinate.systems/nix | sh -s -- install
git clone https://github.com/mmichie/dotfiles ~/src/dotfiles
cd ~/src/dotfiles && just switch
```
## What Broke
Two things, both the same pattern: hardcoded Homebrew paths.
My Ghostty launch command runs `~/bin/tmux-attach-or-new`, which had `TMUX=/opt/homebrew/bin/tmux` on line 3. tmux was now in `/etc/profiles/per-user/mim/bin/tmux` courtesy of Nix. Ghostty showed a "failed to launch" error and wouldn't open at all. Fix: use `command -v tmux` instead.
The starship config had `command = "~/.config/starship/starship-segments git"`, pointing to the old stow'd binary. The Nix-built binary was on PATH but at a different location. Fix: change it to just `command = "starship-segments git"`.
Both were five-minute fixes, but the first one locked me out of my terminal until I figured it out.
## Where It Stands
The experiment is on a [nix branch](https://github.com/mmichie/dotfiles/tree/nix). I've been running it on my Mac and everything works: prompt, tmux, all 120+ CLI tools, macOS defaults, casks. `nix flake check` passes.
The real test is the next time I set up a Linux box. If `home-manager switch --flake .#mim@linux` gives me my full shell environment in one command, I'll merge the branch. That's the whole reason I did this.
The Nix language took some getting used to. It's functional, it's lazy, and the error messages are occasionally unhelpful. I spent more time reading documentation than writing configuration. But the old setup was four scripts run in the right order on the right platform. The new setup is `just switch` on either.
---
## Ditching Dropbox for S3
- URL: https://mattmichie.com/2026/02/12/ditching-dropbox-for-s3/
- Date: 2026-02-12
- Categories: infrastructure, tooling
I've been paying Dropbox $132 a year for personal file storage. Most of what's in there I haven't touched in years: photo backups, old project files, a Google Takeout export, some music, a copy of my Twitter archive, and the general accumulation of a decade of digital life. Two hundred and ten gigabytes of stuff I want to keep but rarely need to access.
That's an expensive filing cabinet.
## The Math
S3 Infrequent Access costs $0.0125 per gigabyte per month. For 210 GB, that's $2.63 a month, or $31.50 a year. Glacier Deep Archive for a cold backup of the same data costs $0.00099 per gigabyte, or $2.49 a year. Combined that's $34 a year. Dropbox was costing me $132. That's nearly a hundred dollars a year I was spending on inertia.
The tradeoff is real: Dropbox has a nice desktop app, file sharing, and a web interface. S3 has none of that. But for an archive of files I open maybe twice a year, I don't need any of that. I need cheap, durable storage with a CLI. S3 is exactly that.
## The Migration
The tool is [rclone](https://rclone.org/). It supports both Dropbox and S3 as backends, handles OAuth for Dropbox, and can copy between cloud providers without needing enough local disk to stage the entire transfer. You configure two remotes and tell it to copy from one to the other. If you'd rather not deal with a CLI, services like [Movebot](https://www.movebot.io/) do the same thing for a one-time fee, but rclone is free and does the job fine.
Setting up the Dropbox remote is an OAuth flow in the browser. Setting up S3 is a config block pointing at your AWS credentials. The copy command is one line:
```bash
rclone copy dropbox: s3:my-archive-bucket/ \
--s3-storage-class STANDARD_IA \
--progress \
--transfers 8
```
The data streams through your local machine on the way from Dropbox to S3. There's no direct server-to-server path between them. For 210 GB that took a few hours overnight. If it gets interrupted, you re-run the same command and it picks up where it left off, skipping files that already exist at the destination.
One gotcha: if you use 1Password's `credential_process` for AWS authentication (which I do), rclone won't pick that up through its `env_auth` setting. You need to export the credentials as environment variables before running the copy:
```bash
export AWS_ACCESS_KEY_ID=$(op read "op://Private/your-vault/access_key_id")
export AWS_SECRET_ACCESS_KEY=$(op read "op://Private/your-vault/secret_access_key")
```
After the copy finished, I ran `rclone check` to verify every file. Twenty-eight thousand four hundred and one files, zero differences.
## Organizing the Mess
A raw Dropbox dump is not a filing system. My top-level directory structure included gems like `2019-12-08 Random`, `nope`, a folder named after what turned out to be my Twitter user ID, and the inevitable `Camera Uploads 2`. A decade of "I'll organize this later" made manifest.
I created a second S3 bucket with a clean folder structure and used rclone to copy everything into it. Since both buckets are in the same AWS region, this is a server-side copy. The data never leaves S3, and 210 GB reorganizes in minutes.
The new structure:
```
photos/ - Camera uploads, events, iPhoto, Flickr, screenshots
documents/ - Docs, paperwork, books
media/ - Video, audio, music, games
exports/ - Google Takeout, Facebook, Twitter archive
backups/ - System backups, legacy 1Password vaults
security/ - Keys, GPG
projects/ - Old code, side projects, work repos
```
The original Dropbox dump goes to Glacier Deep Archive for long-term cold storage at $0.21 a month. The organized copy stays on S3 Infrequent Access for the rare occasions I need to find something.
## The Numbers
| | Monthly | Annual |
|---|---|---|
| Dropbox Plus | $11.00 | $132.00 |
| S3-IA (organized, 210 GB) | $2.63 | $31.50 |
| Glacier Deep Archive (raw backup, 210 GB) | $0.21 | $2.49 |
| **S3 total** | **$2.84** | **$33.99** |
| **Savings** | | **$98.01/yr** |
A hundred dollars a year isn't life-changing money. But it's a hundred dollars a year I was paying for a service whose only remaining value to me was "my files are already there." That's not a feature. That's inertia.
## Is This for Everyone
No. If you use Dropbox for file sharing, collaboration, or syncing across devices, S3 is not a replacement. If you want a web interface for browsing your files, S3's console is functional but not pleasant. If you want to access files from your phone, you'll need a third-party app.
But if you're like me and your Dropbox has quietly become a $132-a-year archive of files you never open, rclone and S3 will do the same job for the cost of a coffee.
---
## Simulating Blackjack the Hard Way
- URL: https://mattmichie.com/2026/02/12/simulating-blackjack-the-hard-way/
- Date: 2026-02-12
- Categories: python, programming, side-projects
I built a blackjack simulator. That sentence undersells it. What I actually built is a 28,000-line Python framework for simulating card games with an event-driven architecture, immutable state management, and realistic shuffle physics. For blackjack.
This is what happens when a software engineer gets curious about casino math.
## The Itch
It started the way these things always start: I wanted to understand the numbers. Not the hand-wavy "the house has a 0.5% edge" stuff you read online, but the actual mechanics. How does basic strategy change when the dealer hits soft 17? What does card counting really buy you? How many riffle shuffles does it take before a deck is actually random?
I could have read a book. Instead I wrote a simulator. Then I rewrote it. Then I rewrote it again.
## Getting the Simulation Right
The first rule I set for myself was no shortcuts. If you're simulating blackjack to understand blackjack, you can't approximate the parts you find inconvenient. Every card comes from a shoe. Every shuffle follows real physics. Every hand resolves by the actual casino rules: splits, doubles, surrender, insurance, the whole mess.
The shuffle simulation is where things got interesting. A perfect Fisher-Yates shuffle is trivial to implement, and it produces a uniformly random deck. But casino dealers don't perform perfect shuffles. They do riffle shuffles, and the mathematics of imperfect riffles are well-studied. It takes about seven riffle shuffles to adequately randomize a deck. Fewer than that and there's exploitable structure left in the card order. I implemented three shuffle types with configurable fidelity so I could study exactly how much information survives an imperfect shuffle.
Card counting was the other rabbit hole. The basic Hi-Lo system is straightforward: low cards add one, high cards subtract one, divide by decks remaining. But professional play deviations are where it gets complicated. The correct play changes based on the true count. Sometimes you should hit a 16 against a dealer 10. Sometimes you shouldn't. The threshold depends on how deep you are into the shoe.
I implemented all of this because I wanted the numbers to be right.
## The Architecture Obsession
The simulation code worked fine as a monolith. I could run thousands of hands and get statistically valid results. But I kept looking at the code and seeing things I wanted to fix.
The game logic was tangled up with the I/O. Strategy decisions were coupled to hand resolution. State was mutable and scattered across half a dozen objects. It worked, but it was the kind of code that made me uneasy. The kind where adding a new feature meant understanding every other feature first.
So I did a four-phase rewrite. Event-driven architecture, immutable state with frozen dataclasses, platform adapters to decouple the engine from any specific interface, and async support throughout. The kind of engineering that is completely unjustifiable for a side project and completely satisfying to build.
The core insight was treating every state change as an event. A card is dealt: that's an event. A player hits: event. The dealer reveals their hole card: event. This makes the game engine a pure state machine. Feed it actions, get back new states. No side effects, no hidden mutations, easy to test, easy to verify.
It also means you can record an entire game as a sequence of events and replay it later. When my simulation produced a result that looked wrong, I could step through every decision and see exactly where the math diverged from my expectations. Usually the math was right and my expectations were wrong.
## What 350,000 Hands Per Second Tells You
At this point the simulator can run about 350,000 games per second. That's enough to get statistically meaningful results on almost any question you want to ask.
Some things I've confirmed that you probably already knew: basic strategy works. Card counting works, barely, under ideal conditions. The Martingale betting system is a reliable way to go broke slowly.
Some things that surprised me: the variance in blackjack is brutal. You can play perfect basic strategy and lose for hours. The math says you'll come out slightly ahead over thousands of hands, but "slightly" is doing a lot of heavy lifting in that sentence. I have a much better intuition now for why card counting requires both a large bankroll and an iron stomach.
## Why Build This
People build side projects for different reasons. Some want to ship a product. Some want to learn a technology. I wanted to understand a system, and building a simulation was the most thorough way I knew to do it.
The architecture work was its own reward. Not because anyone will ever need an event-driven blackjack engine with immutable state management, but because the patterns transfer. The same separation of concerns that makes a card game testable makes a distributed system debuggable. The same event-driven approach that lets me replay a hand of blackjack is the same approach that lets you replay a production incident.
The code is on [GitHub](https://github.com/mmichie/cardsharp) if you want to look at it. Fair warning: it's a side project that kept growing. Twenty-eight thousand lines of Python for a card game. Some projects are just like that.
---
## Timezone Bugs in a Static Site
- URL: https://mattmichie.com/2026/02/10/timezone-bugs-in-a-static-site/
- Date: 2026-02-10
- Categories: web development, astro
A week after migrating this site to Astro, I clicked an old link and got an S3 XML error. The URL was `/2016/11/06/ditched-blogofile-for-hugo/`. The post existed. The content was there. But Astro had built it at `/2016/11/07/ditched-blogofile-for-hugo/`. One day off.
It took me a minute to understand what happened. Then I checked the frontmatter:
```
date: 2016-11-06T21:49:37-08:00
```
November 6th, 9:49 PM Pacific. But in UTC, that's November 7th, 5:49 AM. And JavaScript's `Date.getUTCDate()` returns 7.
## How Hugo Does Dates
Hugo is written in Go, and Go's `time.Time` preserves the original timezone from the parsed string. When Hugo's permalink template says `/:year/:month/:day/:title/`, it uses the date as written. November 6th at 9 PM Pacific is November 6th. The timezone offset is metadata, not a conversion trigger.
JavaScript doesn't work this way. When you create a `Date` from an ISO string, it converts everything to UTC internally. The original timezone is discarded. If you want the year, month, and day, you have to choose: `getFullYear()` gives you the date in the runtime's local timezone, and `getUTCFullYear()` gives you UTC. Neither gives you the date as the author wrote it.
My Astro code was using the UTC methods, which seemed like the safe choice. Timezone-independent. Deterministic. Wrong.
## 43 Out of 152
I wrote a script to check every post. Forty-three of my 152 blog posts were written late enough in the evening Pacific time to roll over to the next day in UTC. Every single one of those posts had a different URL than what Hugo had generated. Twenty years of links, all quietly broken.
The irony of getting bitten by a timezone bug on a static site with no server, no database, and no user input is not lost on me.
## The Fix
The solution is almost embarrassingly simple. Don't use the `Date` object for URL generation at all. Instead, read the raw frontmatter string and parse the date components directly:
```typescript
// src/utils/dates.ts
const content = readFileSync(filePath, 'utf8');
const match = content.match(/^date:\s*["']?(\d{4})-(\d{2})-(\d{2})/m);
```
The date `2016-11-06T21:49:37-08:00` starts with `2016-11-06`. That's the date the author intended. No timezone conversion, no UTC normalization, no surprises. It matches what Hugo did, and it matches what a human reading the frontmatter would expect.
Astro's YAML parser converts date strings to JavaScript `Date` objects before your code ever sees them, so the raw string is gone by the time you're building URLs. The utility reads the markdown files directly at build time, parses the date from the raw text, and caches the results. It's a workaround for a leaky abstraction, but it's a correct workaround.
## Lessons, If You Want Them
The real lesson is one I already knew and ignored: timezone handling is where confident assumptions go to die. I chose `getUTCDate()` because it felt rigorous. UTC is the canonical timezone. UTC is deterministic. UTC is also not what Hugo used, and URL compatibility was the entire point of the migration.
The secondary lesson is that date types that discard timezone information are dangerous. JavaScript's `Date` stores an instant in time, not a calendar date. Those are different things. "November 6th in Pacific time" is a calendar date. "2016-11-07T05:49:37Z" is an instant. If you need the calendar date, don't round-trip through an instant.
The third lesson is to click your own links after a migration. I should have caught this a week ago.
---
## Reconstructing a 1990s DOS Game from Binary
- URL: https://mattmichie.com/2026/02/05/reconstructing-a-dos-game-from-binary/
- Date: 2026-02-05
- Categories: reverse-engineering, programming, nostalgia
I've been spending my evenings reverse-engineering a DOS game from the mid-90s. Not playing it. Reconstructing it. Taking a compiled executable and working backward to understand how it worked, then rewriting it from scratch.
The game itself isn't important for this story. It was a multiplayer thing, text-based, the kind of game you played over modems when that was still novel. I spent a lot of hours on it as a kid. The original source code is long gone, if it ever existed outside the developer's hard drive. What remains is a 400KB executable compiled with Delphi 4 and a set of binary data files.
## Reading Dead Code
The main tool is Ghidra, the NSA's reverse engineering framework that they open-sourced a few years back. You load the executable, tell it the architecture (32-bit x86), and it starts disassembling. What you get is a mess of assembly language, function calls to addresses instead of names, and a lot of patience required.
The first task is finding the data structures. This game stores everything in fixed-size binary records written directly to disk. No headers, no metadata, no format versioning. Just raw structs, one after another. If you don't know the exact size of each record type, you can't read the files.
I found the sizes by looking for file I/O calls in the disassembly, then tracing back to see what buffer sizes were being allocated. Cross-referencing with the actual file sizes on disk and dividing by the number of expected entries confirmed it. One record type had a padding byte I didn't expect. That took two days to find.
## Matching Behavior
Knowing the structures isn't enough. You need to understand the logic. How does the game calculate prices? How does combat resolve? What algorithm generates the game world?
My approach: run the original in DOSBox, poke at it, record the outputs. Then find the corresponding code in Ghidra, understand what it's doing, reimplement it, and compare. When the outputs match exactly, I know I've got it right.
The economic simulation was the most interesting puzzle. There's a negotiation system with rules I never noticed as a player. Thresholds that change how the game responds to your offers. Price curves that depend on supply levels in non-obvious ways. Someone designed this carefully, and the elegance only becomes visible when you're reading the actual math.
Combat was trickier because it involves randomness. The game uses a probability system where outcomes depend on ratios stored in the data files. But one entity type had a hidden modifier that wasn't stored with the rest of its stats. It was a flag bit in a completely different field. I only found it because my implementation gave different results than the original, and I kept digging until I understood why.
## Why This Matters (To Me)
Reverse engineering is tedious. You're reading assembly for functions that do boring things like "copy a string" or "increment a counter." You're wrong constantly. You misread a jump condition, miss a side effect, assume a variable is signed when it's unsigned. Progress is slow.
But every solved puzzle is satisfying in a way that's hard to explain. You're not just learning what the code does. You're learning what the original developer was thinking. Their constraints. Their shortcuts. Their clever tricks. It's a conversation across decades, conducted entirely in machine code.
I'm not releasing this project. The IP is still active, still licensed, still someone's livelihood. This is purely personal, a thing I'm doing because twelve-year-old me would have thought it was magic, and because forty-year-old me finally has the skills to pull it off.
Some projects are just for you.
---
## 25 Years of Writing About Tech
- URL: https://mattmichie.com/2026/02/04/25-years-of-writing-about-tech/
- Date: 2026-02-04
- Categories: personal, writing
Recently I migrated 44 articles I wrote for Linux.com between 1999 and 2002 to this site's archive. Reading through them was like opening a time capsule from a version of myself I barely recognize.
## The Beginning
My first published article was "Microsoft and the Art of War" on July 6, 1999. I was 20 years old, a computer science student at New Mexico State University, and absolutely convinced that Linux was going to change everything. Looking at that piece now, what strikes me is the ambition of it all. I was analyzing Microsoft's competitive strategy through the lens of Sun Tzu, predicting they might release "MS BSD" (they didn't), and signing off as a "struggling computer science student" who was "highly anticipating all the flames on his poor grammar."
The flames did come. When I wrote a series about trying BSD, the Slashdot commenters let me know I wasn't qualified to have opinions about their operating system. One commenter had been using BSD since 1982. I'd been playing with He-Man and G.I. Joe in 1982.
## What I Got Wrong
I made some bold predictions in those early pieces. In "The Twisted Pair: Netscape and Linux," I warned that Linux companies could suffer Netscape's fate if they underestimated Microsoft. I was right about the danger of complacency, but I completely missed that the real threat to those Linux companies wouldn't be Microsoft at all. It would be commoditization, venture capital hype cycles, and the shift to cloud computing.
In "Don't Call It a Comeback," I speculated that Microsoft was deliberately sandbagging their antitrust defense because they'd already shifted focus to controlling internet infrastructure. This was giving Microsoft way too much strategic credit. The reality was messier: internal politics, genuine legal missteps, and the chaos of any large organization trying to navigate change.
I was certain that desktop Linux was just around the corner once we solved the "big four" applications: office productivity, games, financial software, and internet tools. We did eventually get all of those. And desktop Linux market share is still in the single digits, twenty-five years later. The lesson: solving the technical problems doesn't automatically solve the adoption problems.
## What I Got Right
Some things landed closer to the mark. I wrote about the importance of welcoming new users rather than hazing them with RTFM culture. That tension between accessibility and gatekeeping continues to play out in every technical community. I argued that Linux's diversity and multiple companies was a strength, not a weakness. The ecosystem did survive the dot-com crash, the death of VA Linux's hardware business, and countless distribution shake-ups.
My piece about OpenBSD praised their daily security reports that showed file permission changes and config diffs. I said I needed that functionality on my Linux servers. Today that's table stakes for any serious infrastructure: file integrity monitoring, configuration drift detection, audit logging. The security-conscious philosophy I admired in OpenBSD became standard practice.
## The Writer I Was
Reading those articles, I notice stylistic tics I've since outgrown. The military metaphors were relentless: "opening skirmishes," "master stroke," "counter-offensive." Every analysis was framed as warfare. I quoted Sun Tzu in my first article and kept reaching for combat language throughout.
I was also remarkably willing to speculate beyond my expertise. At 20, I wrote confidently about corporate strategy, market dynamics, and technological trajectories. Some of that confidence was necessary to get published at all. But there's a lot of "should" and "must" in those pieces that makes me wince now. I didn't know what I didn't know.
The fiction pieces surprise me most. I'd forgotten I wrote short stories for Linux.com. "Obsession" is about a programmer so consumed by his encryption project that he loses his girlfriend. The themes are classic: technology versus human connection, idealism versus practical life, the seductive pull of meaningful work. The execution is earnest and clumsy and very 1999.
## What Changed
Over the years, my writing shifted. The Linux.com articles evolved from fiery opinion pieces to more measured analysis, then to technical tutorials and event reporting. The author bios changed too: from "struggling computer science student" and "Linux Guru wannabe" to simply "exists in the New Mexican desert."
That desert reference was accurate. I was young, isolated, trying to connect with a global community through dial-up internet and mailing lists. Writing was how I participated. Getting published on Linux.com felt like being granted entry to a conversation that mattered.
Twenty-five years later, I've worked at Amazon, AWS, Uber, Twitter, and Meta. I've seen the infrastructure that makes the modern internet possible. The scale would have been incomprehensible to the version of me who was excited about 50% web server market share.
## Why Archive These
I could have left these articles in the Wayback Machine, where I found them. The original Linux.com site is long gone, and most of these pieces exist only because someone thought to archive that corner of the internet before it disappeared.
But they're part of my history. The person who wrote "Microsoft and the Art of War" became the person who eventually worked on the systems he was writing about. There's a direct line from being a twenty-year-old who cared intensely about free software to spending a career building and maintaining distributed systems.
The predictions were often wrong. The analysis was sometimes naive. The metaphors were overwrought. But the enthusiasm was genuine, and the community those articles connected me to shaped the rest of my career.
If you're twenty years old and writing things on the internet that seem important, keep going. You'll look back in twenty-five years and cringe at some of it. But you'll also see how those ideas, even the wrong ones, helped you figure out what you actually believed.
---
## Transitioning to Astro
- URL: https://mattmichie.com/2026/02/03/transitioning-to-astro/
- Date: 2026-02-03
- Categories: astro, web development
Right on schedule, another platform transition post. It's been about ten years since I moved from Blogofile to Hugo, and twenty years since this blog started on WordPress. At this rate, I'll be writing about whatever comes after Astro sometime around 2036.
Hugo served me well. It's fast, it's simple, and it just works. But I wanted something with a bit more flexibility for the homepage, and I'd been hearing good things about Astro from the React/frontend crowd. The pitch is compelling: ship zero JavaScript by default, but use whatever framework you want when you need interactivity.
The migration was surprisingly painless. All 144 posts came over with their frontmatter intact. The only real work was building out the new layouts and getting the date-based URLs to match the old format. Astro's content collections made the blog setup trivial:
```typescript
const posts = await getCollection('blog');
return posts.map((post) => {
const date = post.data.date;
return {
params: {
slug: `${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')}/${post.slug}`
},
props: { post },
};
});
```
**Update:** That code had a [timezone bug](/2026/02/10/timezone-bugs-in-a-static-site/) that quietly broke 43 post URLs. JavaScript's `Date` object discards the original timezone, so late-night Pacific posts rolled over to the next day in UTC. The fix was to stop using `Date` for URL generation entirely.
The design is inspired by Dieter Rams and Swiss typography. Black, white, and a single red accent color. I spent way too much time looking at Braun product catalogs and old Systems 14 calendars, but the result feels right. No gradients, no rounded corners, just clean lines and good type.
The site still deploys to S3 with CloudFront in front, now via GitHub Actions instead of a shell script. Push to master, wait a minute, done.
I'm genuinely impressed with Astro. The developer experience is excellent, the build times are fast, and the output is lean. We'll see if it holds up for another decade.
If you're reading this via RSS, congrats on still subscribing after all these years.
---
## Hugo Deploy
- URL: https://mattmichie.com/2023/02/09/hugo-deploy/
- Date: 2023-02-09
- Categories: software engineering
I just realized that Hugo has it's own deploy mechanism, so I'm trying it out.
Hugo Deploy worked well for pushing the site to S3, but the blog has since moved to [Astro](/2026/02/03/transitioning-to-astro/).
---
## Amazon Average Profit Margin Post
- URL: https://mattmichie.com/2022/10/17/amazon-average-profit-margin-post/
- Date: 2022-10-17
- Categories: random
I wrote up a quick post on [Amazon Average Profit
Margin](https://hivearchive.com/blog/amazon-average-profit-margin/), over at
Hivearchive. My goal was to give a quick overview on what a seller can expect
especially selling with Amazon FBA.
I also explain some of the benefits a seller will get from using Hivearchive.
Check it out, thanks.
---
## Launched Genki Garb Store today!
- URL: https://mattmichie.com/2022/10/17/launched-genki-garb-store-today/
- Date: 2022-10-17
- Categories: personal
We launched the new [Genki Garb E-commerce Store](https://genkigarb.com), today.
I'm excited to provide life changing clothing for VAD patients. We have shorts,
and shirts that are compatible with the top VAD products.
Check it out and share with anyone you know who has one of these devices. We
are looking for feedback, and keep making our products better over time.
---
## Migrated from Hivearchive.com to MattMichie.com
- URL: https://mattmichie.com/2022/08/20/migrated-from-hivearchivecom-to-mattmichiecom/
- Date: 2022-08-20
- Categories: personal
I forget what the original purpose of hivearchive.com was, but it wasn't for
a blog. For a time, I hosted this content there because I liked the name, but
recently, I created an actual piece of software there, and therefore have moved
everything here.
We'll see how long it takes for the next update! Could be awhile!
For the full story of 25 years of blogging, see [25 Years of Writing About Tech](/2026/02/04/25-years-of-writing-about-tech/).
---
## Relaunched Best Deck of Cards
- URL: https://mattmichie.com/2016/11/23/relaunched-best-deck-of-cards/
- Date: 2016-11-24
- Categories: random
I have relaunched my extreme specialty site, which links to the [best deck of
cards](http://bestdeckofcards.com/) I've ever used. Down the road, I may add
some more brands and decks, but right now it's a handy bookmark for myself.
---
## Using Dropbox as a Git Repo
- URL: https://mattmichie.com/2016/11/12/using-dropbox-as-a-git-repo/
- Date: 2016-11-12
- Categories: software engineering
Today I realized that most of the private GitHub repos that I was using were getting
zero benefit from hosting on GitHub. Then, I thought it would be simple just to
host them directly on Dropbox, which worked great.
However, I started thinking through the implications of a partially synced Dropbox or
what would happen if there was a conflict and how that could potentially corrupt
my repo.
With a little research, I found the perfect solution: [Git Remote Dropbox](https://github.com/anishathalye/git-remote-dropbox). This works fantastically well for the couple of private repos I need.
Because I had created a full repo directly on Dropbox, I couldn't figure out how
to convert over my repo because the instructions listed:
```
git clone "dropbox://path/to/repo"
```
That example kept failing with an empty repo, so I thought maybe I was getting
the paths wrong. The problem is that you can't have the Git repo directly in
Dropbox at all. First, move the repo out of Dropbox onto your regular
filesystem, then just do a remote add as follows:
```
git remote add origin "dropbox://path/to/repo"
```
This did exactly what I expected, and I've had no issues since.
---
## Brought back BSOD gallery
- URL: https://mattmichie.com/2016/11/12/brought-back-bsod-gallery/
- Date: 2016-11-12
- Categories: bsod
So I finally found all the old images from the [Blue Screen of Death
(BSoD)](/archive/bsod/) gallery and put them back online. Enjoy. Feel free to
send me more of them in the wild should you run across them!
---
## Adding Flash to Ubuntu Xenial Chrome
- URL: https://mattmichie.com/2016/11/07/adding-flash-ubuntu-xenial-chrome/
- Date: 2016-11-08
- Categories: linux, system administration
Here's some quick and clear instructions on how to add Adobe Flash to Google
Chrome on Ubuntu 16.04.1 Xenial Xerus from the terminal through the command line:
```
$ sudo add-apt-repository "deb http://archive.canonical.com/ubuntu $(lsb_release
-sc) partner"
$ sudo apt-get update
$ sudo apt-get install adobe-flashplugin
```
Restart Chrome and everything should be happy.
---
## Ditched Blogofile for Hugo
- URL: https://mattmichie.com/2016/11/06/ditched-blogofile-for-hugo/
- Date: 2016-11-07
- Categories: software engineering
Apparently I only update this blog when I transition from technology to
technology. It's been a good six years. I hadn't kept up on the blogofile
updates, and so I decided to go wholesale into hugo. I've tried to keep the
URLs about as close as I could get.
The site is now also hosted by S3, so it should be pretty stable.
For reference, here's a quick and dirty script I wrote to convert from Blogofile
0.6 to Hugo. It's buggy and will probably delete your hard drive, but I'll put
it out here for future Googling anyway.
I wonder if anyone has a RSS feed poking at this anymore? Leave a comment and say hi!
**Update:** Ten years later, the blog moved again -- this time to [Astro](/2026/02/03/transitioning-to-astro/).
```
import datetime
import dateutil.parser
import glob
import html2text
import re
import sys
for file_name in glob.glob('before/*'):
print 'Processing: %s' % file_name
html_file = open(file_name, 'r')
lines = html_file.readlines()
categories = lines[1].strip()
categories = '[ ' + ', '.join(['"%s"' % i for i in categories.split(': ')[1].split(', ')]) + ' ]'
print categories
date = lines[2].strip().split(': ')[1]
date = dateutil.parser.parse(date).strftime('%Y-%m-%dT%H:%M:%S-07:00')
guid = lines[3].strip()
permalink = lines[4].strip()
tags = lines[5].strip()
tags = '[ ' + ', '.join(['"%s"' % i for i in tags.split(': ')[1].split(', ')]) + ' ]'
title = lines[6].strip().split(': ')[1]
body = lines[8:]
body = ''.join(body)
body = ''.join([i if ord(i) < 128 else ' ' for i in body])
out_file_name = file_name.split('. ')[1].split('.')[0]
out_file = open('content/%s.md' % out_file_name, 'w')
print >> out_file, '---'
print >> out_file, 'title = "%s"' % title
print >> out_file, 'date = %s' % date
print >> out_file, 'draft = false'
print >> out_file, 'categories = %s' % categories
print >> out_file, '---'
print >> out_file, ''
try:
print >> out_file, html2text.html2text(body)
except Exception as e:
print 'exception: %s on %s' % (e, body)
sys.exit(1)
html_file.close()
out_file.close()
```
---
## Converted old daimyo content
- URL: https://mattmichie.com/2016/11/06/converted-old-daimyo-content/
- Date: 2016-11-06
- Categories: hugo
I spent the morning dumping the Drupal database that used to power this website.
Since it was such an old version of Drupal, the existing drupal2hugo converter
did not work, so I wrote my own.
Be warned now that it's a hack, and will probably delete all your data. That
said, I've included it here for anyone who may be Googling in the future.
```python
#!/usr/bin/python
from __future__ import unicode_literals
import datetime
import html2text
import MySQLdb as mdb
import re
def file_guess(title):
title = title.replace(' ', '-')
title = title.replace('.', '-')
title = title.replace('?', '')
title = title.replace('"', '')
title = title.replace('%', 'percent')
title = title.replace('&', 'percent')
title = title.replace('$', '')
title = title.replace('/', '')
title = title.replace('>', '')
title = title.replace('<', '')
title = title.replace(',', '')
title = title.replace("'", '')
title = title.replace(":", '')
if title[-1] == '-':
title = title[:-1]
title = re.sub('-+\(.*\)$', '', title)
title = re.sub('-{2,}', '-', title)
title = re.sub('-\(.*$', '', title)
title = re.sub('\([r|R]\)', '', title)
title = title.lower()
title = title + '.md'
return title
db = mdb.connect(host='localhost', user='', passwd='',
db='drupal', charset='utf8', use_unicode=True)
cur = db.cursor(mdb.cursors.DictCursor)
cur.execute('select * from node where type="blog"')
for row in cur.fetchall():
f = open('content/%s' % file_guess(row['title']), 'w+')
print 'processing file_name: %s' % file_guess(row['title'])
print >>f,'+++'
print >>f, 'title = "%s"' % row['title']
print >>f, 'draft = false'
print >>f, 'date = %s' % datetime.datetime.fromtimestamp(int(row['created'])).strftime('%Y-%m-%dT%H:%M:%S-07:00')
print >>f, ''
print >>f, '+++'
print >>f, ''
try:
print >>f, html2text.html2text(row['body'].encode('ascii', 'ignore'))
except Exception as e:
print 'could not convert: %s because %s' % (row['title'], e)
f.close()
db.close()
```
---
## Hugo theme works locally, not on S3
- URL: https://mattmichie.com/2016/11/05/hugo-theme-works-locally-not-on-s3/
- Date: 2016-11-05
- Categories: hugo
I attempted to setup a new Hugo site with the S3 websites feature. When I ran
the Hugo server locally, my theme displayed correctly. However, when I uploaded
it to S3, the CSS wasn't displaying, even though the files were there.
The dev console in Chrome showed that it was fetching the CSS files, but it was
failing to render them. When I opened the error console in Safari, it finally
told me the issue: ``"Did not parse stylesheet at 'http://daimyo.org/css/style.css'
because non CSS MIME types are not allowed in strict mode."``
Since I was using s3cmd to upload my site into the bucket, I did some Googling
which led me to this bug report: [//github.com/s3tools/s3cmd/issues/198](https://github.com/s3tools/s3cmd/issues/198).
The long and short is that CSS has issues getting mime type autodetected, so
even when you run s3cmd with the ``--guess-mime-type`` flag, it still wouldn't
set the correct mimetype. Once I set the --no-mime-magic flag, everything was
happy again. Be sure to check mimetype in S3 afterward to ensure it is being
set properly.
---
## Reinitializing daimyo
- URL: https://mattmichie.com/2016/11/05/reinitializing-daimyo/
- Date: 2016-11-05
- Categories: meta
After many years of neglect, I took some time to bring daimyo.org back to life.
It is now proudly hosted using Route53, S3 and the Hugo static site generator.
At least it's likely that S3 won't be going down very often, or losing this data
anytime soon. **knock on wood**
---
## Ditched Wordpress for Blogofile
- URL: https://mattmichie.com/2010/11/27/ditched-wordpress-for-blogofile/
- Date: 2010-11-28
- Categories: software engineering
I'm finally tired of the Wordpress upgrade treadmill, and the zero-day
exploits for poorly written PHP code causing my site to be compromised, and
spammers to filling my blog with crap.
Since many of my posts have good Google juice, it was important for me to
maintain my link structure. For awhile, I toyed with writing my own static
site generator. I wanted to be able to edit my posts in Vim, and generate
static HTML. The bar for hacking a blog through static HTML files and CSS is
far higher than PHP backed MySQL driven sites. I did some searching and found
one written in my language of choice, Python and which allowed me to
seamlessly convert from PHP without breaking my links.
Though it's got some rough edges, I'm pretty pleased with how well
[Blogofile](http://www.blogofile.com/) has worked. I highly recommend it! Now that [CloudFront supports a default root object](http://aws.amazon.com/about-aws/whats-new/2010/08/05/cloudfront-adds-default-root-object-capability/), I will eventually end up serving my blog through AWS, eliminating having to maintain a server or muck with Apache at all. Win win win.
**Update:** The blog has since moved from Blogofile to Hugo, and most recently to [Astro](/2026/02/03/transitioning-to-astro/).
---
## Upgraded to Wordpress 2.9
- URL: https://mattmichie.com/2009/12/19/upgraded-to-wordpress-29/
- Date: 2009-12-20
- Categories: wordpress
Tired of the Wordpress upgrade treadmill. I don't need any new features, but
I'm terrified of all the lurking security holes. It may be high time to write
my own blogging engine with only the features I need. Update: awesome, a
spammer injected crap into my blog already. I hate wordpress.
---
## Chinese Citation
- URL: https://mattmichie.com/2008/12/11/chinese-citation/
- Date: 2008-12-11
- Categories: linux
I came across [someone citing an article](http://cyberwarfaremag.wordpress.com/2008/12/05/china-red-flag-linux/) I wrote for Linux.com back in 2002 about China's Red Flag Linux. It's
weird reading stuff I wrote back then now. Back in the day, I thought I was
pretty knowledgeable. These days I actually know more, and feel like I know
less. In fact, it's hard to find anything worthwhile to write about as I don't
feel like I can do it justice. One of these days I'm going to have to
chronicle some of the event surrounding Linux.com. I made a lot of good
friends working on that site, made a little bit of money for college, and
learned a ton. Still, there were some decisions made by VA/OSDN that weren't
in the best interest of the community or the people that volunteered their
time, energy and passion to trying to spread open source and evangelize Linux.
Maybe some day I will, but not tonight :) Happy Holidays everyone!
---
## Attack of the Ubuntu Forks
- URL: https://mattmichie.com/2008/11/17/attack-of-the-ubuntu-forks/
- Date: 2008-11-18
- Categories: linux
Why does Ubuntu [inspire so many forks](http://www.linuxhaxor.net/2008/11/17/attack-of-the-ubuntu-forks/)?
---
## Why does Ubuntu have so many forks?
- URL: https://mattmichie.com/2008/11/10/why-does-ubuntu-have-so-many-forks/
- Date: 2008-11-10
- Categories: linux
Why do you need to fork an entire distribution to change the window manager,
like Xubuntu, or to make the default KDE like Kubuntu? Ummm, could you just
make it user configurable instead of duplicating this amount of effort? Guys,
really? Really? Really?
---
## Chimpanzee rides Segway and Wins at the Internet
- URL: https://mattmichie.com/2008/10/21/chimpanzee-rides-segway-and-wins-at-the-internet/
- Date: 2008-10-21
- Categories: random, humor
I love you internets.
---
## Need a private jet?
- URL: https://mattmichie.com/2008/09/13/need-a-private-jet/
- Date: 2008-09-14
- Categories: random
Hope you got several thousand dollars per
hour :)
---
## Seattle relieved to lose its high-tech toilets
- URL: https://mattmichie.com/2008/08/17/seattle-relieved-to-lose-its-high-tech-toilets/
- Date: 2008-08-17
- Categories: seattle
> City officials have finally gotten rid of five high-tech self-cleaning
toilets that cost Seattle $5 million but sold online for just $12,549. The
city installed the modernistic stand-alone toilets four years ago, hoping they
would provide tourists and the homeless a place to do their business while
downtown. But the automated loos became better known for drug use and
prostitution than for relief. [USA
Today](http://www.usatoday.com/news/offbeat/2008-08-15-seattle-toilets_N.htm)
Oh you clever headline writer you. It's rather unfortunate that these didn't
work out. I remember seeing similar public toilets in Paris. This is a huge
problem in downtown Seattle. It is difficult to find a public restroom
anywhere, much less if you look like a transient. Living downtown, I have
found a couple of strategic places that I can just jump into the bathroom
without a code, or having to make a purchase, or being scrutinized before
using it (and no I'm not telling where they are). The one truly open to the
public restrooms exist in the downtown Seattle Library. The last time I walked
in there, there were multiple homeless men practically camped in the bathroom,
trying to wash up. One was shaving in the mirror. I have a lot of sympathy for
their situation, but it was also a very uncomfortable place to be. There has
to be a better way.
---
## BMW GINA Light Visionary Model
- URL: https://mattmichie.com/2008/08/15/bmw-gina-light-visionary-model-premiere/
- Date: 2008-08-15
- Categories: video
The BMW GINA Light Visionary Model - a shape-shifting concept car with a fabric skin that can change form.
---
## Project Euler and Prime Factorization
- URL: https://mattmichie.com/2008/06/20/project-euler-and-prime-factorization/
- Date: 2008-06-20
- Categories: python, programming
I have been doing some of the exercises at [Project Euler](http://projecteuler.net/) lately. Project Euler describes themselves
as:
> A series of challenging mathematical/computer programming problems that will
require more than just mathematical insights to solve. Although mathematics
will help you arrive at elegant and efficient methods, the use of a computer
and programming skills will be required to solve most problems.
It has been a lot of fun to code these up in my language du jour, Python. There are a couple of problems that Python's built in libraries have made trivial.
I have to admit the most enjoyable part for me is having problems that require efficiency in algorithm. For the simpler problems, I usually just quickly hack together the "naive" brute force method, figure out that it doesn't scale and then start investigating how I can fix it. Doing this, you will exercise your mathematics, computer science and programming skills, something that a lot of programming doesn't do.
I convinced my girlfriend to work with me on one of the exercises, and of course she picked one of the Prime Factorization problems. The naive brute force algorithm would not be an option for the large composite number given, so we ended up hacking together a [Sieve of Eratosthenes](http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes).
Ultimately, we got a version working, but it was still pretty inefficient, only returning the answer in about an hour. An optimal version should be able to do it within seconds. Obviously there is some "refactoring" to do.
That appetite for building simulations to understand systems led to a much larger project: [simulating blackjack the hard way](/2026/02/12/simulating-blackjack-the-hard-way/).
---
## Upgraded Wordpress to 2.5 with SVN
- URL: https://mattmichie.com/2008/04/21/upgraded-wordpress-to-25-with-svn/
- Date: 2008-04-22
- Categories: wordpress
So my Wordpress got compromised again by spammers, I've upgraded to the latest
and greatest and instituted new protection mechanisms as well as tracking
Wordpress by SVN to make upgrades more painless. Some stats: You have 125
posts, 2 pages, 11 drafts, contained within 63 categories and 2 tags. You are
using WordPress Default theme with 3 widgets. This is WordPress version 2.5.
Akismet has protected your site from 24,837 spam comments already, and there
are 446 comments in your spam queue right now.
---
## A real solution to PowerShell SSH Remoting
- URL: https://mattmichie.com/2008/03/30/a-real-solution-to-powershell-ssh-remoting/
- Date: 2008-03-31
- Categories: windows, security, microsoft, system administration
**Update (July 2026):** NetCmdlets, the MSDN blog, and the era when a third-party cmdlet pack was the "real solution" are all gone. Windows ships OpenSSH natively now and PowerShell 7 remotes over SSH out of the box: [Using PowerShell over SSH, Twenty Years Later](/2026/07/11/powershell-over-ssh-twenty-years-later/).
---
> Can't wait for us to ship PowerShell Remoting? Want remoting to use SSH? Why
wait for us? /N software has just announced a beta of their NetCmdlets V2.0
which provides PowerShell remoting over SSH today! They've had this for a
while and V2 updates (and improves) the usability of the cmdlets as well as
adding a bunch of new and exciting commands. For example, chances are that you
won't ever see Microsoft ship the [get/send]-s3 cmdlets but /N software V2
does. :-)
My [blog post](/2006/07/03/using-powershell-through-ssh/) from 2006 is currently the #1 Google Result for PowerShell SSH, but finally there is a good solution out there from /N software. It also supports S3. Very cool :)
---
## Craig Venter
- URL: https://mattmichie.com/2008/03/27/craig-venter/
- Date: 2008-03-28
- Categories: video, science
Interesting video... Feels strange to see CompSci intersecting so close to Biology.
---
## ZFS Source Tour
- URL: https://mattmichie.com/2008/03/20/zfs-source-tour/
- Date: 2008-03-20
- Categories: solaris, software engineering
---
## In Canada, Milk Comes in Bags
- URL: https://mattmichie.com/2008/03/16/in-canada-milk-comes-in-bags/
- Date: 2008-03-16
- Categories: random, humor
---
## iBand
- URL: https://mattmichie.com/2008/02/21/iband/
- Date: 2008-02-21
- Categories: random, video
---
## Tuscon Complete Launches
- URL: https://mattmichie.com/2007/12/11/tuscon-complete-launches/
- Date: 2007-12-12
- Categories: friends
My friend Richard has just launched his newest site:
[Tusconcomplete.com](http://www.tucsoncomplete.com). The goal is to collect
all the little tidbits of Tuscon in one place. Check it out, it is powered by
my all time favorite open source Wiki software, DokuWiki. Congrats on the site
launch, good luck dude!
---
## Obligatory Seattle Snow Pictures
- URL: https://mattmichie.com/2007/12/01/obligatory-seattle-snow-pictures/
- Date: 2007-12-02
- Categories: seattle
When it snows in Seattle, it s a big deal. 

Thanks to [Flickr](http://www.flickr.com/) for hosting my images.
---
## By the powers of two I command you to dial
- URL: https://mattmichie.com/2007/11/13/by-the-powers-of-two-i-command-you-to-dial/
- Date: 2007-11-13
- Categories: random, humor, system administration
> Here in Alabama, USA we've just acquired the new area code "256" which means
that some lucky (and probably unappreciative) bastard will get ---1-256-512-1024
Which has simply got to be the coolest damn phone number I can imagine. \--
David McNett Can i dial 1-255-255-255255 and make every phone in the world
ring? \-- Tanuki
---
## Personal Gmail Use Statistics
- URL: https://mattmichie.com/2007/11/04/personal-gmail-use-statistics/
- Date: 2007-11-05
- Categories: google, random
I've been using Gmail since the invite only beta, my first received email was
6/15/04, and overall I have 8353 emails stored, which means that: I am
currently using 896 MB (19%) of 4647 MB. Not bad, wish Google tracked the
amount of spam I've gotten in that time frame. What does everyone else's
account look like?
---
## Refresh on Daimyo.org
- URL: https://mattmichie.com/2007/11/04/refresh-on-daimyoorg/
- Date: 2007-11-04
- Categories: wiki
I got tired of all the crappy security updates that I needed to apply to my
Drupal site, so I deleted the whole thing and installed
[DokuWiki](http://wiki.splitbrain.org/wiki:dokuwiki). I'll be filling it out
slowly over the next couple of years. Feel free to add something to it.
[Daimyo.org](http://daimyo.org)
---
## Bash one liner to randomize lines in file
- URL: https://mattmichie.com/2007/10/18/bash-one-liner-to-randomize-lines-in-file/
- Date: 2007-10-18
- Categories: linux, unix, system administration
## The Modern Way
As many commenters pointed out over the years, most Linux systems now ship with `shuf` (part of GNU coreutils):
```bash
shuf unusual.txt > randorder.txt
```
If your system has GNU sort, `sort -R` also works, though it groups duplicate lines together:
```bash
sort -R unusual.txt > randorder.txt
```
For maximum portability (especially on older systems or macOS without GNU coreutils), the `awk` approach works everywhere:
```bash
awk 'BEGIN{srand()}{print rand(),$0}' unusual.txt | sort -n | cut -d ' ' -f2- > randorder.txt
```
---
## Original 2007 Post
Discovered that the bash shell has a variable called `$RANDOM`, which outputs a
pseudo-random number every time you call it. Sweet! Allowed me to randomize
the lines in a file for a process I needed to do, thusly:
```bash
for i in `cat unusual.txt`; do echo "$RANDOM $i"; done | sort | sed -r 's/^[0-9]+ //' > randorder.txt
```
In other words, put a random number on every line, sort the file, then take
off the random numbers. Worked like a charm.
**Note:** The `for` loop breaks on lines with spaces. If your file has spaces, use `while read` instead:
```bash
while read -r line; do echo "$RANDOM $line"; done < unusual.txt | sort | sed -r 's/^[0-9]+ //' > randorder.txt
```
Also, `sed -r` is GNU sed. On macOS, use `sed -E` instead.
---
## Hivearchive Downtime
- URL: https://mattmichie.com/2007/10/05/hivearchive-downtime/
- Date: 2007-10-06
- Categories: linux, system administration
Had a bit of hardware trouble, with a hard drive failing today. However, due
to my sysadmin ninja skills, no data was lost and the RAID 1 is rebuilding.
> [root@nexus ~]# cat /proc/mdstat Personalities : [raid1] md1 : active raid1
hdc1[2] hda1[0] 79360960 blocks [2/1] [U_] [>....................] recovery =
2.2% (1809408/79360960) finish=25.9min speed=49725K/sec md0 : active raid1
hdc2[1] hda2[0] 1052160 blocks [2/2] [UU] unused devices:
If you need to do this:
> # dd if=/dev/hda of=/dev/hdc bs=512 count=1 # mdadm --manage /dev/md0 --add
/dev/hdc2 # mdadm --manage /dev/md1 --add /dev/hdc1
In other words, copy the master boot record from the good drive to the new
drive so you have the same partitions, then hot add the new partitions to your
array. WARNING DANGER DANGER WARNING. Backup all your data first, and test
your backups work. Change the partitions and drives to match your own
situation. Failure to do so will cause you to hose your system... That is all.
Now if only Linux could do all this automatically like other sane operating
systems. Update: I'm getting a little suspicious that just copying the MBR
from one hard drive to another, messed up something with Linux's software
RAID. Sigh. This is exactly how I would do it in Solaris, but Linux has no
great documentation on how to do it easily. Lazyweb? Update, 2 Aug 2008: I did
this again and this time realized that copying the MBR will work fine with DD,
but Linux needs to be explicitly told to rescan the partition table. I simply
opened up the device with fdisk, checked the partitions looked how I wanted
and then rewrote the partition table. Fdisk then calls the IOCTL to tell the
kernel to rescan the partitions. Problem solved. :)
---
## iPhone Fun
- URL: https://mattmichie.com/2007/09/27/iphone-fun/
- Date: 2007-09-27
- Categories: python, apple, unix, iphone
```
# uname -a
Darwin Matt Michie's iPhone 9.0.0d1 Darwin Kernel Version 9.0.0d1:
Fri Jun 22 00:38:56 PDT 2007;
root:xnu-933.0.1.178.obj~1/RELEASE_ARM_S5L8900XRB iPhone1,1 Darwin
# python
Python 2.5.1 (r251:54863, Jul 27 2007, 12:05:57)
[GCC 4.0.1 LLVM (Apple Computer, Inc. build 2.0)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
```
Mmmmm tasty! iPhone with SSH, Python, BSD subsystem. Life is good.
---
## Upgraded to WordPress 2.3
- URL: https://mattmichie.com/2007/09/25/upgraded-to-wordpress-23/
- Date: 2007-09-26
- Categories: wordpress, system administration
Surprisingly, the upgrade went pretty smoothly. While dinking around in the
admin section, I noticed: Akismet has protected your site from 15,874 spam
comments. Man, I hate spammers. The more popular my domains get, the more they
get targeted. One of my other sites was used as a forged from address in a
bunch of e-mails and I got all the bounces. Thanks for checking SPF everyone.
:( **Update**: Ugh! Damn it.
```
WordPress database error: [Table 'wp_post2cat' doesn't exist]
SELECT cat_ID AS ID, MAX(post_modified) AS last_mod
FROM `wp_posts` p
LEFT JOIN `wp_post2cat` pc ON p.ID = pc.post_id
LEFT JOIN `wp_categories` c ON pc.category_id = c.cat_ID
WHERE post_status = 'publish'
GROUP BY cat_ID
```
Yes, I ran the update which supposedly updated my DB. Lovely. **Update 2**:
Apparently I need to update my Google Sitemaps plugin as found in this thread:
---
## VMWare VProbes (dtrace for all)
- URL: https://mattmichie.com/2007/09/17/vmware-vprobes-dtrace-for-all/
- Date: 2007-09-18
- Categories: virtualization, troubleshooting, system administration, software
Keith Adams has an intriguing post about [VMWare
vprobes](http://x86vmm.blogspot.com/2007/09/presenting-vprobes.html):
> VProbes attempts to provide a set of tools for answering the question, "What
the heck is this computer doing?" It's an open-ended question, so vprobes is
accordingly open-ended, as well. In its current form, it provides an
interactive, safe way of instrumenting a running VM at any level: from user-
level processes down to the kernel, and even into VMware's VMM and hypervisor,
if need be.
>
> First, we are aiming to provide a Dtrace-like tool for other commercially
important operating systems than Solaris. Second, VProbes can combine with
other virtualization-based techniques in powerful ways. For example, VProbes
and deterministic replay combine to make the most potent tool that I'm aware
of for debugging intermittent performance anomalies.
---
## Ruby Monkey Patching Slang
- URL: https://mattmichie.com/2007/08/12/ruby-monkey-patching-slang/
- Date: 2007-08-12
- Categories: ruby, humor
Stumbled across a great list of "alternate" terms for Monkey Patching in Ruby:
[My Complete List Of Substitute Names For The Maneuver We Now Know To Be
Monkeypatching](http://hackety.org/2007/08/10/myCompleteListOfSubstitutePhrasesForTheActWeNowKnowToBeMonkeypatching.html)
---
## TCP/IP Over Firewire on OSX
- URL: https://mattmichie.com/2007/07/22/tcpip-over-firewire-on-osx/
- Date: 2007-07-22
- Categories: grid computing, osx, network
I wasn't aware of this until today:
> Customers can immediately enable IP over FireWire and then connect two or
more Macintosh systems by FireWire for file sharing, Internet sharing, or the
use of any other IP-based service. IPv6 and zero-configuration networking are
also supported. Many Macintosh products have 10/100 Ethernet and FireWire 400,
making FireWire the fastest option for local area IP. For help activating IP
over FireWire, open Mac Help and enter "IP over FireWire". IP over FireWire
can also be used as the starting point for new development, such as for
cluster computing applications. Established IP services such as AFP, HTTP,
FTP, SSH and TCP/IP can all be used on FireWire to support new development.
[IP Over Firewire
(apple.com)](http://developer.apple.com/hardwaredrivers/firewire/ip_over_firewire.html)
Sweet! (yes, Gigabit Ethernet is faster and better supported, but I love
having a wide range of devices on the Physical layer of the stack)
---
## Everything is Miscellaneous
- URL: https://mattmichie.com/2007/07/14/everything-is-miscellaneous/
- Date: 2007-07-14
- Categories: internet, psychology, philosophy, video
> "David Weinberger's new book covers the breakdown of the established order
of ordering. He explains how methods of categorization designed for physical
objects fail when we can instead put things in multiple categoreis at once,
and search them in many ways. This is no dry book on taxonomy, but has the
insight and wit you'd expect from the author of The Cluetrain Manifesto, Small
Pieces Loosely Joined, and a former writer for Woody Allen."
The video starts out a little slow and I kept thinking, "yes, this is
obvious," but it picks up pace and puts all the things that are happening in
the taxonomy / folksonomy field into perspective. Also Melvil Dewey of the
Dewey Decimal System, sounds a lot more insane than I ever realized. David
Weinberger really gets to some issues that I hated about the way that
Universities somewhat arbitrarily divide learning into Colleges.
How does it make sense that Computer Science and Painting are both in the
College of Arts & Sciences, yet Electrical Engineering is in the College
of Engineering, for example. Some important cross fertilization is missed
simply because students are physically separated into different buildings.
Damn you Aristotle, damn you! *Shakes fist*
_Update_: just read an article in the NY Times [about a library abandoning the
Dewey Decimal System](http://www.nytimes.com/2007/07/14/us/14dewey.html)
---
## Worse is better?
- URL: https://mattmichie.com/2007/06/29/worse-is-better/
- Date: 2007-06-29
- Categories: python, ruby, linux, freebsd
Linux : FreeBSD :: Ruby : Python Discuss.
---
## Seattle 911 Dispatch on I5
- URL: https://mattmichie.com/2007/06/18/seattle-911-dispatch-on-i5/
- Date: 2007-06-18
- Categories: seattle
Tonight, I heard a bunch of sirens beyond the typical living in First Hill
next to 10 hospitals sirens, and lacking a scanner I was curious what was
going on. I fired up Google and found a nice mashup of real time [Seattle 911
Dispatch overlaid on Google Maps](http://www.public911.com/911/seattle).
Someone must have convinced the Seattle.gov guys to make it easy to parse
again. I know there was a flareup where for "security" reasons they turned the
whole thing into an image. Anyway, I assume the incident I heard was:
> 22:26:09 Rescue Heavy 0 - 0 Nb I5 At 45A14 A14 B5 B6 DEP1 E17 E2 E22 E25 L7
L9 M16 M16 M44 R1 SAFT2 STAF10
Which according to the legend, and as best I can tell, they dispatched 2 Aid
Units (Basic Life Support), 2 Battalion Chiefs, 4 Engines (water, hose and a
pump), 2 Ladders (ladders and a large assortment of tools), 3 Medic Units
(Advanced Life Support), 1 Rescue Unit and 3 others which I'm not sure how to
interpret (DEP1, SAFT2, STAF10) to a location on I-5. Searching around the
[Seattle Fire Dept
Gallery](http://www.seattle.gov/fire/photoGallery/apparatusShowcase/showcasemenu.htm)
didn't reveal much. Anyone know what those other 3 units are? Must have been a
pretty nasty accident. Hope everyone comes out safely.
---
## Python Party in Ruby
- URL: https://mattmichie.com/2007/06/17/python-party-in-ruby/
- Date: 2007-06-17
- Categories: python, ruby
> Last month, a lengthy discussion kicked off on Ruby-Talk called "[Why not
adopt Python style indentation for Ruby?](http://blade.nagaokaut.ac.jp/cgi-
bin/scat.rb/ruby/ruby-talk/252034)" .. it wasn't anything particularly new,
because [a similar discussion](http://blade.nagaokaut.ac.jp/cgi-
bin/scat.rb/ruby/ruby-talk/11876) occurred six years ago. Nevertheless, a
coder called Jinjing has been inspired to create
[Lazibi](http://lazibi.rubyforge.org/), a Ruby pre-processor to allow one to
use Python style indentation within Ruby code.
Why not just adopt Python altogether? :-P So close and yet so far.
---
## Firefox Bug on Long Tooltips
- URL: https://mattmichie.com/2007/06/17/firefox-bug-on-long-tooltips/
- Date: 2007-06-17
- Categories: humor, software engineering
The true test of Geekdom is whether you can read a bug report on a Saturday
evening and find great humor in it. Here is your chance:
### [Bug 45375](https://bugzilla.mozilla.org/show_bug.cgi?id=45375) SeaMonkey-
only bug: Long tooltips should wrap instead of being cropped (multiline
tooltips)
Look for such "celebrity" appearances as the "[xkcd](http://xkcd.com)" guy and
others. My favorite part, is the bug reporter chiming in each year to wish the
bug happy birthday, though there is an inconsistency when he changes the
gender of the bug along the way. Maybe I should file a bug on the bug report?
---
## Regular Expressions, Lisp, SQL, Parsing, Domain Specific Languages
- URL: https://mattmichie.com/2007/06/10/regular-expressions-lisp-sql-parsing-domain-specific-languages/
- Date: 2007-06-10
- Categories: code, lisp, programming, unix, philosophy, software engineering
I've been trying to code some more on Project Shelob (my web server) in my spare time. I'm to the point of needing a configuration file, so I can start up the server using different ports and directories for testing.
Speaking of testing, I'm also to the point of needing automated test suites. I was refactoring some of the HTTP code, and when I got done, it was far more readable, and there was much rejoicing! Unfortunately, two days later I discovered I had introduced a subtle bug in keep-alive handling during a 404 event. Oops.
Anyway, I decided to use JSON as my configuration language. Simple, accommodated everything I needed, and later I would be able to easily write an AJAX GUI front end to configure the whole thing. Should be slick, right?
Not as easy as it might sound. Though I have written parsers by hand, I'd rather not. Ok, so I'm using C++, surely someone has written an easy to use open source library that I can just stick in my rules and get out a nice data structure, right?
Well, kind of. There is [Boost Spirit](http://spirit.sourceforge.net/) which would do everything that I want it to do, but it also required me translating the EBNF grammar of JSON into Boost's strange amalgamation of YACC and C++. Okay well and good, but surely there is something better?
After some more searching, I run across [ANTLR](http://www.antlr.org/) which seems to be the spiritual successor to LEX and YACC/Bison. It even has a nice Java GUI and someone had kindly done the ANTLR rules for JSON. Check out the graphical goodness:

Still, the C++ backend wasn't fully supported and required installing libraries and was complicated. Not 100% what I needed or wanted.
All of which got me thinking about domain specific languages. Most programmers don't consider it, but SQL and Regular Expressions are good examples of Domain Specific Languages (DSL), as are lex and yacc/bison.
Up till now, I've frowned on the whole idea of DSLs in general. It had always seemed like bad software engineering practice to invent a new language for each problem. After all, did we really want to learn an entirely new programming language with each assignment? Who is going to maintain the code?
However, the facts point out that you have to learn an entire API anyway, and the API really just layers over what you're really trying to do with a language that wasn't quite expressive enough to do the job natively to begin with.
Which of course leads me to LISP and through Martin Fowler who makes [some good points here](http://www.martinfowler.com/articles/languageWorkbench.html#unixLittleLanguage):
> "One of the most obviously DSLy parts of the world is the Unix tradition of writing [little languages](http://www.catb.org/%7Eesr/writings/taoup/html/minilanguageschapter.html). These are external DSL systems, that typically use Unix's built in tools to help with translation. While at university I played a little with lex and yacc - similar tools are a regular part of the Unix tool-chain. These tools make it easy to write parsers and generate code (often in C) for little languages. Awk is a good example of this kind of mini-language."
While I've been using SQL, regular expressions, awk, lex, and yacc for years, I'd never really classified them in my mind as DSLs. I've been well aware of the power of small specialized utilities aggregated together to perform a bigger task and why UNIX has been so successful at this, but I hadn't made the leap to apply this to my programming.
Fowler continues:
> "Lisp is probably the strongest example of expressing DSLs directly in the language itself. Symbolic processing is embedded into the name as well as practice of lispers. Doing this is helped by the facilities of lisp - minimalist syntax, closures, and macros present a heady cocktail of DSL tooling. Paul Graham writes a lot about [this style of development](http://www.paulgraham.com/progbot.html). Smalltalk also has a strong tradition of this style of development."
I've heard "grey-beards" and academics talk about the power of Lisp for years, and though I did some trivial functional programming in college, I've dismissed the rants of the Lisp guys as nothing more than rants. Today though, the ideas are crystallizing in my head, and I'm excited to explore this more.
---
## Reading about Get Friday on a Sunday
- URL: https://mattmichie.com/2007/06/03/reading-about-get-friday-on-a-sunday/
- Date: 2007-06-03
- Categories: random, humor, psychology
I read way too much and I visit too many random web sites. Today, I was
reading the Wall Street Journal online about [outsourcing the more common
things in your
life.](http://online.wsj.com/article/SB118073815238422013.html?mod=tff_main_tff_top)
I do a search for [Get Friday](https://www.getfriday.com/), one of the Indian
firms mentioned, out of curiosity. Under unusual services they have provided a
couple tidbits:
* Apologizing and sending flowers and cards on their behalf to spouses or clients.
* Research on how to tie a shoe lace meant for a kid (client s son).
* Talking to parents in our client s stead.
* Reading bedtime stories to a young kid on phone
What kind of person thinks it would be a swell idea to have someone in India
read your kid a bedtime story on the phone because they are too busy?
Although, it would be fun to have everyone route their requests to a personal
assistant, just to see the looks on their faces.
---
## Microsoft, true innovation
- URL: https://mattmichie.com/2007/06/03/microsoft-true-innovation/
- Date: 2007-06-03
- Categories: microsoft, unix, humor, philosophy
**Wes**: check out [introducing pipes](http://blogs.msdn.com/bclteam/archive/2006/12/07/introducing-pipes-justin-van-patten.aspx)
**Matt**: "Those who do not understand Unix are condemned to reinvent it, poorly."
**Matt**: I hear vista finally has symlinks. Wake me up when they invent mount points and finally kill drive letters
**Wes**: I think you can do that somehow.
**Matt**: yeah sure, and break everything *nerd rage*
**Wes**: yeah, junction point. [junction points (technet)](http://www.microsoft.com/technet/sysinternals/Utilities/Junction.mspx)
**Matt**: "Those who do not understand Unix are condemned to reinvent it, poorly."
---
**Update**: Wes says, if you want to know more see his blogs at:
- [www.brokenbuild.com/blog/category/windows-unixism](http://www.brokenbuild.com/blog/category/windows-unixism/)
- [www.brokenbuild.com/blog/2006/12/11/is-there-a-windows-equivalent-of-mount](http://www.brokenbuild.com/blog/2006/12/11/is-there-a-windows-equivalent-of-mount/)
---
## Smalltalk Inventor Uses Python
- URL: https://mattmichie.com/2007/05/29/smalltalk-inventor-uses-python/
- Date: 2007-05-29
- Categories: python
> "Alan Kay of Smalltalk fame, friend of Seymour Papert of Logo, champion of
One Laptop per Child ([OLPC](http://mybizmo.blogspot.com/2007/01/cp4e-versus-
olpc.html)) has become our new keynote speaker
([EuroPython](http://worldgame.blogspot.com/2006/07/information-
harvesting.html) by transmission) and provider of new hope to many a would be
Python learner. That's right, Alan has adopted Python as his new pet language"
From:
---
## I was a ghost in the machine until the machine woke up
- URL: https://mattmichie.com/2007/05/28/i-was-a-ghost-in-the-machine-until-the-machine-woke-up/
- Date: 2007-05-29
- Categories: web 2.0, random, philosophy, video
Found this video randomly today.... This is why I do what I do. Computers are great.
---
## NVidia Forcedeth Ethernet Full-Duplex
- URL: https://mattmichie.com/2007/05/25/nvidia-forcedeth-ethernet-full-duplex/
- Date: 2007-05-25
- Categories: linux, red hat, troubleshooting, system administration
Just an FYI, the NVidia Gigabit Forcedeth Ethernet driver in Linux uses the
ethtool command to get and set the duplex rate and not the mii-tool like many
other web pages erroneously state.
---
## The True Reason Halliburton is Evil
- URL: https://mattmichie.com/2007/05/24/the-true-reason-halliburton-is-evil/
- Date: 2007-05-25
- Categories: random, politics, humor, network
They have their very own Class A IP space assigned to them: See:
---
## Understanding Monkey Patching
- URL: https://mattmichie.com/2007/05/24/understanding-monkey-patching/
- Date: 2007-05-24
- Categories: python, ruby, rails, software engineering
I've noticed one of the problems I have writing this blog is that I prefer to
have finished thoughts when I write up something, or at least to have a good
understanding of a problem I am working on before committing it to 'paper'.
Unfortunately, this doesn't lead to many updates. I'll try to break this habit
a little. Recently I heard the term 'Monkey Patching' after one of the
[Seattle Patterns Group](http://www.patternsgroup.org) meetings, in relation
to Ruby on Rails.
> A [Monkey-Patch](http://en.wikipedia.org/wiki/Monkey_patch) (also called
Monkey Patch, MonkeyPatch) is a way to extend or modify runtime code without
altering the original source code for dynamic languages (e.g. Ruby and
Python).
Today, reading a [blog entry from Chad
Fowler](http://chadfowler.com/index.cgi/Computing/Programming/Ruby/TheVirtuesOfMonkeyPatching.rdoc,v),
the term came up again with a Python developer saying:
> You can monkeypatch code in Python pretty easily, but we look down on it
enough that we call it "monkeypatching". In Ruby they call it "opening a
class" and think it's a cool feature. I will assert: we are right, they are
wrong.
When I read that, I felt almost relieved, because I was thinking the same
thing. I can see a limited use for it, but it seems like something you should
only do in dire circumstances, that it would be detrimental to good software
engineering practices. I can't prove this, nor am I totally convinced, but
Ruby and Ruby on Rails in particular seems to play a little bit fast and
loose. I suppose this fits in with Agility, but there does seem to be a mental
divide between Python and Ruby people (even though they are really quite close
linguistically). To date, I'm much more in the Python camp, but I've been
deploying Rails apps at work, and I'll be delving more into Ruby as I go
forward. I have heard rumors that Zope does Monkey Patching, and this
convinces me even more. Zope has almost single handedly destroyed Python's
reputation at my place of work. Thanks Zope!
Years later, I built [my own language](/2026/02/26/building-a-programming-language-for-fun/) with a protocol system for operator dispatch -- a more structured approach to the same extensibility that monkey patching provides.
---
## Solaris Perl CPAN
- URL: https://mattmichie.com/2007/05/23/solaris-perl-cpan/
- Date: 2007-05-23
- Categories: solaris, troubleshooting, perl, system administration
Today, I was searching Google for help installing Perl modules through CPAN
using the default Solaris Perl. Sadly, my own blog was one of the search
results, and it was no help. I guess this entry is going to make the situation
even worse. So I suppose I should put some useful information:
* Solaris Perl is compiled using Sun Studio and **not** gcc
* You **must** compile Perl modules with the same compiler Perl was compiled with
* The Blastwave Perl is also uselessly compiled using Sun Studio and **not** gcc
* [Sun Studio](http://developers.sun.com/sunstudio/) is now free instead of thousands of dollars and free to download
* The [Sunfreeware](http://www.sunfreeware.com/) Perl Package is compiled **with** gcc. Go sanity!
I'm sure if you cared enough and wanted to waste time, you could download the
Sun Studio compiler just for your handful of Perl modules, or you could
download the Sunfreeware package and use gcc, the compiler that God intended
you to use. Your choice man. BTW, Sun, you suck.
---
## Jabba the Hutt, Hermaphrodite
- URL: https://mattmichie.com/2007/05/23/jabba-the-hut-hermaphrodite/
- Date: 2007-05-23
- Categories: random, humor
Today I found out that [Jabba the
Hutt](http://en.wikipedia.org/wiki/Jabba_the_Hutt) is a
[hermaphrodite](http://en.wikipedia.org/wiki/Hermaphrodite).
> A hermaphrodite is an organism that possesses both male and female sex
organs during its life.
Umm, thanks Wikipedia?
---
## Amazon S3 Backup Solution
- URL: https://mattmichie.com/2007/05/21/amazon-s3-backup-solution/
- Date: 2007-05-21
- Categories: web 2.0, unix, perl, system administration
Although I've had an [Amazon Simple Storage Service](http://aws.amazon.com/s3)
account for awhile, I haven't used it. For those of you who aren't familiar
with S3, Amazon has opened up their resources for everyday people to use. In
this instance, you can use their servers as a place to dump your files online.
Currently they charge $0.15 per gigabyte of storage used as well as a fee for
the bandwidth to transfer it back and forth.
With this setup, they take care of the administration, backup, redundancy,
troubleshooting, and the storage scales to whatever you need automatically.
I've been searching for a good backup script so I can backup all the stuff I
have running on this web-host, but most of them have been beta to this point
or a pain to setup. Today I finally installed
[Brackup](http://search.cpan.org/~bradfitz/Brackup/brackup) through CPAN,
along with all the requisite Perl modules. I've already tested a backup and
restore and it seems it will fit my needs well.
---
## 3 Dudes Mojo Launched
- URL: https://mattmichie.com/2007/05/19/3-dudes-mojo-launched/
- Date: 2007-05-19
- Categories: friends
[3dudesmojo.com](http://3dudesmojo.com/). The three dudes have launched their
new basecamp. Posting link for posterity and for Google to start crawling it.
More to come as it becomes available. Check it out.
---
## Do Lobsters Hurt?
- URL: https://mattmichie.com/2007/05/19/do-lobsters-hurt/
- Date: 2007-05-19
- Categories: random
The Canadian Parliament's Senate Standing Committee on Legal and
Constitutional Affairs has a [document
summarizing](http://www.parl.gc.ca/37/2/parlbus/commbus/senate/Com-e/lega-e/witn-e/shelly-e.htm)
all the salient points on whether lobsters feel pain. Good reading for a
Saturday morning.
---
## Ghetto Latte
- URL: https://mattmichie.com/2007/05/18/ghetto-latte/
- Date: 2007-05-18
- Categories: random
Oh Wikipedia, I do love thee. [Ghetto Latte
Entry](http://en.wikipedia.org/wiki/Ghetto_latte)
---
## Updated to Wordpress 2.2
- URL: https://mattmichie.com/2007/05/16/updated-to-wordpress-22/
- Date: 2007-05-16
- Categories: wordpress
I have upgraded everything to the latest Wordpress, installed new plugins and
updated the theme. Let me know if you see something broken, and I'll get it
fixed up. I'll probably be experimenting with some new themes and graphics
placement stuff. I have already installed some new plugins that do some semi-
intelligent caching, so that should speed things up. I also recently tuned
MySQL to have a query-cache. In combination with the Wordpress speedsups, this
site should be able to take quite a beating.
---
## Convert Floppy Image to an ISO (Solaris/Linux)
- URL: https://mattmichie.com/2007/03/19/convert-floppy-image-to-an-iso-solarislinux/
- Date: 2007-03-19
- Categories: solaris, troubleshooting, system administration
Device manufacturers still haven't caught on that floppy drives are no longer standard equipment on most modern machines. I recently came across this issue when trying to install a RAID driver on a Solaris 10 (x86) box, and solved it thusly:
```
# lofiadm -a /export/home/mmichie/tmp/ARCMSR.DD
/dev/lofi/1
# mount -F pcfs /dev/lofi/1 /mnt/floppy/
# mkisofs -R -J -o driverdisk.iso /mnt/floppy/
Total translation table size: 0
Total rockridge attributes bytes: 2428
Total directory bytes: 16384
Path table size(bytes): 122
Max brk space used 10000
278 extents written (0 MB)
```
In other words, download the raw floppy image and mount it as a loopback device. Then use mkisofs to translate it to an iso. Use your favorite CD-R burning software to burn the ISO. Install your driver disk.
This can be done similarly in Linux, the main difference will be mounting the floppy image:
```
mount -o loop driverdisk.img /mnt
```
The mkisofs command will be exactly the same as Solaris.
---
## The development, design, manufacture or production of nuclear, missiles, or
- URL: https://mattmichie.com/2007/03/05/the-development-design-manufacture-or-production-of-nuclear-missiles-or/
- Date: 2007-03-06
- Categories: random
\--- Apparently once in the iTunes EULA:
> You also agree that you will not use these products for any purposes
prohibited by United States law, including, without limitation, the
development, design, manufacture or production of nuclear, missiles, or
chemical or biological weapons.
Did they take it out? I can't find it in the latest one.
---
## I want a F-22A for Christmas
- URL: https://mattmichie.com/2007/02/26/i-want-a-f-22a-for-christmas/
- Date: 2007-02-26
- Categories: random, hardware
From a Forum I was reading today:
> The [F-22A](http://en.wikipedia.org/wiki/F-22_Raptor) has two redundant
CIPs, each powered by Intel i960 RISC microprocessor and VHSICDSP chipsets,
with fiber-optic links used for transferring data between the CIPs and
sensors. It's capable of 700 mips, which makes it roughly equivilent to a
Pentium III. A modern core 2 duo is about 10x faster. If the mips of the CIP
is determined to be a limiting factor, it will be replaced, but the new
technology is fickle as you know- I mean, who among us has not had a computer
die out from under them? The F-22A has to fight in a very hostile environment,
and has to use extremely robust industrial components that you can literally
hit with hammer blows and flash with nuclear EMP and they still keep working.
> "The only way an F-15 eagle is going to get in there and kill an F-22
Raptor, is if the Eagle has a driver with 3,000--- hours, and the raptor driver
is fresh from HOT training. Also, it would have to be 2 on 1. And the raptor
driver had to have drunk the whole night before. And he drank during the
flight. Also he passed out." - Anonymous F-15 pilot
---
## Cron error
- URL: https://mattmichie.com/2007/02/14/cron-error/
- Date: 2007-02-14
- Categories: solaris, system administration
For all you Googlers out there: If you see the following in /var/cron/log on
Solaris:
```
! bad user (root) or setgid failed (root)
```
The solution is restarting cron.
---
## Apache Logs Compress Well
- URL: https://mattmichie.com/2007/02/13/apache-logs-compress-well/
- Date: 2007-02-13
- Categories: http, unix, apache
> 1 342 625 990 / 105 314 712 = 12.748703
Yes, log files contain a lot of redundant information. I enjoy seeing over 12X
compression on a file!
---
## I went to Canada and all I got was this lousy punch card
- URL: https://mattmichie.com/2007/02/08/i-went-to-canada-and-all-i-got-was-this-lousy-punch-card/
- Date: 2007-02-08
- Categories: security, random, humor
Canada blows my mind. My Canadian friends tried to explain their magical
blinking protected left traffic lights, and I didn't quite get it, but I
remember thinking there was some logic behind it. Today, driving in Vancouver,
I came across regular blinking green traffic lights. I asked my friend about
it and after five minutes of explaining, all I got was to go forward on green,
I think. Metric continues to blow my mind, even though I spent some of my
formative years in Europe. Google Maps automatically switches to metric if
your starting position is in Canada. Nifty. Overall, the most baffling thing I
have experienced in Canada is the hotel room key. The hotel is nice, but it
has a dated feel to it. At one time, you can imagine that it was all very hi-
tech, but parts were just never upgraded. Surprisingly, one of these parts is
the hotel room key. While most hotels have chosen to go with magnetic swipe
cards, this nameless hotel has kept with punch cards. No kidding. Check it
out:  Yes, just by
posting this image, the key could probably be copied. All I could find about
this on the 'Net comes from a [1989 Usenet
posting](http://securitydigest.org/rutgers/archive/1989/09):
> There used to be only one kind of Ving card lock. Now there are two kinds,
as I discovered to my horror a while back while at a convention. The first and
possibly "classic" version is all-mechanical, while the second is optical with
an electronic controller. I did a longish article on the mechanical one back
when I got to take it apart, which I will send to anyone who asks, and since
the time of that writing discovered a few more things about it. I believe this
article was sent to this very list years ago...
I love stuff like this. These things were spoken about on a security list in
'89 with horror and how they ran across them a while back and discussed them
"years ago". Not only do these things seem trivial to copy, but seeing the
regular pattern in the holes seems to suggest you could easily reverse
engineer the algorithm and make keys for every room in the hotel given the
room number. I guess you don't need high security in a country where people
say they don't even lock their front doors. Good times.
---
## Linux Block I/O Scheduler Interview
- URL: https://mattmichie.com/2007/01/31/linux-block-io-scheduler-interview/
- Date: 2007-01-31
- Categories: linux, software engineering
Kernel Trap has a great [interview with the maintainer of the Linux Block IO
layer](http://kerneltrap.org/node/7637). He discusses some of the limitations
in the current I/O schedulers, and how they can be swapped out dynamically at
runtime. I found the following particularly informative: "Splice has a host of
applications. It can completely replace the bad hack that is sendfile(), which
is an extremely limited zero copy interface for sending a file over the
network. The neat thing about using pipes as the buffers, is that you have a
known interface to work with and a way to tie things together intuitively. A
good and easy to understand example is a live TV setup, where you have a
driver for your TV encoder (lets call that /dev/tvcapture) and a driver for
your TV decoder (lets call that /dev/tvout. Say you want to watch live TV
while storing the contents to a file for pausing or rewind purposes, you could
describe that as easy as:"
```bash
$ splice-in /dev/tvcapture | splice-tee out.mpg | splice-out /dev/tvout
```
"The first step will open /dev/tvcapture and splice that file descriptor to
STDOUT. The second will duplicate the page references from the STDIN pipe,
splicing the first to the output file and splicing the second to STDOUT.
Finally, the last step will splice STDIN to a file descriptor for /dev/tvout.
The data never needs to be copied around, we simply move page references
around inside the kernel. It's like building with Lego blocks :-)"
---
## Entertaining like a Canadian Diplomat
- URL: https://mattmichie.com/2007/01/23/entertaining-like-a-canadian-diplomat/
- Date: 2007-01-23
- Categories: random, humor
I recently ran across some rather [amusing Amazon
reviews](http://www.amazon.com/gp/cdp/member-reviews/A2752XIGJY2YH6/) from
some madman genius. Here is a sample:
> Margaret Dickenson is the wife of a Canadian diplomat. I learned from her
book the hierarchical placement of guests around the dinner table that
diplomats use. The most important sits to the right of the host, the second
most important to the left. I have used this dinner table tactic to divide and
conquer my guests, making them jealous of each other for my attention. I had
Jeremy Saltmaven over for vermouth the other day and made him sit to my left,
leaving a vacancy to the right. With this subtle trick I suspect I probably
let Jeremy Saltmaven know he needs to give me more finery to secure my favour.
Margaret Dickenson also explores dinner party themes, but this is where I went
soft on the book. For my Hieronymus Bosch themed party, I assembled a nice
costume from one of Bosch's panels. I heard the first knock at the door, and
hurriedly threw on my bird mask, mounted a copper cauldron on my head, and
leapt up onto my stilts. In the process of taking my first step I spilled
headfirst into the front door, misjudging the weight imbalance of the cauldron
on my neck. My guests later told me they first heard some shuffling, the
single sonorous knell as of a large bell, and then nothing. After waiting
patiently on the porch for 5 minutes, it took them a few moments longer than
normal to open the front door, heaving it, unwittingly shifting my dumped
motionless body across the vestibule floor. So, Margaret Dickenson, that's why
I can't give this book anything higher than 3 stars.
---
## Oracle Install Buttons Don't Work
- URL: https://mattmichie.com/2007/01/16/oracle-install-buttons-dont-work/
- Date: 2007-01-16
- Categories: troubleshooting, oracle
Today, I was attempting to uninstall/upgrade Oracle Enterprise Manager 10g on
a Solaris 8 Sparc server, and spent well over an hour trying to get the
display exported properly to my MacBook Pro. First, the OSX X11 component
doesn't seem to play nicely with the Oracle 'Universal' Installer, so I booted
up Red Hat Enterprise Linux in a Parallels Desktop and used ssh to export the
display. Then, everything came up fine, but I couldn't click any of 'Next',
'Installed Products', or even 'Help'. It makes me wonder about the rest of
Oracle when the installer buttons don't work right, I mean that's so hard to
test and all.... Anyway, after searching the web the only recommendations I
could find for this problem (going back at least 6 years) were:
* Turn off your numlock key (no, seriously)
* Try a different window manager
* Type: `export LANG=C` at the shell prompt before launching runInstaller
After trying all of these, including booting into Ubuntu, nothing was working.
Out of desperation, I booted into Knoppix, exported the display and everything
worked the first try. Ubuntu and RHEL both use Gnome and Knoppix uses KDE, so
I guess the 'try a different window manager' is the solution. Die Oracle, Die.
Hope this helps someone Googling out there.
---
## Cyclomatic complexity of Django
- URL: https://mattmichie.com/2007/01/12/cyclomatic-complexity-of-django/
- Date: 2007-01-12
- Categories: python, software engineering
Gary Wilson has written up a post detailing the [cyclomatic complexity of
Django](http://gdub.wordpress.com/2006/07/09/cyclomatic-complexity-of-django/)
(the Python web dev framework).
Wikipedia defines [cyclomatic
complexity](http://en.wikipedia.org/wiki/Cyclomatic_complexity) as:
> Cyclomatic complexity is a software metric (measurement) in computational
complexity theory. It was developed by Thomas McCabe and is used to measure
the complexity of a program. It directly measures the number of linearly
independent paths through a program's source code. The concept, although not
the method, is somewhat similar to that of general text complexity measured by
the Flesch-Kincaid Readability Test. Cyclomatic complexity is computed using a
graph that describes the control flow of the program. The nodes of the graph
correspond to the commands of a program. A directed edge connects two nodes if
the second command might be executed immediately after the first command.
It isn't often that you see software engineering metrics applied to open
source projects. I wonder why that is?
---
## Snow in Seattle (again)
- URL: https://mattmichie.com/2007/01/10/snow-in-seattle-again/
- Date: 2007-01-11
- Categories: seattle

Yes, it is snowing in Seattle, again. People are already freaking out. Should
be fun tomorrow.
---
## I wonder if we can adopt him
- URL: https://mattmichie.com/2007/01/02/i-wonder-if-we-can-adopt-him/
- Date: 2007-01-03
- Categories: random
> Hello Everyone, This morning a crazy man wearing tan pants, tan shirt,
baseball cap, and sneakers bolted through security and managed to get up the
elevators before anyone could stop him. He has been raiding the first aid kits
mounted in the hallways, and pulling the blue phones off the walls. If you see
this man please contact security and let me know about it. If you are going to
be the last person to leave of the day please check your room to insure that
you really are the last person, then double check the lock. Thank you
---
## Intimate Strangers
- URL: https://mattmichie.com/2006/12/15/intimate-strangers/
- Date: 2006-12-16
- Categories: random, humor
A BBC photographer embarked on a [project to talk to, "... people you see
every day but never
meet](http://news.bbc.co.uk/2/hi/uk_news/magazine/6176235.stm). Urban living
is full of these close encounters where we never make contact."
Tony, from London, had the following to say, _"Oh, stop it, you touchy-feely
freak! I live in London precisely because people here are NOT overly intimate.
I like the fact that I walk amongst strangers, I love the fact I am not
subject to tedious drivel from people who happen to impinge upon my geography.
If you want to know your neighbours, go live up North or something - stop
assuming we all want to be like you."_
---
## Evil Genius
- URL: https://mattmichie.com/2006/12/14/evil-genius/
- Date: 2006-12-15
- Categories: random
```
<@ebnf> "I made a program that connects to the outlook calendar database,
checks if a meeting takes place on any of the 6 floors at lunch
and then alerts me of the meetings ending so that I can rush to
the breakroom on that floor and get at all the food before anyone
else can. Those sandwiches can be really tasty."
<@ebnf> that guy is genius
```
---
## Cheap Mac Software
- URL: https://mattmichie.com/2006/12/14/cheap-mac-software/
- Date: 2006-12-14
- Categories: apple, software, osx
I finally broke down and bought one of the [Mac
Heist](http://www.macheist.com/) bundles for $49. Although there has been
[some grumbling](http://daringfireball.net/2006/12/iniquities_of_the_selfish)
that Mac Heist is ripping off indie software developers, they entered into the
deal of their own volition and it lets users get software at a good price. A
portion of the sale also goes to charity. With any luck,
[Textmate](http://macromates.com/) will get unlocked (I have a license at
work, but not for my personal laptop).
* * *
Links to other Cheap or Free Mac Software:
* [Macgamesandmore.com](http://www.macgamesandmore.com/)
* [Freemacware.com](https://web.archive.org/web/20250828122910/http://freemacware.com/)
* [Indispensable Mac OS X Software](https://web.archive.org/web/20081023121933/http://madsenblog.dk:80/?page_id=11)
* [OSX Inventories](https://web.archive.org/web/20170815022935/http://wiki.43folders.com:80/index.php/OS_X_Inventories)
* [Nifty OS X apps list](https://web.archive.org/web/20110825182032/http://generaldisarray.wordpress.com:80/2006/02/11/nifty-os-x-apps-list/)
* [The Top Ten Most Beautiful OS X Apps](https://web.archive.org/web/20111222192411/http://phillryu.com:80/2006/07/03/the-top-ten-most-beautiful-os-x-apps/)
* [Essential Mac OS X Applications...](http://macspecialist.org/content/articles/essential_apps/)
* [The Top 100 OSX Applications](http://www.creationrobot.com/index.php?p=728)
* [Top 10 Shareware Apps of 2005](http://maczealots.com/articles/shareware-2005/)
* [Taco HTML Edit for Mac OS X](http://tacosw.com/main.php)
---
## Java 6 is out
- URL: https://mattmichie.com/2006/12/12/java-6-is-out/
- Date: 2006-12-12
- Categories: java
I'm still waiting for ~~"hack" Java~~ hacked javva (don't ask, long story),
but Java SE 6 actually has some [pretty sweet
features](http://blogs.sun.com/dannycoward/entry/java_se_6_top_ten). I've been
impressed with what Sun is doing lately, they are making the right moves. I'm
excited to see what the JRuby guys do with a GPL Java, with any luck they'll
make the JVM much more accommodating to dynamic languages, which includes my
favorite Python (Jython)
---
## Seattle Job Opportunities
- URL: https://mattmichie.com/2006/10/25/seattle-job-opportunities/
- Date: 2006-10-25
- Categories: random, seattle
Wes over at [brokenbuild.com](http://www.brokenbuild.com) has posted two jobs
that have opened at his company:
* Java Software Engineer
* [White-box QA Engineer (SDET)](http://www.brokenbuild.com/blog/2006/10/25/now-hiring-white-box-qa-engineer-sdet/)
If you, or someone you know is interested, send them his way. The jobs are
located in Seattle, WA.
---
## System Administration as Science
- URL: https://mattmichie.com/2006/10/21/system-administration-as-science/
- Date: 2006-10-21
- Categories: system administration, philosophy
One goal in my day to day work is to quantify events in a systemic way. System
administrators are in a unique position to view the network, servers, clients,
software and the ways that they interact. While good software development
depends on abstracting away as many things as you can, good system
administration depends on understanding how the layers interact.
For example, a good developer will abstract away the type of database he is
connecting to. There is a small shim that can be adjusted so that the program
runs with no changes on Oracle or PostgreSQL, for example. The Java language
itself depends on abstracting away the entire computer by implementing a
virtual machine that acts consistently over differing operating systems, or
even different CPU architectures. A Java programmer doesn't care that he is
running on Solaris Sparc or Linux MIPS or Windows X86, or whether the CPU is
big-endian or little-endian.
However, a good system administrator does care, and should know the
difference. System administration is about removing layers to solve problems
that occur when the abstractions break down. Joel Spolsky refers to this as
["The Law of Leaky
Abstractions."](http://www.joelonsoftware.com/articles/LeakyAbstractions.html)
> All non-trivial abstractions, to some degree, are leaky.
Some have compared system admins to the plumbers of the IT world. Like
plumbing, the effects of system administration disappear when everything is
working. Only when things start to leak, and shit starts to hit the fan
(literally or figuratively) does it become noticeable. There seems to be one
breed of system administrator that thrives on fixing problems. Imagine the
server going down, and the mayor frantically paging the heroic sysadmin with
the Bat Signal.
Our hero drops into the storm with his combat boots and trusty Leatherman,
typing arcane commands, drinking Mountain Dew and cursing at everyone around
him. Suddenly, joyous shouts erupt as the users discover their work can
continue. Everyone cheers the SysOp, while he struts back to his Bat Cave,
until the next Bat Time, at the same Bat Channel.
How does one measure the performance of the lone rogue sysadmin troubleshooter
against another that has carefully scheduled downtime, and the system "just
works"? Is the system with less downtime more reliable because of the work of
the system administrator, or are they just lucky? How does one compensate the
hero who fixes every problem solved, verses someone that never demonstrates
this ability because the system never goes down?
What of the sysadmin who has unreliable hardware or buggy software forced on
him by upper management or customer demand? A lot of companies want to measure
metrics like uptime, but is it even possible to properly measure 99.99%
uptime, and does that have any correlation to the person running the system?
99.9% uptime amounts to approximately 42 minutes of downtime in a single
month, but many of the tools used to measure the availability of the system
have a minimum time resolution of 1 minute. For example, you want to test that
your website is up and available to your users, so you write a script that
makes an HTTP request and returns the result. It sends you e-mail if it
doesn't get a response. However, the standard UNIX cron utility that schedules
tasks can only run once per minute.
With a CPU running millions of instructions per second and servers typically
having multiple processors, one minute is too long. But, if we magically
invent a utility that can schedule and execute your script once per second,
suddenly your server is overwhelmed by these requests and your script itself
brings the system to a halt. What if you have a process that crashes and
restores itself in less time than your monitoring tool checks? You wouldn't
consider a server that crashed every 30 seconds reliable, but most monitoring
software can't tell the difference.
Recently, I upgraded our company's e-mail server because it was crashing under
an ever increasing load of spam. The new software was more efficient and no
longer crashed, however this meant it was also more efficient at delivering
spam. I was happy because I wasn't getting pages to restart the mail server,
but the average user actually saw more spam in their in-boxes. It is difficult
to explain to the average person who just wants to read and send e-mail how
complex the system is and how upgrading the software was the right thing to
do.
Most people don't understand that e-mail isn't guaranteed instant delivery,
and that mail servers will attempt redelivery if it can't get through to a
server. In our case, when the server was flooded by spammers, all the
legitimate e-mail eventually got through while some spam probably didn't
(spammers typically won't retry delivery when they can't connect). Now, both
spam and ham get through equally quick. Of course, we are working on ways to
reduce the spam, but it is an almost intractable problem when you have
thousands of people around the world working day and night to devise clever
ways to deliver their junk.
One thing that is important from a sysadmin point of view is to document and
explain the problem both upwards to management and downwards to the clients
and customers. To quantify the problem I'm using log analysis tools to graph
the problem over time. Now that I have hard data, I can start to formalize the
problem and test the validity of various hypotheses to solve it.
The challenge, as with uptime statistics is to find numbers that are accurate
without introducing a sort of Heisenburg effect from monitoring and then
presenting the numbers in a way so that the people who depend on the sysadmin
to get their work done can evaluate whether that person is doing a good job or
not. I'm not sure there is any magic bullet, but it is clear to me that
applying some science to the art of system administration can aid in
communication, diagnosis and ultimately problem resolution.
It is an area I will be expending more brain slices on in the future and on
this blog.
---
## Great Java RFE Bug
- URL: https://mattmichie.com/2006/10/16/great-java-rfe-bug/
- Date: 2006-10-17
- Categories: java, programming, psychology
I love snarky bug reports for some reason. It cracks me up that it took 8
years for Sun to add password prompting to Java. The users increasingly
becoming irate in the bug reports is awesome. I wish the programmers would
have responded back in a big flame war. I can only imagine what they were
saying inside Sun. Good stuff.
[Improved interactive console I/O (password prompting, line
editing)](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4050435)
---
## Yet More Shelob Hacking
- URL: https://mattmichie.com/2006/10/15/yet-more-shelob-hacking/
- Date: 2006-10-15
- Categories: http, programming
I've been fixing some on my web server again, for fun. Last weekend, I refactored a lot of code, added dynamic mime typing and CGI support!
I was going to continue fleshing it out today, but I had to do even more refactoring to clean up some messy code paths. I broke the `Http::sendFile()` method into several new ones and moved HTTP/1.1 keep-alive handling into a more central location instead of just tacked on to the first place that it worked.
One thing that is driving me slightly insane is that there appears to be a tiny memory leak. I can't figure out where it is happening since I eliminated almost all dynamic allocations in the stack. As I wrote that sentence, I think I figured out where it could be coming from, but I'll need to rewrite some more code to fix it. It is so small, you don't start to notice it until you get at least 1,000 requests.
Overall, I'm happy with the design so far. This is my first C++ program and my first serious "server" program. I didn't do any real upfront design except for drawing on past experience and my gut. I've added a number of features and it has been extendable.
OOP purists would probably frown on it, but I'm using the subset of C++ and OOP in general that makes sense to me and is practical for what I'm doing. Is there a cleaner way? Likely *shrug*. I'm getting to the point where a couple of patterns probably make sense. This program is growing organically, but under a tight enough constraint that it isn't turning into a mess (at least not yet).
The other thing that starts making sense is Unit Testing. I've been doing more refactoring than I have been adding new features and it would be awesome to be able to run a test suite and know that I haven't broken anything. I'm not even really sure where to begin on that, but it is obvious that Shelob is becoming more of a "real" program and less of a toy. A couple more good weekends and it would actually be semi-useful.
---
## Simple unix tools in Haskell
- URL: https://mattmichie.com/2006/09/22/simple-unix-tools-in-haskell/
- Date: 2006-09-22
- Categories: programming, unix
> [Simple unix tools written in
Haskell](http://haskell.org/haskellwiki/Simple_unix_tools).
>
> This is intended as a beginners tutorial for learning Haskell from a "Lets
just solve things already!" point of view. The examples should help give a
flavour of the beauty and expressiveness of Haskell programming.
Twenty years later, I wrote [an entire shell in Go](/2026/03/15/writing-a-shell-in-go/) -- with structured data pipes instead of plain text.
---
## Python 2.5 Goes Final
- URL: https://mattmichie.com/2006/09/19/python-25-goes-final/
- Date: 2006-09-19
- Categories: python
---
## Python's Default Web Layer
- URL: https://mattmichie.com/2006/08/27/pythons-default-web-layer/
- Date: 2006-08-28
- Categories: python, django, turbogears
Apparently Django might become the defacto Python framework. Django is pretty
good, but I'm kind of surprised that Turbogears didn't get the nod.
[Link](http://www.cmlenz.net/blog/2006/08/the_python_web_.html)
---
## Qwest won't commit to Seattle fiber, doesn't want city to do it
- URL: https://mattmichie.com/2006/08/15/qwest-wont-commit-to-seattle-fiber-doesnt-want-city-to-do-it/
- Date: 2006-08-15
- Categories: internet, seattle
> Fiber isn't coming anytime soon, according to Qwest CEO Dick Notebaert.
That's the answer Notebaert gave a Seattle Times reporter in a recent
interview, and it looks as though it will echo throughout Qwest's service
region. Although the telecom has built some very small FTTP and FTTN networks
for specific subdivisions, it has shown little interest in the kind of
widescale deployment its larger brethren are undertaking.
>
> Seattle is anxious to get fiber one way or another, and last year a city
task force recommended it develop its own fiber network in order to remain
competitive. Predictably, Qwest wasn't too impressed. In fact, it was
downright critical of the task force's report.
Via [Arstechnica](http://arstechnica.com/news.ars/post/20060814-7496.html)
---
## SR-71 Break-Up
- URL: https://mattmichie.com/2006/07/30/sr-71-break-up/
- Date: 2006-07-30
- Categories: random
> "I tried to rotate the parachute and look in other directions. But with one
hand devoted to keeping the face plate up and both hands numb from high-
altitude, subfreezing temperatures, I couldn't manipulate the risers enough to
turn. Before the breakup, we'd started a turn in the New Mexico-Colorado-
Oklahoma-Texas border region. The SR-71 had a turning radius of about 100 mi.
at that speed and altitude, so I wasn't even sure what state we were going to
land in. But, because it was about 3:00 p.m., I was certain we would be
spending the night out here."
[SR-71 Blackbird Break-up](http://www.alexisparkinn.com/sr-71_break-up.htm)
---
## Cogent Confabulation
- URL: https://mattmichie.com/2006/07/29/cogent-confabulation/
- Date: 2006-07-30
- Categories: artificial intelligence
> Adults possess billions of individual items of knowledge, and the rate of
acquisition must exceed one item per second, which is totally inconsistent
with current views of human nature, said the mathematician, who is affiliated
with UCSD s Institute for Neural Computation, as well as the California
Institute for Telecommunications and Information Technology. How many times
has your child come home from school and, when asked what he or she learned
today, said nothing. But that s not true. They have probably accumulated
hundreds of thousands of items of knowledge, and when we sleep, we consolidate
that knowledge. No wonder we need eight hours of sleep!
[Cogent Confabulation](http://www.jefallbright.net/node/3300) Interesting
theory, heard about it for the first time today. Will have to look into this
further, sounds promising!
---
## Server Room Gets Slimed
- URL: https://mattmichie.com/2006/07/28/server-room-gets-slimed/
- Date: 2006-07-28
- Categories: random, hardware, humor
From a forum I frequent: "what a pleasant surprise this morning. the floor
above us was putting down some floor leveler and it just happened to leak
right onto our rack, covering the whole thing is a cement like shell. luckily
everything is still up and running. oh happy day, oh happy day"
---
## Terrorists as Pirates
- URL: https://mattmichie.com/2006/07/28/terrorists-as-pirates/
- Date: 2006-07-28
- Categories: politics
The Legal Affairs magazine has a great [article comparing terrorists to
pirates in the eyes of the law](http://www.legalaffairs.org/issues/July-
August-2005/feature_burgess_julaug05.msp). One of the major obstacles has been
finding a common definition that works under international law. As the author
points out, in order to eradicate pirates, nations had to come together and
recognize them as a special threat to all states.
> "TO UNDERSTAND THE POTENTIAL OF DEFINING TERRORISM as a species of piracy,
consider the words of the 16th-century jurist Alberico Gentili's _De jure
belli_: "Pirates are common enemies, and they are attacked with impunity by
all, because they are without the pale of the law. They are scorners of the
law of nations; hence they find no protection in that law." Gentili, and many
people who came after him, recognized piracy as a threat, not merely to the
state but to the idea of statehood itself. All states were equally obligated
to stamp out this menace, whether or not they had been a victim of piracy.
This was codified explicitly in the 1856 Declaration of Paris, and it has been
reiterated as a guiding principle of piracy law ever since. Ironically, it is
the very effectiveness of this criminalization that has marginalized piracy
and made it seem an arcane and almost romantic offense. Pirates no longer
terrorize the seas because a concerted effort among the European states in the
19th century almost eradicated them. It is just such a concerted effort that
all states must now undertake against terrorists, until the crime of terrorism
becomes as remote and obsolete as piracy."
---
## Cathedral of Santa Eulalia
- URL: https://mattmichie.com/2006/07/19/cathedral-of-santa-eulalia/
- Date: 2006-07-20
- Categories: random

The Cathedral of Santa Eulalia. Makes me want to build something beautiful.
---
## Celebrated Non-Photography Day
- URL: https://mattmichie.com/2006/07/17/celebrated-non-photography-day/
- Date: 2006-07-18
- Categories: random
It was a lot of work, but it was sure worth while.
[Link](http://www.nonphotographyday.com/).
---
## Psychology of Booba and Kiki
- URL: https://mattmichie.com/2006/07/15/psychology-of-booba-and-kiki/
- Date: 2006-07-15
- Categories: random, psychology

In a psychological experiment first designed by [Wolfgang K
hler](http://en.wikipedia.org/wiki/Wolfgang_K%C3%B6hler "Wolfgang K hler" ),
people are asked to choose which of these shapes is named **Booba** and which
is named **Kiki**. Try it yourself, assign the name to each shape and then
compare your results [here](http://en.wikipedia.org/wiki/Image:BoobaKiki.png).
---
## Why Functional Programming Matters
- URL: https://mattmichie.com/2006/07/15/why-functional-programming-matters/
- Date: 2006-07-15
- Categories: programming
* [Why functional programming matters](http://www.math.chalmers.se/%7Erjmh/Papers/whyfp.html)
* [Brief discussion on Lambda - The Ultimate](http://lambda-the-ultimate.org/classic/message10106.html)
* [The next mainstream programming language - A game developer's perspective](http://www.st.cs.uni-sb.de/edu/seminare/2005/advanced-fp/docs/sweeny.pdf)
* [Gentle Introduction to Haskell 98](http://www.haskell.org/tutorial/index.html)
* [Functional Programming](http://en.wikipedia.org/wiki/Functional_programming)
* [Lambda Calculus](http://en.wikipedia.org/wiki/Lambda_calculus)
---
## Java theory and practice
- URL: https://mattmichie.com/2006/07/14/java-theory-and-practice/
- Date: 2006-07-15
- Categories: java, programming
IBM DeveloperWorks has a great article on the [details of the JVM garbage
collector](http://www-128.ibm.com/developerworks/java/library/j-jtp09275.html),
including some neat foreshadowing of escape analysis that will be present in
Java Mustang.
> "The Java language does not offer any way to explicitly allocate an object
on the stack, but this fact doesn't prevent JVMs from still using stack
allocation where appropriate. JVMs can use a technique called _escape
analysis_, by which they can tell that certain objects remain confined to a
single thread for their entire lifetime, and that lifetime is bounded by the
lifetime of a given stack frame. Such objects can be safely allocated on the
stack instead of the heap. Even better, for small objects, the JVM can
optimize away the allocation entirely and simply hoist the object's fields
into registers."
---
## Solaris Secure by Default Design
- URL: https://mattmichie.com/2006/07/13/solaris-secure-by-default-design/
- Date: 2006-07-14
- Categories: security, solaris
Coming from [OpenBSD](http://openbsd.org) background, installing Solaris can
be an eye opening experience. There are many services enabled and listening to
the world; luckily for Sun, most Solaris boxes are running on Sparc. Linux
used to do the same thing, up until Red Hat starting to get a reputation for
getting owned. Finally, there is some sanity at Sun and the Open Solaris
project has some design documents on what they are working toward:
[](http://www.opensolaris.org/os/community/security/projects/sbd/sbd_design/)
[
](http://www.opensolaris.org/os/community/security/projects/sbd/sbd_design/)[Secure
by Default Design
Specification](http://www.opensolaris.org/os/community/security/projects/sbd/sbd_design/)
SBD is available in [Nevada](http://www.opensolaris.org/os/community/onnv/)
build 42 and greater.
---
## How to End Poverty
- URL: https://mattmichie.com/2006/07/12/how-to-end-poverty/
- Date: 2006-07-13
- Categories: politics
Bono, of U2 fame has asked Yahoo Questions, "[What can we do to make poverty history](http://answers.yahoo.com/question/index;_ylt=ApS_ry2VsiLeaDfq1JQxOO3py6IX?qid=20060706201547AAy10c8)?"
The first thing that struck me, was that the entire question is framed wrong. Instead of asking how to end poverty, ask, "How do we make the whole world richer (and not leave anyone behind)?" The first question immediately brings to mind soup kitchens, donations and starving kids in Africa, whereas the second one makes me imagine Europe, Japan, and South Korea destroyed by wars and rebuilding their entire economies in a couple of decades.
In order to end poverty, the governments of most of the affected countries would have to change. Corruption, instability, and wars are not good growth mediums to build riches.
On the other hand, Africa is saddled with diseases that are destroying the entire population. Solving AIDS and Malaria is probably the first step on that journey. They can't start boot-strapping their countries until they start living longer than a median of 30-something.
Once disease is solved, there are some deep rooted cultural issues that are holding back many countries in poverty. What makes South Korea rebound from occupation, war, military dictatorships, and being surrounded by hostile nations to becoming one of the Asian Tigers and one of the most wired nations in the world?
For fun, compare and contrast North Korea with South Korea. Obviously the people in both countries have roughly the same potential for success, yet North Korea is a world pariah and many of the people are imprisoned in gulags or starving.
The U.S.A. through [the Marshall Plan](http://usinfo.state.gov/usa/infousa/facts/democrac/57.htm), provided the following for war torn Europe after World War II:
> The United States offered up to $20 billion for relief, but only if the European nations could get together and draw up a rational plan on how they would use the aid. For the first time, they would have to act as a single economic unit; they would have to cooperate with each other. Marshall also offered aid to the Soviet Union and its allies in eastern Europe, but Stalin denounced the program as a trick and refused to participate. The Russian rejection probably made passage of the measure through Congress possible.
>
> The Marshall Plan, it should be noted, benefited the American economy as well. The money would be used to buy goods from the United States, and they had to be shipped across the Atlantic on American merchant vessels. But it worked. By 1953 the United States had pumped in $13 billion, and Europe was standing on its feet again. Moreover, the Plan included West Germany, which was thus reintegrated into the European community. (The aid was all economic; it did not include military aid until after the Korean War.)
I believe that the Marshall Plan was one of the greatest things that America did in the 20th century. However, a similar plan for Africa would fail miserably due to corruption in the governments of Africa.
Even before Africa, how do we provide Mexico with a similar path to economic success? The whole immigration debate seems to miss the fact that if Mexico was as rich as Canada, we wouldn't have any immigration problems. Anyone who has been to a border city like El Paso, Texas and stared over the wall to Mexico has a good appreciation of why people immigrate to the United States. Almost any rational person would do the same, at whatever the cost.
I wonder if anyone has outsourced Spanish tech support to Mexico. Perhaps one thing that Mexico could do is start switching their schools to English and try to compete with India for some of that business. They are on the same time zone and for whatever reason, Americans seem to find a Spanish accent more pleasant than an Indian one. However, yet again I think that corruption in the government is holding down the entire country.
Perhaps to solve poverty, we need to solve corruption first. You could donate all the money you like, but if all of it is intercepted by warlords or despots, you've done no good, and in fact you've made things worse, because you are keeping these dictators in power.
So bottom line, solve culture and corruption and we have a chance to solve poverty. Do neither and just donate billions of dollars and make the situation worse.
*PS, the people who are saying prayer obviously haven't heard the saying, "When your boat springs a leak, pray to God, but row to shore."*
---
## Microsoft's Intentional Ignorance of Other Operating Systems
- URL: https://mattmichie.com/2006/07/11/microsofts-intentional-ignorance-of-other-operating-systems/
- Date: 2006-07-11
- Categories: windows, microsoft, unix
I'm really happy that Microsoft employees are blogging more. Though I miss [Robert Scoble](http://scobleizer.wordpress.com/). Microsoft really lost a lot of public relations points when Scoble left.
Today, I came across a post by [Raymond Chen](http://blogs.msdn.com/oldnewthing/), one of the great Microsoft guys that keeps new versions of Windows compatible with older applications. Truly, compatibility is a heroic task, one that most programmers don't want to deal with.
However in recent discussions on Windows blindly overwriting the master boot record (and in the process screwing everyone with alternate operating systems), he says:
> In the discussions following [why Windows setup lays down a new boot sector](http://blogs.msdn.com/oldnewthing/archive/2005/12/20/505887.aspx), some commenters suggested that Windows setup could detect the presence of a non-Windows partition as a sign that the machine onto which the operating system is being installed belongs to a geek. In that way, the typical consumer would be spared from having to deal with [a confusing geeky dialog box that they don't know how to answer](http://blogs.msdn.com/oldnewthing/archive/2004/04/26/120193.aspx).
>
> The problem with this plan is that not everybody with a non-Windows partition type is necessarily a geek. Many OEM machines ship with a hard drive split into two partitions, one formatted for Windows and the second a small non-Windows partition to be used during system diagnostics and recovery. The presence of this small non-Windows partition is typically not well-known, and it comes into play only when you boot from the manufacturer's "system recovery CD".
I would challenge Raymond Chen to install Linux, because this problem isn't difficult to solve and has been solved by every major Linux distribution years ago.
This has been one of my biggest all time gripes with Microsoft. They put on blinders and ignore everything not invented at Microsoft (except when they steal Apple's GUI, but that's another entry).
I've reproduced the common system partition types that Linux fdisk knows about. If Microsoft took this list and detected the top ten most common ones, they could solve this problem. If they decided to spend another couple hours implementing all of them, they would make installing Vista a breeze for those of us who know there is more than one Microsoft way.
However, they won't because why would Microsoft care if they overwrite your grub/lilo boot record? That just means you will only be using Windows, right? I think they forget that I am a customer too, and I don't appreciate it when a product destroys my setup.
```
0 Empty 1e Hidden W95 FAT1 75 PC/IX be Solaris boot
1 FAT12 24 NEC DOS 80 Old Minix bf Solaris
2 XENIX root 39 Plan 9 81 Minix / old Lin c1 DRDOS/sec (FAT-
3 XENIX usr 3c PartitionMagic 82 Linux swap c4 DRDOS/sec (FAT-
4 FAT16 <32M 40 Venix 80286 83 Linux c6 DRDOS/sec (FAT-
5 Extended 41 PPC PReP Boot 84 OS/2 hidden C: c7 Syrinx
6 FAT16 42 SFS 85 Linux extended da Non-FS data
7 HPFS/NTFS 4d QNX4.x 86 NTFS volume set db CP/M / CTOS / .
8 AIX 4e QNX4.x 2nd part 87 NTFS volume set de Dell Utility
9 AIX bootable 4f QNX4.x 3rd part 8e Linux LVM df BootIt
a OS/2 Boot Manag 50 OnTrack DM 93 Amoeba e1 DOS access
b W95 FAT32 51 OnTrack DM6 Aux 94 Amoeba BBT e3 DOS R/O
c W95 FAT32 (LBA) 52 CP/M 9f BSD/OS e4 SpeedStor
e W95 FAT16 (LBA) 53 OnTrack DM6 Aux a0 IBM Thinkpad hi eb BeOS fs
f W95 Ext'd (LBA) 54 OnTrackDM6 a5 FreeBSD ee EFI GPT
10 OPUS 55 EZ-Drive a6 OpenBSD ef EFI (FAT-12/16/
11 Hidden FAT12 56 Golden Bow a7 NeXTSTEP f0 Linux/PA-RISC b
12 Compaq diagnost 5c Priam Edisk a8 Darwin UFS f1 SpeedStor
14 Hidden FAT16 <3 61 SpeedStor a9 NetBSD f4 SpeedStor
16 Hidden FAT16 63 GNU HURD or Sys ab Darwin boot f2 DOS secondary
17 Hidden HPFS/NTF 64 Novell Netware b7 BSDI fs fd Linux raid auto
18 AST SmartSleep 65 Novell Netware b8 BSDI swap fe LANstep
1b Hidden W95 FAT3 70 DiskSecure Mult bb Boot Wizard hid ff BBT
1c Hidden W95 FAT3
```
---
## Microsummary, Woot!
- URL: https://mattmichie.com/2006/07/10/microsummary-woot/
- Date: 2006-07-11
- Categories: mozilla
> "Microsummaries are regularly-updated succinct compilations of the most
important information on web pages. They are compact enough to fit in the
space available to a bookmark label, provide more useful information about
pages than static page titles, and are regularly updated as new information
becomes available."
[Woot.com has added support for Microsummaries](http://www.melez.com/mykzilla/2006/07/wootcom-provides-microsummary.html). I can't wait until someone like Ebay adds support for
these! Great feature in Bon Echo.
---
## Mayflies so thick they appeared on radar as a rainstorm
- URL: https://mattmichie.com/2006/07/10/mayflies-so-thick-they-appeared-on-radar-as-a-rainstorm/
- Date: 2006-07-10
- Categories: random

> A record hatch of mayflies in LaCrosse, Wisconsin was so thick that it
showed up on local weather radar as a rainstorm.
[Link](http://www.jsonline.com/story/index.aspx?id=457479)
---
## Bacon of the Month Club
- URL: https://mattmichie.com/2006/07/07/bacon-of-the-month-club/
- Date: 2006-07-07
- Categories: random
> [The Bacon of the Month
Club](https://web.archive.org/web/20170323193221/http://mgrsti5395q.seamlesstech.biz/Merchant/2005TGP/BOM%20pages/bom.html)
is the greatest of all gifts. I m not making that up. I get calls from
customers all the time that tell me this. In my humble opinion no other club
in the universe gives you as much pleasure and sheer delight as The Bacon of
the Month Club. The Bacon of the Month Club is the go-to gift for that person
in your life who loves bacon, who has everything or who has very little. Join
for yourself. Give yourself the gift of bacon.
I have no idea what's going on with that sign. I found it on Google. I guess
it has something to do with no bacon surfing allowed. You make your own
conlusions. Please don't sign me up for the Bacon of the Month Club.
---
## Protip
- URL: https://mattmichie.com/2006/07/07/protip/
- Date: 2006-07-07
- Categories: apple
> Want the fastest way to put your Mac right into a deep, sleepy-bear
hibernation-like sleep (no whirling fan, no dialogs, no sound nuthin just
fast, glorious sleep). Just press Command-Option and then hold the Eject
button for about 2 seconds and Zzzzzzzzzzzzzz. It doesn t get much faster than
that.
---
## Python vs Perl vs Ruby vs PHP vs Java
- URL: https://mattmichie.com/2006/07/07/python-vs-perl-vs-ruby-vs-php-vs-java/
- Date: 2006-07-07
- Categories: java, python, ruby, programming, perl, php
* [Executable line noise? Damn right (at least in this case)](http://blog.delaguardia.com.mx/index.php?op=ViewArticle&articleId=49&blogId=1)
* [Python vs __](http://www.jrandolph.com/blog/?p=32)
* [ python2.5. faster startup, better memory use, faster.](http://renesd.blogspot.com/2006/07/python25-faster-startup-better-memory.html)
* [Python Web Developer Appliance](http://www.vmware.com/vmtn/appliances/directory/289)
* [Mozilla Python Sidebar](http://projects.edgewall.com/python-sidebar/)
* [How Dynamic is too Dynamic](http://www.voidspace.org.uk/python/weblog/arch_d7_2006_07_01.shtml#e381)
---
## Using PowerShell through SSH
- URL: https://mattmichie.com/2006/07/03/using-powershell-through-ssh/
- Date: 2006-07-03
- Categories: microsoft
**Update (July 2026):** Twenty years later, the begging in this post finally paid off in full. OpenSSH ships in Windows, sshd comes preinstalled on Windows Server 2025, and PowerShell 7 does native SSH remoting. The modern setup, including key auth and the `administrators_authorized_keys` gotcha, is covered in [Using PowerShell over SSH, Twenty Years Later](/2026/07/11/powershell-over-ssh-twenty-years-later/). What follows is the original Cygwin recipe, preserved as history.
---
## Original 2006 Article
*The following is the original article from July 2006, preserved for historical context. At the time, PowerShell was brand new, Windows had no SSH support, and Cygwin was the only way to make this work.*
### Introduction
> Windows PowerShell is a new command-line shell and task-based scripting technology that provides comprehensive control and automation of system administration tasks. Windows PowerShell allows Windows administrators to be more productive by providing numerous system administration utilities, consistent syntax, and improved navigation of common management data such as the registry or Windows Management Instrumentation (WMI). Windows PowerShell also includes a scripting language which enables comprehensive automation of Windows system administration tasks. The Windows PowerShell language is intuitive and supports existing scripting investments. Exchange Server 2007 and System Center Operations Manager 2007 will be built on Windows PowerShell.
>
> -- [Windows Server 2003 Technologies - PowerShell](http://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx)
I come from UNIX, where the text shell is the preferred way to do system administration. I've been following Powershell née Monad for some time. Windows has needed a powerful shell since before MS-DOS (not sure what the default shell in [Xenix](http://en.wikipedia.org/wiki/Xenix) was). The PowerShell team seems to be laying out some of the architecture that will be needed to bring Microsoft forward on this front. I've argued before that one of the reasons Google is beating Microsoft is the easy scriptability and command line interface on Google's Platform, Linux. If Microsoft wants to play seriously with admins like me and compete with Apple and Google, they will have to continue building on PowerShell.
One of the key components of System Administration is remote access. It would be absurd to have to physically walk up to every machine you were responsible for and use the keyboard and mouse to configure or install anything. There are some pretty good tools for working with Windows remotely, but most of them require a video card and mouse. I can type upwards to 100 words a minute, anytime I have to move my hands off the home row to the mouse, I am losing productivity. Anytime I have to stream video, I am wasting bandwidth. I can administer a UNIX box from a palmtop device like a Sidekick over a slow cell phone connection.
One of the first things that an admin wants to do with PowerShell is run remotely. To do this securely, you **must** encrypt your data. SSH has been the proven way to do this. So the question becomes, how do I connect SSH and PowerShell together? With a little bit of kludge, it is possible. Why this wasn't included by default in version 1.0, I have no idea. My advice and plea to the Microsoft developers is to just use SSH. Please don't invent a proprietary Microsoft only tool to do this. Please please please please!
**Note: The following assumes that you have logged in as a local admin and this account has a password.**
## Download and Install Cygwin
Fire up Firefox (or your favorite browser) and choose a [Cygwin Mirror](http://www.cygwin.com/mirrors.html).
- Select a mirror
- Download setup.exe
- Run setup.exe
- Most of the defaults can be left as is
However, make sure to select SSH under the Network category. It will select the other required dependencies for you.
## Configure Cygwin
Right click My Computer, select Properties -> Advanced -> Environment Variables.
Next, click the New button and add:
```
name: CYGWIN
value: ntsec
```
Select the Path variable and click Edit then append `;c:\cygwin\bin` (assuming you installed Cygwin here) at the end of the existing string.
## Download and Install Microsoft Tools
**Note: The following requires Microsoft Passport aka Live ID**
- [Download .Net 2.0 Framework](http://msdn.microsoft.com/downloads/)
- [Download PowerShell](http://www.microsoft.com/downloads/details.aspx?FamilyId=2B0BBFCD-0797-4083-A817-5E6A054A85C9&displaylang=en#AffinityDownloads)
Unzip the downloads and run their respective setup. I used all the defaults.
## Run Cygwin
- Either click the green Cygwin icon or run `c:\cygwin\cygwin.bat`
- Run ssh install script: `$ ssh-host-config`
- Answer "yes" to every question except for the last one, which should be ntsec
```
Should privilege separation be used? (yes/no) yes
Should this script create a local user 'sshd' on this machine? (yes/no) yes
Do you want to install sshd as service?
(Say "no" if it's already installed as service) (yes/no) yes
Which value should the environment variable CYGWIN have when
sshd starts? It's recommended to set at least "ntsec" to be
able to change user context without password.
Default is "ntsec". CYGWIN=ntsec
```
Start SSHD:
```
$ net start sshd
The CYGWIN sshd service is starting.
The CYGWIN sshd service was started successfully.
```
## Run Powershell
Start -> Programs -> Windows Powershell. Choose to always accept Microsoft signed code. Close PowerShell.
## Test SSH and Powershell
Run [Putty](http://www.chiark.greenend.org.uk/~sgtatham/putty/) or your favorite ssh client and connect to localhost. Accept the hash and login. If everything works, you should be at a bash prompt in Cygwin.
Next run PowerShell. Due to the limitations of PowerShell v1.0 we have to tell it that we are redirecting the input. Note that you won't get any output from PowerShell indicating that it started up, including a command prompt!
```
$ "/cygdrive/c/Program Files/Windows PowerShell/v1.0/powershell.exe" -Command -
```
Try a PowerShell one-liner:
```
[System.Net.Dns]::GetHostbyAddress("207.46.198.30")
[System.Net.Dns]::GetHostAddresses("www.msn.com")
dir | where {$_.PsIsContainer}
```
## Links
- [Using MSH Interactively From Within Other Programs](http://www.leeholmes.com/blog/UsingMshexeInteractivelyFromWithinOtherPrograms.aspx)
- [PowerShell Remoting](http://www.gotdotnet.com/workspaces/news/viewnews.aspx?id=ce09cdaf-7da2-4f1c-bed3-f8cb35de5aea)
## Credits
Big shout out and thanks to [Lee Holmes](http://www.leeholmes.com) for answering my e-mail and pointing me in the right direction, and [PigTail Cygwin SSHD Instructions](http://pigtail.net/LRP/printsrv/cygwin-sshd.html) for clearing up some of the finer points in the SSH install.
---
## Microsoft Frustration
- URL: https://mattmichie.com/2006/07/03/microsoft-frustration/
- Date: 2006-07-03
- Categories: microsoft
After writing an article about Microsoft's PowerShell, I kept getting search
referrals from people trying to get PowerShell working with SSH. Since I had
some free time, I thought an article describing how to do this would be
useful. I just spent the past hour trying to get PowerShell working with
Cygwin's sshd. It seems to be impossible. Cmd.exe works fine. I'm trying to
track down the technical reason this won't work, until then I'm going to keep
my cussing to myself. I'm stunned this doesn't work. **Update: **I contacted
one of the PowerShell developers and got a work around to make this work. I'll
clean up the article and post it. The work around is a little ugly, but it
will get you PowerShell through sshd.** **
---
## F-117 and V-22 Osprey
- URL: https://mattmichie.com/2006/07/01/f-117-and-v-22-osprey/
- Date: 2006-07-02
- Categories: albuquerque
[](http://www.flickr.com/photos/52811932@N00/179377265/
"photo sharing"
)[](http://www.flickr.com/photos/52811932@N00/179377265/)[F-117 and V-22
Osprey](http://www.flickr.com/photos/52811932@N00/179377265/)Originally
uploaded by [mimichie](http://www.flickr.com/people/52811932@N00/). After
seeing the Thunderbirds out practicing over Albuquerque yesterday, and finding
out at the last minute Kirtland was once again having an air show, I had to
go. This is the first air show they've had here since 9/11. Security was
tight, but not unreasonable and there were some great aircraft in attendence.
As awesome as the Thunderbirds, the
[F-117](http://www.af.mil/factsheets/factsheet.asp?fsID=104), the [V-22
Osprey](http://www.navair.navy.mil/v22/) and others were, I think my favorite
moment was seeing the [P-51](http://www.mustangsmustangs.com/p51.htm), an [F-4
Phantom](http://www.fas.org/man/dod-101/sys/ac/f-4.htm) and an
[F-15](http://www.fas.org/man/dod-101/sys/ac/f-15.htm) flying formation over
the crowd.The military definately needs a boost in public morale lately and
airshows are a great way to do this. I'm glad they opened up the base and show
some of what they do.
---
## Koizumi and Bush go to Graceland
- URL: https://mattmichie.com/2006/06/30/koizumi-and-bush-go-to-graceland/
- Date: 2006-06-30
- Categories: politics, humor
From the [New York Times](http://www.nytimes.com/2006/06/30/world/asia/30cnd-elvis.html?hp&ex=1151726400&en=8fdb46352ffa6481&ei=5094&partner=homepage):
> In the annals of international diplomacy, it is not exactly Yalta. But today's visit to Graceland the ticky-tacky Elvis Presley mansion here by President Bush and Prime Minister Junichiro Koizumi of Japan brings a little bit of shake, rattle and roll to American foreign relations.
>
> The prime minister is a die-hard Elvis fan; the two share a birthday, Jan. 8, and a pompadour hairstyle, though Mr. Koizumi's locks are longer and grayer than those of the King of Rock 'n' Roll. On Thursday, in a joint appearance with Mr. Bush at the White House, the prime minister had a message for the United States:
>
> "Thank you very much, American people, for 'Love me Tender,'" he said
---
## Dabble DB
- URL: https://mattmichie.com/2006/06/28/dabble-db-7-minute-overview/
- Date: 2006-06-28
- Categories: web 2.0
Though the whole Web 2.0, look at us try to shoehorn a desktop application to
the web thing is getting a little old, I was really impressed by how easy
DabbleDB makes publishing data from a Spreadsheet, check out the [7 Minute
whirlwind tour](http://dabbledb.com/utr/).
---
## Microsoft adCenter Labs Analysis of Hivearchive.com
- URL: https://mattmichie.com/2006/06/26/microsoft-adcenter-labs-analysis-of-hivearchivecom/
- Date: 2006-06-26
- Categories: microsoft
Microsoft adCenter Labs has interesting demos of algorithms they are using to help target their ads. Google obviously has similar tools, but they have kept them internal (probably to keep spammers and SEO guessing). I ran through some of them for this site. Results follow.
[Content Categorization](http://adlab.microsoft.com/KTS/CCATResult.aspx):
| Categories | Confidence |
|---|---|
| Computing\Software | 0.110 |
| People & Chat\Homepages | 0.063 |
| Computing\Internet | 0.061 |
| Entertainment\Games | 0.050 |
| Computing\Computer Science | 0.050 |
| Computing\Networks & Comm. | 0.036 |
| Computing\Sales | 0.032 |
| People & Chat\Email | 0.029 |
| People & Chat\Forums & Lists | 0.027 |
| Computing\Multimedia | 0.025 |
| Entertainment\Humor & Fun | 0.024 |
| Computing\Hardware | 0.023 |
| People & Chat\Chat | 0.022 |
| Entertainment\Music | 0.020 |
| Computing | 0.010 |
[Demographics Prediction](http://adlab.microsoft.com/DPUI/DPUI.aspx):
- **Gender:** Male Oriented
- **Age:** 25~34 Oriented
Online Commercial Intention:
- **Result:** NonCommercial (Page)
- NonCommercial Prob.: 0.91448
- Commercial-Informational Prob.: 7.6531e-002
- Commercial-Transactional Prob.: 8.9882e-003
---
## Strange Colors in Video Playback
- URL: https://mattmichie.com/2006/06/25/strange-colors-in-video-playback/
- Date: 2006-06-26
- Categories: windows, troubleshooting
After attempting to play back some MPEG and DivX videos, I was getting strange
colors in every program I was using, including VLC, Windows Media Player and
mplayer. Even tweaking the gamma, constrast, hue, brightness and every other
setting I could find, the video still looked washed out and dark. The only
thing affected was video playback. The desktop, web browsing and games all
looked fine. Finally, I figured out that in the NVidia control panel, there
are seperate settings for video playback. Somehow they had all been changed to
bizzare values. All it took was to return them to the default to fix the
problem. Very strange, as I know I didn't touch any of these values and I had
just reinstalled this system from scratch. Anyway, hope this helps someone
Googling this problem as I wasn't able to find any useful information.
---
## Fake Identity Generator
- URL: https://mattmichie.com/2006/06/22/fake-identity-generator/
- Date: 2006-06-23
- Categories: security
Ever wanted a [new identity](http://dev.allredtech.com/fakename/)?
---
## Royksopp - Remind Me (video)
- URL: https://mattmichie.com/2006/06/21/royksopp-remind-me-video/
- Date: 2006-06-21
- Categories: random, music
The animation in this music video is very unique. 8/10 overall.
---
## 17 Mistakes Microsoft Made in the Xbox Security System
- URL: https://mattmichie.com/2006/06/21/17-mistakes-microsoft-made-in-the-xbox-security-system/
- Date: 2006-06-21
- Categories: security, microsoft
The folks at xbox-linux have a great article on the [17 Mistakes Microsoft Made in the Xbox Security System](http://www.xbox-linux.org/wiki/17_Mistakes_Microsoft_Made_in_the_Xbox_Security_System). Following is an excerpt of just one back and forth between hackers and Microsoft Security.
> The history of Microsoft's reactions to the font vulnerability is the perfect lesson of how to do it wrong.
>
> 1. After MechInstaller had been released, Microsoft fixed the buffer vulnerability in the Dashboard and distributed this new version over the Xbox Live network and shipped it with new Xboxes.
>
> 2. For the hackers, this was no major problem: It was possible to downgrade the Dashboard of a new Xbox to the vulnerable version. Just run Linux using a savegame exploit, and "dd" the old image. Some people felt downgrading on new Xboxes was not piracy, because after all, Microsoft upgraded Xbox Live users' hard disks to the new version without asking.
>
> 3. As the next step, Microsoft blacklisted the old Dashboard in the new kernel. It was impossible to just "dd" an old Dashboard image onto newer Xboxes.
>
> 4. Still no major problem for hackers: The second executable on the hard disk, "xonlinedash", which is used for Xbox Live configuration, had the same bug, so it was possible to copy the old "xonlinedash" and to rename it to "xboxdash" to make it crash because of the faulty fonts.
>
> 5. Microsoft consequently blacklisted the vulnerable version of "xonlinedash".
>
> 6. Again, no major problem for hackers: All Xbox Live games come with the "dashupdate" application, which adds Xbox Live functionality to the Dashboard for the first Xboxes which came without it. This update application has the same font bug, and it can be run from hard disk. So it is possible to copy the file from any Xbox Live game DVD, rename it to "xboxdash" and let it crash.
>
> 7. Microsoft could not blacklist this one. Xbox Live enabled games run the update application every time they start, making sure the Xbox has the Xbox Live functionality. Blacklisting "dashupdate" would break these games.
We won.
---
## Solaris Secure by Default (maybe soon)
- URL: https://mattmichie.com/2006/06/21/solaris-secure-by-default-maybe-soon/
- Date: 2006-06-21
- Categories: security, solaris
Found the following at :
> **SARC case 2004/368 : Secure By Default**
>
> - BUG/RFE:4875624 - *syslogd* turn off UDP listener by default
> - BUG/RFE:5004374 - Ship with remote services disabled by default
> - BUG/RFE:5016956 - By default rpcbind should not listen for remote requests
> - BUG/RFE:5016975 - By default snmpd/dx should not be enabled
> - BUG/RFE:5016998 - By default inetd should not listen for remote connections
> - BUG/RFE:5017041 - By default sendmail should not listen for remote connections
> - BUG/RFE:5046450 - Create a greenline profile for Secure by Default installation
> - BUG/RFE:6267741 - RFE: One-touch knob for outbound-only sendmail
> - BUG/RFE:6414308 - syslogd could use some lint soap
Oddly enough, I was just complaining about this myself. :)
---
## Materishche otherwise known as Matt Michie
- URL: https://mattmichie.com/2006/06/20/materishche-otherwise-known-as-matt-michie/
- Date: 2006-06-20
- Categories: microsoft
> The closest match for 'matt michie' is 'Materishche [Zalesnaya], Novgorod,
Russia'. If the closest match is incorrect, enter the complete address
including country name and commas, and try again.
> [local.live.com ](http://local.live.com)
I was playing around with Microsoft's new web search and was amused at this
result. Of course my entry was nonsensical, but trying out some legit queries
on the search engine side left me mildly impressed. The search results are
returning more what I expect. I'm not completely sold on the AJAX interface,
but it is novel and works on Firefox. The birds eye view of Local Live blows
away Google Maps, at least for Albuquerque. Looks like we've got some
competition going!
---
## Mexican Campaign Ads
- URL: https://mattmichie.com/2006/06/18/mexican-campaign-ads/
- Date: 2006-06-18
- Categories: politics, humor
> With Mexico's presidential election two weeks away, the drug wars are a
central issue in the race, and the main candidates are all trying to look
tough on the issue, while splitting over whether U.S.-style solutions are
needed. Roberto Madrazo of the former ruling party claims the toughest law-
and-order platform: _One of his campaign ads depicts a criminal wetting his
pants out of fear of Madrazo's proposals for stiffer sentencing. "Criminals
can't play around with me," Madrazo tells voters. _
* [Yahoo News](http://news.yahoo.com/s/ap/20060618/ap_on_re_la_am_ca/mexico_drugs_and_votes)
---
## Solaris 10 Default Security
- URL: https://mattmichie.com/2006/06/15/solaris-10-default-security/
- Date: 2006-06-16
- Categories: unix, solaris
When are we going to start making Operating Systems install secure by default?
```
$ netstat -a|grep -i listen|awk '{print $1}'
*.sunrpc
*.32771
*.lockd
*.32772
*.32773
*.32774
*.32775
*.32776
*.telnet
*.ftp
*.finger
*.login
*.shell
*.fs
*.32777
*.ssh
*.5987
*.898
*.32778
*.5988
*.32779
*.9010
*.32780
*.32782
*.32781
*.smtp
*.smtp
*.submission
*.telnet
*.ftp
*.finger
*.login
*.shell
*.fs
*.ssh
*.smtp
```
---
## TurboGears API Goes 1.0
- URL: https://mattmichie.com/2006/06/14/turbogears-api-goes-10/
- Date: 2006-06-14
- Categories: python, turbogears
> "The [TurboGears](http://www.turbogears.org/) 1.0 API is done. There may be
some minor additions, but there won't be breaking changes between now and 1.0
final. I'm also working to ensure that only changes with minimal risk to
production use are checked into the 1.0 branch. So, everything is organized
around the notion that we are stabilizing things for a 1.0 release."
> Kevin Dangoor
I've been looking forward to this announcement. It is hard to get caught up in
a web framework when you know there could be major upheaval in the API. I
haven't been able to get into the Ruby craze, I'm still on my Python kick for
awhile longer and with TurboGears and Django going stable, there isn't a
better time to be a Python web developer.
---
## Handy .screenrc
- URL: https://mattmichie.com/2006/06/13/handy-screenrc/
- Date: 2006-06-14
- Categories: unix
Found the follow handy .screenrc posted in a forum. If you are a heavy UNIX
user and you haven't used [GNU Screen](http://www.gnu.org/software/screen/),
you are missing out on one of the handiest applications around. Highly
recommended. The following adds a nice status line and F5 and F6 to switch
through windows, F7 to rename the active window, and F8 to create a new
window.
```
bindkey -k k5 prev
bindkey -k k6 next
bindkey -k k7 title
bindkey -k k8 screen
msgwait 1
autodetach on
nethack on
sorendition 04 43
hardstatus alwayslastline "%D %M %d %c | %-w %{---r} %n %t %{-} %+w"
vbell on
defscrollback 1024
startup_message off
defutf8 on
term xterm
```
---
## Concurrent Port Scanner in Haskell
- URL: https://mattmichie.com/2006/06/13/concurrent-port-scanner-in-haskell/
- Date: 2006-06-13
- Categories: security, programming
Tom Moertel wrote a very concise [port scanner in Haskell](http://blog.moertel.com/articles/2004/03/13/concurrent-port-scanner-in-haskell). I have never looked at Haskell in any detail, but this program seems pretty impressive. You wouldn't be able to do a port scanner quite so neatly in most other languages. I guess I'll have to put that on the long stack of things to look into in more someday.
---
## Don't Be Evil (but censorship is ok)
- URL: https://mattmichie.com/2006/06/09/dont-be-evil-but-censorship-is-ok/
- Date: 2006-06-09
- Categories: china, censorship, google
> "Google Inc. is committed to doing business in China despite criticism the company has faced for abiding by Chinese government censorship restrictions, co-founder Sergey Brin said this week. ... Brin told a small group of invited journalists: 'I think it's perfectly reasonable to do something different. Say, OK, let's stand by the principle against censorship and we won't actually operate there.' But he then added: 'That's an alternative path. It's not the one we've chosen to take right now.' ... At a regular news briefing in Beijing on Thursday, Foreign Ministry spokesman Liu Jianchao said the Chinese government viewed Google's involvement in the country positively."
>
> -- [Reuters](http://today.reuters.com/news/newsarticle.aspx?type=technologyNews&storyID=2006-06-09T105024Z_01_N08363725_RTRUKOC_0_US-GOOGLE-CHINA.xml&pageNumber=0&imageid=&cap=&sz=13&WTModLoc=NewsArt-C1-ArticlePage2)
So it is perfectly reasonable for a company whose sole mission is to bring the world's information to your fingertips and was founded with the motto "Don't Be Evil" to work with oppressive governments to censor such words as:
- democracy
- human rights
- tiananmen
- bird flu
- dissidents
- water pollution
- tank man
- freedom
- protests
The above list was obtained from: . I don't know how Google can be so blind, but hey at least the stock is doing well.
---
## Badonkadonk Land Cruiser/Tank
- URL: https://mattmichie.com/2006/06/08/badonkadonk-land-cruisertank/
- Date: 2006-06-08
- Categories: random

You can get anything from Amazon these days, including a [JL421 Badonkadonk
Land
Cruiser/Tank](http://www.amazon.com/exec/obidos/tg/detail/-/B00067F1CE/103-3790076-3466236).
The reviews on this thing are awesome.
---
## Embarrassing Red Hat RPM Bug
- URL: https://mattmichie.com/2006/06/08/embarrassing-red-hat-rpm-bug/
- Date: 2006-06-08
- Categories: linux, red hat
Tonight, I stumbled upon an [embarrassing RPM bug report](https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=119185) that puts Red Hat developers in a bad light. I can understand that as a developer you could become frustrated with a report, but instead of trying to explain how the RPM database could go into an inconsistent state, and determine whether that was fixable or not, the developers berated the users. Is this how you build a community?
Finally, after two years of ignoring the bug, Red Hat finally came around and 'fixed' it, though it isn't clear whether they fixed the general case, or put a workaround for the behavior from the original report. I wasn't aware that RPM or yum had this behavior and it makes me trust the whole mess a lot less. I wonder how apt-get handles this.
As a system admin, I generally prefer systems with package management. Being able to do security updates without hassle is a huge benefit. However, no matter how much one tries, there are always going to be programs or libraries outside your package manager. From a philosophical point of view, it is probably better to have all or nothing, so I sympathize with those who compile and install everything, or use a comprehensive system like BSD ports.
I think a better system could be developed that encompasses the entirety of program management. It should include installing libraries from scripting languages such as Python Eggs, Ruby Gems or Perl CPAN. It should probably include hooks into GNU AutoConf/AutoMake, though I imagine the political hurdles of getting so many disparate projects to agree on a standard would be far greater than the technical ones. I suppose we can all hope.
---
## Brin says Google compromised principles
- URL: https://mattmichie.com/2006/06/07/brin-says-google-compromised-principles/
- Date: 2006-06-07
- Categories: china, censorship, google
_"Google Inc. co-founder Sergey Brin acknowledged Tuesday the dominant
Internet company has compromised its principles by accommodating Chinese
censorship demands. He said Google is wrestling to make the deal work before
deciding whether to reverse course."_ [
http://news.yahoo.com/s/ap/20060606/ap_on_hi_te/google_censorship_3](http://news.yahoo.com/s/ap/20060606/ap_on_hi_te/google_censorship_3)
---
## The Coming Battle Over Grid Computing and Internet Services
- URL: https://mattmichie.com/2006/06/02/the-coming-battle-over-grid-computing-and-internet-services/
- Date: 2006-06-02
- Categories: google, internet, yahoo, microsoft, hardware, grid computing
A comment I left on Wes Maldonado's blog has started a [conversation about grid computing](http://www.brokenbuild.com/blog/2006/06/02/why-is-the-digipede-network-good-for-windows-environments/). He posted on [Digipede](http://www.digipede.net/), a Windows centric way to do distributed computing and I responded that it would be "nice" not to be forced to do this type of work on an operating system that required a GUI.
That set off another post about cost effectiveness and using existing infrastructure, points I don't disagree with. In an IT environment with a lot of computers running Windows and a problem that allows you to do distributed algorithms easily, Digipede seems pretty exciting. Ever since the original Distributed.net, I'd wondered if a company would bring a product like this to market. It is something that I would have a lot of fun playing with.
That said, my point on electricity and running super computer clusters on Windows still stands. My comment wasn't intended to disparage Digipede so much as point out the problem that Microsoft is going to have competing with companies like Google and Yahoo for the next generation of Internet Services.
Some have estimated that Google's data centers have well over 100,000 COTS PCs setup in a distributed grid. Google is running Linux, which can run headless without a video card, or the need to install any GUI package. Linux has been "designed" to be completely scriptable from a command line interface. Windows however, appears to have a tight integration between the GUI layers and the NT kernel. As far as I know, it is impossible to install Windows on a machine without a video card. Obviously, the GUI layer will be paged to disk on all these machines, but the cost of a video card multiplied by several hundred thousand is needless.
The other competitive advantage Google and Yahoo have is the scriptability of Linux and FreeBSD. While PowerShell is a step forward for Microsoft, my view is that the UNIX environment wins on system administration scriptability. The key to building super computer clusters is easy system administration. Perhaps Microsoft can leverage their existing infrastructure and prove that GUI tools can do everything the UNIX ones can and more, but they are starting with less experience.
Google has already proven they can do it effectively. My back of the envelope estimation is that Google Linux sysadmins are each responsible for between 1,000 and 2,000 servers. I don't see a Microsoft solution for that yet, and I don't think the Digipede product is intended to compete in that type of environment. Digipede also probably isn't going to compete in the National Labs super computer arena either (at least yet).
The second problem is any kind of parallel programming is really hard. Even threads prove a huge challenge within a single application. While clever, I don't think that [Map/Reduce](http://labs.google.com/papers/mapreduce-osdi04.pdf) is a magic bullet either. A lot of algorithms simply don't scale linearly with computing power, so adding more hardware just burns a hole in your wallet and in your data center's air conditioning.
All that said, there are plenty of places that products like Digipede would fit perfectly. Mainly, I am interested to see how this all shakes out, as we see Microsoft, Google and Yahoo [building their data centers close to hydro-electric power](http://www.entmag.com/news/article.asp?EditorialsID=7302) to cut costs. Sun is also a dark horse in this whole race, building out their grid infrastructure and custom chips that suck less juice. I can't wait to see more!
---
## Compiling nmap
- URL: https://mattmichie.com/2006/05/30/compiling-nmap/
- Date: 2006-05-31
- Categories: openbsd
After cvs updating my ports tree in OpenBSD, I was going through and compiling
a bunch of fun stuff, noticed this one building nmap:
config.status: creating nsock_config.h
( ) /\ _ (
\ | ( \ ( \.( ) _____
\ \ \ ` ` ) \ ( ___ / _ \
(_` \--- . x ( .\ \/ \____-----------/ (o) \_
- .- \--- ; ( O \____
) \_____________ ` \ /
(__ ---- .( -'.- <. - _ VVVVVVV VV V\ \/
(_____ ._._: <_ - <- _ (-- _AAAAAAA__A_/ |
. /./.---- . .- / +-- - . \______________//_ \_______
(__ ' /x / x _/ ( \___' \ /
, x / ( ' . / . / | \ /
/ / _/ / --- / \/
' (__/ / \
NMAP IS A POWERFUL TOOL -- USE CAREFULLY AND REPONSIBLY
Configuration complete. Type make (or gmake on some *BSD machines) to compile.
ASCII art makes me nostalgic.
---
## Virtualizing Firefox Bon Echo with Altiris SVS
- URL: https://mattmichie.com/2006/05/30/virtualizing-firefox-bon-echo-with-altiris-svs/
- Date: 2006-05-30
- Categories: windows, mozilla, howto, virtualization
The next release of Mozilla Firefox is approaching, with some of the following new features:
- Built in Anti-Phishing protection
- Search suggestions now appear with search history in the search box for Google and Yahoo!
- Support for client-side session and persistent storage
- Changes to tabbed browsing behavior
- Search plugin manager for removing and re-ordering search engines
- Better support for previewing and subscribing to web feeds
- New microsummaries feature for bookmarks
- Inline spell checking in text boxes
- Automatic restoration of your browsing session if there is a crash
- New combined and improved Add-Ons manager for extensions and themes
- Extended search plugin format
- Updates to the extension system to provide enhanced security and to allow for easier localization of extensions
- Support for SVG text using svg:textPath
Do you love Firefox and want to help test the bleeding edge versions, but don't want blood all over your computer? Are you worried that the Alpha software will kill your bookmarks and eat your GMail? Enter Altiris Software Virtualization Solution:
> "Where virtual machine utilities like VMware Workstation manage entire virtual computers, Altiris Software Virtualization Solution 2.0 virtualizes individual software installations. Once installed on a system, SVS runs continually. If you install a program under it, SVS grabs all changes to the Registry and file system (including added and deleted files) that the installer makes and puts them in what Altiris calls a layer. Thereafter, the virtualization software directs file and Registry calls to the layer or to the base system as appropriate. The SVS-installed app looks perfectly normal, but disappears without a trace when you deactivate the layer. You can turn the app on and off like a light switch."
>
> -- [Neil J. Rubenking, PC Magazine, 3-23-06](http://www.pcmag.com/article2/0,1895,1941377,00.asp)
Altiris has made this software free for personal use and I've written some instructions to get you started (assuming you have access to a Win32 PC).
## Step by Step
1. [Download Bon Echo Alpha 3](http://download.mozilla.org/?product=bonecho-alpha3&os=win&lang=en-US)
2. [Obtain Altiris personal use license](http://www.altiris.com/Download/svsPersonal.aspx). You don't have to input your e-mail address on the download form (unless you want to). Kudos to Altiris for this.
3. [Download Altiris Software Virtualization Solution](http://www.download.com/Software-Virtualization-Solution/3000-2651-10516806.html?part=dl-SoftwareV&subj=uo&tag=button)
4. Install SVS by unzipping the download and double-clicking the `Software_virtualization_Agent.msi`.
5. Make sure to check the Software Virtualization Admin Tool box, we will be using it later to create our own custom Bon Echo layer.

6. Reboot (it is Windows after all)
7. Open the Altiris Software Admin and select File -> Create New Layer.
8. On the Create New Layer dialog, select "Install application" and click Next.

9. Enter Bon Echo Alpha 3 as the Layer name and click Next.
10. Make sure Single program capture is selected, then browse to where you saved the Bon Echo Setup alpha 3.exe. Parameters can be left blank. Click Next.

11. Verify the information you entered is correct and click "Finish".

12. Proceed through the Bon Echo Setup as normal. You can leave the defaults as is.

13. When you reach the final screen, right click on the Altiris Capture tray icon (yellow lightning bolt) and select Stop Capture.
At this point you should have a virtualized Bon Echo Layer. Use the Altiris Admin tool to enable or disable this layer. You can also reset the layer back to the default state from this interface. With this tool, you can help test beta software without worry of damaging your system. Be sure to [report any bugs](https://bugzilla.mozilla.org/) you discover. There are also many pre-packaged layers available at [svsdownloads.com](http://svsdownloads.com). Cheers!
---
## Lisp Cells Moving to Python
- URL: https://mattmichie.com/2006/05/30/lisp-cells-moving-to-python/
- Date: 2006-05-30
- Categories: python, code, lisp
I ran across the NYC Lisp User Group's description of a Google Summer of Code
project to [port Lisp Cells to
Python](http://www.lispnyc.org/wiki.clp?page=PyCells). I hadn't heard of Cells
before this, but this seems like a potentially cool thing. I would like to try
this, especially on Python. I'm not a Lisp coder, but it would be fascinating
to go to one of their meetings. One can imagine anyone in NYC passionate
enough to show up to a Lisp user group would be an interesting character. :-)
---
## Parsing, Priv Separation and chroot
- URL: https://mattmichie.com/2006/05/27/parsing-priv-separation-and-chroot/
- Date: 2006-05-27
- Categories: internet, security, code, http
I fixed up the parsing issues on Shelob so that it is somewhat respectable, instead of a bunch of hacks. It was obvious once I started looking at what the client was sending me (the [LiveHTTP headers Firefox extension](http://livehttpheaders.mozdev.org/) rocks), that I needed to break up each line and then separate the values into a name and value.
After rewriting the `getHeaders()` function to use STL hash tables, not only is the code more flexible, but it is also cleaner. For example:
```cpp
log.writeLogLine(inet_ntoa(sock->client.sin_addr), request_line, 200, size,
headermap["Referer"], headermap["User-Agent"]);
```
Here, with the headermap, it is obvious what values I am passing. Before the rewrite, I just had a bunch of `tokens[3]`, `tokens[5]`, etc.
I'm also toying around with the idea of privilege separation and chroot jails. This sort of flows with the previous post of a micro-kernel type approach, similar to how Postfix works. While it is more secure, the programming challenges are pretty high. I may leave that for a later version. I still have a bit of cleanup to do before a release.
Aside: Theo de Raadt gave a nice [presentation on exploit mitigation techniques](http://www.openbsd.org/papers/ven05-deraadt/index.html) that OpenBSD is using which relates to some of these ideas.
---
## Color ls on OpenBSD
- URL: https://mattmichie.com/2006/05/26/color-ls-on-openbsd/
- Date: 2006-05-27
- Categories: openbsd
To get color ls output on OpenBSD, get a recent version of ports and then do
the following:
1. cd /usr/ports/sysutils/colorls
2. make install
3. set your TERM to wsvt25
4. /usr/local/bin/colorls -G should now display similar to the GNU ls with the color option
5. Set the appropriate alias for your shell.
---
## More Hacking Shelob
- URL: https://mattmichie.com/2006/05/25/more-hacking-shelob/
- Date: 2006-05-25
- Categories: internet, code, http
I fussed around more with logging today, which lead me to the `parseHeader()` function. Parsing is one of the weakest areas right now. For simplicity, I had implemented it by simply tokenizing on "space", shoving the tokens into a string vector and then iterating over that vector for the tokens I needed. So far, I've not peeked at anyone else's source code, Shelob is a clean room implementation of a basic HTTP server.
However, I really need to clean up the parser. I thought about going with a full lexer using flex or something, but that is probably overkill. Plus, I'd rather not add another dependency. More thought on this is needed and maybe some research into how other people are doing this. Very much an area where security can go wrong, it needs to be done right.
The other thought I had while poking around, is that I could make each component into its own server, sort of a mini-microkernel approach. I could imagine a swarm of different servers, all being able to communicate. You could have the log server running on one host, separate cgi servers for each user, as well as different backends.
The only thing I'm not sure about is how much overhead this would be. A lot of the interprocess communication could happen over local UNIX sockets, FIFOs, or even shared memory, but it would be awesome if it all worked fast over a regular socket. Yet more thought needed here.
So far I'm having a blast playing with this program. It is nice to write something for yourself and make only the trade offs you decide. I don't have any customer or management trying to shoehorn this thing into something I don't want. Even if I never release it, it is a good brain exercise.
---
## Hacking Shelob
- URL: https://mattmichie.com/2006/05/24/hacking-shelob/
- Date: 2006-05-25
- Categories: code, http
Today I added support for NCSA/Apache style logs. It has been nearly 2 years since I last touched this code and closer to 3 since I first wrote it. Surprisingly, I'm able to make modifications pretty easily. To me, this indicates that the design is semi-clean.
The odd thing about Shelob is that it is literally my first C++ program. I've never so much as done a Hello World in C++ before writing a web server. Granted, I had done a fair amount of C before this and I'm using C++ more for the STL and namespaces. It isn't completely OOP, but C++ isn't either. One of the big things that I was trying to do with Shelob was to use C++ strings exclusively, but I found out quickly that it is almost impossible not to drop down and use C style "strings" at some point, especially when dealing with sockets.
Right now Shelob is very incomplete, but it does have the following features:
- Compiles cleanly on Solaris/Sparc, OpenBSD/PPC, OSX/PPC, Linux/x86
- Binary is less than 60K
- Supports HTTP/1.1 Keep-Alive
- Basic log file support
- A filter class (currently supports adding a footer to every HTML page before serving)
Currently, it is forking, but I'm considering moving to a select model for speed. I would also like to be able to run it from Win32, but that is a much lower priority. It would be nice if Vista supported forking.
I have some ideas for future features, but there are some areas that are a little rough in the current code that need refactoring. I also need to ponder what license to release under. I'm leaning towards BSD, but GPL is running a close second. I should probably look at other web servers and see what they are operating under.
---
## Shelob Needs a New Name
- URL: https://mattmichie.com/2006/05/22/shelob-needs-a-new-name/
- Date: 2006-05-22
- Categories: code
Several years ago, I implemented a partially compliant HTTP/1.1 web server in C++. It is named Shelob, after the Spider Beast in Lord of the Rings. It's also an acronym: Server for HTTP Environment and Logging Outgoing Bits (credit goes to [Darren Morin](http://truefluke.org/) for the name).
I ported it to Automake/Autoconf a year ago, and I would like to update it some and release it as open source. However, I probably need to come up with a new name to avoid copyright infringement and to make it easier to find in search engines. Any ideas?
---
## Apple Laptop Hard Drives
- URL: https://mattmichie.com/2006/05/17/apple-laptop-hard-drives/
- Date: 2006-05-17
- Categories: apple, hardware
Apple Insider [reports](http://www.appleinsider.com/article.php?id=1750) that
the new Macbook laptops have user servicable hard drives. Awesome! I replaced
my own G4 Powerbook hard drive when the factory one failed. I would not
recommend this to anyone. The amount of various sized screws, hard to remove
casings and tenously coupled cables make it an unfun adventure. Good to see
they are learning from their mistakes.
---
## The Zen of Python
- URL: https://mattmichie.com/2006/05/07/the-zen-of-python/
- Date: 2006-05-07
- Categories: python
```
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
[Tim Peters ](http://www.python.org/dev/peps/pep-0020/)
```
---
## Broken Windows
- URL: https://mattmichie.com/2006/05/01/broken-windows/
- Date: 2006-05-01
- Categories: windows, security, microsoft
I finally started fixing some of the computers I've had lying around the house. Someone asked me if I was embarrassed that I had three broken systems. I guess that gave me some motivation, plus I wanted to play Tony Hawk Pro Skater 3 on my projector and I needed a Windows PC. I've been using my PowerBook G4 for almost two months now and it has done everything I've needed except hardcore gaming.
It took me about an hour to piece together all the parts into one working PC. I finally got XP to boot and then realized I had forgotten my password, and since I had increased the security settings to insane levels, I locked out all my accounts, including administrator. Sigh.
So I spent another two hours downloading Linux boot CD-ROMs with utilities to "hack" the Windows password file. While I was burning one, I discovered that if you boot XP into safe mode, it happily ignores the account lockouts. I don't know whether to laugh that I locked myself out of my own PC, or to cry that Windows would allow such an easy bypass.
Well maybe tomorrow I'll get the energy to get OpenBSD on the G3 I have sitting in the corner. I expect OpenBSD running on PPC is slightly more secure than XP.
---
## Random Links
- URL: https://mattmichie.com/2006/04/28/random-links/
- Date: 2006-04-28
- Categories: random
* [Web Hosting, An Illustration of No Entry Barriers](http://mattinglot.com/blog/2006/04/27/web-hosting-an-illustration-of-the-dangers-of-no-entry-barriers/)
* [Nintendo Revolution Renamed to "Wii"](http://arstechnica.com/news.ars/post/20060427-6690.html)
* [The Guy I Almost Was](http://www.e-sheep.com/almostguy/)
* [Paragliding: It's the Alone Way to Fly](http://www.nytimes.com/2006/04/28/travel/escapes/28para.html)
* [Life Without Numbers](http://www.jcrows.com/withoutnumbers.html)
---
## 102 Movies to See
- URL: https://mattmichie.com/2006/04/26/102-movies-to-see/
- Date: 2006-04-27
- Categories: film
I ran across this list on [Kottke.org](http://kottke.org), who apparently cribbed it from [Jim Emerson](https://web.archive.org/web/20130116152834/http://rogerebert.suntimes.com/apps/pbcs.dll/article?AID=/20060420/EDITOR/60419010). I've marked the ones I've seen with a check. Even though I've watched a lot of movies lately, I still have a lot of catching up to do.
I am tickled that I've actually seen [Un Chien Andalou](http://www.imdb.com/title/tt0020530/), a somewhat obscure 1929 French film by Luis Bunuel and Salvador Dali that features an eyeball getting slit open by a razor! If you have ever heard the Pixies song Debaser, it is about this movie. Check it out.
- [ ] 2001: A Space Odyssey
- [ ] The 400 Blows
- [ ] 8 1/2
- [ ] Aguirre, the Wrath of God
- [x] Alien
- [ ] All About Eve
- [ ] Annie Hall
- [x] Apocalypse Now
- [x] Bambi
- [ ] The Battleship Potemkin
- [ ] The Best Years of Our Lives
- [ ] The Big Red One
- [ ] The Bicycle Thief
- [ ] The Big Sleep
- [x] Blade Runner
- [ ] Blowup
- [ ] Blue Velvet
- [ ] Bonnie and Clyde
- [ ] Breathless
- [ ] Bringing Up Baby
- [ ] Carrie
- [ ] Casablanca
- [x] Un Chien Andalou
- [ ] Children of Paradise / Les Enfants du Paradis
- [x] Chinatown
- [ ] Citizen Kane
- [x] A Clockwork Orange
- [x] The Crying Game
- [ ] The Day the Earth Stood Still
- [ ] Days of Heaven
- [ ] Dirty Harry
- [ ] The Discreet Charm of the Bourgeoisie
- [ ] Do the Right Thing
- [ ] La Dolce Vita
- [ ] Double Indemnity
- [x] Dr. Strangelove
- [ ] Duck Soup
- [x] E.T. -- The Extra-Terrestrial
- [ ] Easy Rider
- [x] The Empire Strikes Back
- [x] The Exorcist
- [x] Fargo
- [x] Fight Club
- [x] Frankenstein
- [ ] The General
- [x] The Godfather
- [x] The Godfather, Part II
- [ ] Gone With the Wind
- [x] GoodFellas
- [x] The Graduate
- [ ] Halloween
- [ ] A Hard Day's Night
- [ ] Intolerance
- [ ] It's a Gift
- [x] It's a Wonderful Life
- [ ] Jaws
- [ ] The Lady Eve
- [ ] Lawrence of Arabia
- [ ] M
- [ ] Mad Max 2 / The Road Warrior
- [ ] The Maltese Falcon
- [x] The Manchurian Candidate
- [ ] Metropolis
- [ ] Modern Times
- [x] Monty Python and the Holy Grail
- [ ] Nashville
- [ ] The Night of the Hunter
- [ ] Night of the Living Dead
- [ ] North by Northwest
- [ ] Nosferatu
- [ ] On the Waterfront
- [ ] Once Upon a Time in the West
- [ ] Out of the Past
- [ ] Persona
- [ ] Pink Flamingos
- [ ] Psycho
- [x] Pulp Fiction
- [ ] Rashomon
- [x] Rear Window
- [ ] Rebel Without a Cause
- [ ] Red River
- [ ] Repulsion
- [ ] The Rules of the Game
- [ ] Scarface
- [ ] The Scarlet Empress
- [x] Schindler's List
- [ ] The Searchers
- [x] The Seven Samurai
- [ ] Singin' in the Rain
- [ ] Some Like It Hot
- [ ] A Star Is Born
- [ ] A Streetcar Named Desire
- [ ] Sunset Boulevard
- [ ] Taxi Driver
- [ ] The Third Man
- [ ] Tokyo Story
- [ ] Touch of Evil
- [ ] The Treasure of the Sierra Madre
- [ ] Trouble in Paradise
- [ ] Vertigo
- [ ] West Side Story
- [ ] The Wild Bunch
- [x] The Wizard of Oz
---
## Microsoft's Monad Misses the Mark
- URL: https://mattmichie.com/2006/04/25/microsofts-monad-misses-the-mark/
- Date: 2006-04-26
- Categories: windows, microsoft
[Monad](http://en.wikipedia.org/wiki/MSH_\(shell\)), what have you become? I found the following on [Arul Kumaravel](http://blogs.msdn.com/arulk/archive/2006/03/08/546600.aspx)'s blog:
| CMD.EXE | Monad Equivalent |
|---|---|
| `cd` | `set-location` or `cd` |
| `cd c:\temp` | `set-location c:\temp` |
| `cls` | `clear-host` or `cls` |
| `copy con` | `function copycon { [system.console]::in.readtoend() }` |
| `copy con foo.txt` | `copycon \| set-content foo.txt` |
| `dir` | `get-childitem` or `dir` |
| `dir /ad` | `get-childitem \| where { $_.MshIsContainer }` |
| `dir /od` | `get-childitem \| sort-object LastWriteTime` |
| `dir /o-d` | `get-childitem \| sort-object LastWriteTime -desc` |
| `pushd` | `push-location` |
| `popd` | `pop-location` |
| `start .` | `invoke-item .` or `ii .` |
When I saw this, I actually looked to make sure it wasn't an April Fool's joke. I've been hearing about Monad for some time, it was yet another promised feature that Vista won't have. It sounded impressive, for once Microsoft was going to create a command line interface, and they were going to clean up the cruft that has accumulated in the past 40 years of computing. It was/is supposed to be completely object oriented, a cut above the poor UNIX text interfaces.
I was just impressed they had finally listened to their customers pleading and begging for a way to script and use the command line to admin Windows boxes. Then I run across an idiot on Slashdot where someone was using this example to **brag** about Monad!
Most of the time when people type LOL, they aren't really laughing out loud, but this time, my lungs hurt from laughing so hard. Have these people actually used a command line interface? The reason the commands are so small in UNIX is that they are faster to type!
This syntax in Monad looks like it was dreamt up by someone that saw a UNIX shell a couple times and said, "wow, these commands don't make much sense, how would a new user know what cd or ls or ps means?" If this is the state of Monad, I can't imagine ever using it.
The whole point of a command line interface is that I can ssh to a machine over any kind of network and **quickly** type and do useful work. I was ready to give them a shot, but if they've missed this most basic point, I don't see how it would be useful. Probably not a surprise that Microsoft can't get a text interface right, but I was hoping.
I leave with a quote from [ebnf]: "Is monad pronounced like gonad?"
---
## Google Adsense and the Magic of the Long Tail
- URL: https://mattmichie.com/2006/04/25/google-adsense-and-the-magic-of-the-long-tail/
- Date: 2006-04-25
- Categories: google, internet
Lem Bingley at IT Week blogs about the [millions of blogs now running AdSense](http://lembingley.itweek.co.uk/2006/04/googles_results.html) that rarely, if ever break the $100 limit that Google requires before they cut you a check. This made sense in the early days of AdSense, since they were still mailing checks to everyone. It certainly isn't cost effective for Google to mail out $0.10 checks all over the world.
However, with electronic transfers now enabled, they've kept the limit the same. Even banks don't make this much money off the float. If Yahoo or MSN really wanted to cut into the long tail of AdSense, they would lower the minimum payout for electronic transfers to something more like $25/month.
The other major complaint that I have with AdSense is that I am not allowed to set a bid price on what ads can appear on my site. Google controls it. If they determine that my page rates $0.01 ads, that's the ad they place. Granted, it is in their best interest as well as mine to put the ad most likely to receive a legit click-through.
However, it may not be in my best interest to clutter up my page with $0.01 advertisements. I should be able to set a minimum bid price for an ad to appear on my site. If I bid too high, then ads don't show up, but since I'm not making much money anyway, I probably won't care. My visitors will be more likely to come back and read something else I wrote.
I am very much looking forward to good competition in this space. I've tried the Yahoo Beta program and it isn't close yet. I hope it gets better soon.
---
## Microsoft Vista, Ignoring the Tried and True
- URL: https://mattmichie.com/2006/04/25/microsoft-vista-ignoring-the-tried-and-true/
- Date: 2006-04-25
- Categories: windows, security
Bruce Schneier, noted security expert, summarizes some of what is being said
about [Vista's new security
model](http://www.schneier.com/blog/archives/2006/04/microsoft_vista.html). It
is amazing how clueless Microsoft can be in ignoring the security models that
have proven themselves to be successful and useful in other operating systems.
This is one area where I wouldn't give Microsoft flack for not innovating.
Security is tough, learn from the mistakes others have made! I'm very
disappointed with this, especially because NTFS has such a fine grained
permissions system. They could have really pulled off something nice.
Thankfully, I've been using nothing but Linux and Apple OSX for the past
month. If more games were available for OSX, there would be no need for
Windows in my life ever again.
---
## Yahoo Slurpy Verifier
- URL: https://mattmichie.com/2006/04/24/yahoo-slurpy-verifier/
- Date: 2006-04-24
- Categories: internet, yahoo
Some kind of beta webcrawler from Yahoo has been hitting my site in weird ways. It crawled one page 41 times today so far, sometimes less than a minute apart. Uhhh? Yahoo?
The user agent is `Slurpy Verifier/1.0` and it is coming from `66.228.164.201` / `rdev25.yst.corp.yahoo.com`.
```
24/Apr/2006:04:54:17
24/Apr/2006:04:55:20
24/Apr/2006:05:09:19
24/Apr/2006:05:10:12
24/Apr/2006:05:25:35
24/Apr/2006:05:26:51
24/Apr/2006:05:40:03
24/Apr/2006:05:53:00
24/Apr/2006:06:08:24
24/Apr/2006:06:23:49
24/Apr/2006:06:39:04
24/Apr/2006:06:55:50
24/Apr/2006:07:10:21
24/Apr/2006:07:26:04
24/Apr/2006:07:41:15
24/Apr/2006:07:57:16
24/Apr/2006:08:13:54
24/Apr/2006:08:25:44
24/Apr/2006:08:41:38
24/Apr/2006:08:56:35
24/Apr/2006:09:09:55
24/Apr/2006:09:25:36
24/Apr/2006:09:42:03
24/Apr/2006:09:57:09
24/Apr/2006:10:11:12
24/Apr/2006:10:25:53
24/Apr/2006:10:41:22
24/Apr/2006:10:56:33
24/Apr/2006:11:11:46
24/Apr/2006:11:25:46
24/Apr/2006:11:39:40
24/Apr/2006:11:55:19
24/Apr/2006:12:13:24
24/Apr/2006:12:25:08
24/Apr/2006:12:40:09
24/Apr/2006:12:53:50
24/Apr/2006:13:11:00
24/Apr/2006:13:24:19
24/Apr/2006:13:41:08
24/Apr/2006:13:53:56
24/Apr/2006:14:09:42
```
---
## Waiting For Python Web Frameworks
- URL: https://mattmichie.com/2006/04/23/waiting-for-python-web-frameworks/
- Date: 2006-04-23
- Categories: python, ruby, django, rails, turbogears
I've tried out Turbogears and Django, ultimately putting together a quick prototype in Django, because the built in admin interface was the only thing left for me to complete. It was simple enough to port over my object from Turbogears, add in some meta data and push the whole thing to "production".
Unfortunately, I started coding in Django right before the "magic" removal branch went public. The documentation didn't mention anything about a massive API change that seems to require lots of changes to any code you write. Not that it is too important to me, it will be faster for me to start over and move the methods into the new branch. Still frustrating.
Of the two, I think Turbogears has the long term advantage. I love the fact that someone took the time to integrate a bunch of seperate programs into a whole (it's not quite coherent yet). The desire to re-invent the wheel is strong with all programmers and I've done it myself a couple times. Turbogears also is not quite ready, they have some nice widgets that will be a joy to use, but when I tried, I couldn't find any documentation beyond the wiki. The example in the wiki didn't work with my build, so I decided I would come back to it after I had tried Django. Maybe after they come out with 1.0.
Which leaves me to ponder trying out Ruby on Rails. Frankly, I've been avoiding it because I want to stick with Python. I've been using Python for all my Unix Scripting and I love the way it is put together. I've heard good things about Ruby, but I also want to deepen my Python experience, not dilute the languages I know with yet another one. But considering Rails is past 1.0 and is gaining momentum, it would be a mistake not to look into it further.
There is no doubt in my mind that I ever want to go back to writing straight PHP if I don't have to though. These new frameworks make writing web applications a joy. The thought of thousands of lines of poorly written PHP make me shudder.
---
## Dynamic Languages on the JVM
- URL: https://mattmichie.com/2006/04/22/dynamic-languages-on-the-jvm/
- Date: 2006-04-22
- Categories: java, python, ruby, django
I've been focusing on Python lately, mostly for web development. It is
strange, but it doesn't quite feel ready yet. Obviously, there are large
production sites deploying on some of the frameworks like
[Django](http://www.djangoproject.com/), but compared to Java and Tomcat,
Python web development is still in the infant stages. Even so, the
productivity that Python provides over Java is astonishing. PHP just makes me
laugh, though PHP 5 does clean up a lot of the warts. The only good thing I
can say about PHP right now is that it is ubiquitous and easy to learn. I
don't know how I missed it but in late 2004, there was an awesome [meeting of
the minds](http://www.tbray.org/ongoing/When/200x/2004/12/08/DynamicJava) at
Sun which included:
* [Larry Wall](http://www.wall.org/~larry/)
* [Guido van Rossum](http://www.python.org/~guido/)
* [Jython](http://www.jython.org/) folks
* [Groovy](http://groovy.codehaus.org/) folks
* [Parrot](http://www.parrotcode.org/) people

If Sun would release the JVM under the GPL or BSD or even the Mozilla MPL, and
create awesome support for dynamic languages, it would explode all over the
web server scene. Heck, I would pay good money for a JVM that had first rate
support for Python. It would also help consolidate Ruby, Python, Perl and
Java. I guess Parrot could do this, but honestly it will take years for it to
be as fast as the JVM on all the platforms Java currently supports. The JVM is
an impressive bit of Sun kit, but Sun has tied too closely to the Java
language. Sun, open up the JVM even if you keep the Java spec under your
control. This is the best of both worlds and would take a major bite out of
.NET. Unfortunately, Sun will probably let the JVM wither away just like they
are doing with Solaris. Sigh.
---
## My Internet Drives Me Crazy
- URL: https://mattmichie.com/2006/04/21/my-internet-drives-me-crazy/
- Date: 2006-04-21
- Categories: comcast, internet
In the past I haven't had a lot of trouble with Comcast Broadband, but for the past couple days it has been dropping packets all over the place. ARRRRRGH.
```
--- comcast.net ping statistics ---
624 packets transmitted, 95 packets received, 84% packet loss
round-trip min/avg/max/stddev = 68.991/400.410/3449.330/765.964 ms
```
**UPDATE:** I upgraded my firmware on my wireless router and things started working. One of the most bizzare network issues I've seen, since I hadn't touched anything on that router for about 2 years, and the problem was intermittent. I got rid of the old Sveasoft WRT54 firmware and upgraded it to [DD-WRT](http://www.dd-wrt.com/).
---
## Tandom Story Comedy
- URL: https://mattmichie.com/2006/04/20/tandom-story-comedy/
- Date: 2006-04-21
- Categories: writing
Ran across this gem on Kuro5hin:
> _In-class assignment for Wednesday April 5, 2006: **Tandem Story**. Each person will pair off with the person sitting next to them. One of you will then write the first paragraph of a short story. The partner will read the first paragraph and then add another paragraph to the story. The first person will then add a third paragraph, and so on until both people agree a conclusion has been reached. The story must be coherent, and each paragraph relevant to the prior one._
...and here's what one pair turned in!
**Rebecca and Gary**
English 144A Creative Writing
---
At first, Laurie couldn't decide which kind of tea she wanted. The camomile, which used to be her favorite for lazy evenings at home, now reminded her too much of Carl, who had once said in happier times, that he liked camomile. But she felt she must now, at all costs, keep her mind off Carl. His possessiveness was suffocating, and if she thought about him too much her asthma started acting up again. So camomile was out of the question.
Meanwhile, Advance Team Captain Carl Harris was leading his patrol squadron into orbit over Skylon 4. Carl had more important things to think about than the neuroses of that air-headed asthmatic woman named Laurie who, after one sweaty night over three months ago, was still desperately clinging to an illusion of a relationship she had fabricated in her unbalanced mind. "Alpha Tango One to Geostation One-Niner-Three", he said into his subspace communicator. "Polar orbit established. No sign of resistance..." But before he could sign off a bluish plasma beam flashed out of nowhere and blasted a hole through his ship's cargo bay. The jolt from the direct hit threw him out of his seat and into the cockpit control panel. He hit his head and died almost immediately, but not before he felt one last pang of regret for psychically brutalizing the one woman who had ever had feelings for him.
Soon afterwards, Earth stopped its pointless hostilities towards the peaceful farmers of Skylon 4. "Congress Passes Law Permanently Abolishing War and Space Travel", Laurie read in her newspaper one morning. The news simultaneously excited her and bored her. She stared out the window, dreaming of her youth -- when the days had passed unhurriedly and carefree, with no newspapers to read, no television to distract her from her sense of innocent wonder at all the beautiful things around her. "Why must one lose one's innocence to become a woman?" she pondered wistfully.
Little did she know, but she has less than 10 seconds to live. Thousands of miles above the city, the Anu'udrian battleship launched the first of its lithium fusion missiles. The dim-witted, bleeding-heart peaceniks who pushed the Unilateral Aerospace Disarmament Treaty through the U.N. had left Earth a defenseless target for the hostile alien empire who was determined to enslave the human race. Within two hours after the passage of the treaty the Anu'udrian ships were on course for Earth, carrying enough firepower to pulverize the entire planet and nothing to stop them. They swiftly initiated their diabolical plan. The lithium fusion missile entered the atmosphere unimpeded. The President, in a submarine off the coast of Guam, felt the inconceivably massive explosion which vaporized Laurie and 15 million other Americans. He slammed his fist on the conference table. "I KNEW this would happen! I am exercising my executive privledge to annul that treaty effective IMMEADIATELY! Ready the nukes, we're gonna blow those bastards out of the sky!"
---
This is absurd. I refuse to continue this mockery of literature. My writing partner is a violent, chauvinistic, semi-literate adolescent.
Yeah? Well, you're a self-centered tedious neurotic whose attempts at writing are the literary equivalent of Valium.
Asshole.
Bitch.
---
## Cryptome China
- URL: https://mattmichie.com/2006/04/20/cryptome-china/
- Date: 2006-04-20
- Categories: china, censorship
The [Cryptome](http://cryptome.org/) network has opened a [Chinese
Branch](http://cryptome.cn/) with materials censored by the Chinese
authorities.
---
## Chinese Freedom
- URL: https://mattmichie.com/2006/04/14/chinese-freedom/
- Date: 2006-04-14
- Categories: china, censorship, google
I've been passing time watching documentaries. Along the way, I've discovered that [Errol Morris](http://www.errolmorris.com/) is incredible. Yesterday though, I watched the BBC's take on Auschwitz followed by PBS Frontline's excellent Tank Man. Tank Man is the Chinese citizen who stopped a column of tanks holding two plastic shopping bags.

Seeing how few people stood up to the Nazis and their death camps, and the difference that those who did made, it was even more striking seeing Tank Man. It is clear that one concerned citizen can make a difference.
In China, huge economic reforms were taken after the 1989 Tiananmen Square uprising at the cost of any political reform. In essence, the city people traded freedom for wealth. I suppose the root of the idea is as old as giving the people their quotient of circus and bread, but China took it to an extreme. The fact that it was so easy and the people went along so well made me examine my own country, the U.S.A.
We've heard a lot lately from Ben Franklin's quote, "Those who would give up Essential Liberty to purchase a little Temporary Safety, deserve neither Liberty nor Safety." We're all still trying to find the right balance here after 9/11, and it feels like many people feel we went a little too far trying to find elusive safety, giving up essential freedom along the way.
Beyond safety though, it seems that we all are willing to give up essential liberty for purchases. Give a citizen a cell phone, an iPod, cable TV, and a nice car, and he's not going to be concerned with politics. Most revolts seem to stem from widespread economic disparity. After all, the American revolution was started over unfair taxation.
For all of China's booming success, the economic disparity is growing daily. The capitalistic approach has largely been benefiting the cosmopolitan city dwellers, with the peasants providing near slave labor in the factories. How bizarre that a country that started out as Communist is only increasing the differences in the classes. In fact, in the country most peasants can't afford to send their children to school.
Frontline gave some statistics on the confrontations happening between the Chinese government and the peasants and they have been increasing dramatically every year. There is a good chance that there will be another Chinese revolution if the economic reforms don't move to more people in the country. One can hope that it will give the Chinese people the freedom that they deserve.
Seeing Tank Man stand up to those tanks made me want to stand up for the Chinese people too. It is distressing that many companies helping China oppress their citizens are American. Google's China presence censors out all references to Tank Man in their image search:
- [Google China](http://images.google.cn/images?svnum=10&hl=zh-CN&sa=X&oi=spell&resnum=0&ct=result&cd=1&q=tiananmen---square)
- [Google America](http://images.google.com/images?q=tiananmen---square&hl=en&btnG=Search+Images)
It is heartbreaking to see how much this one man was willing to do to stand up for freedom and then seeing American companies with American employees going along with censorship because they are making a lot of money. They clearly took the same bargain with the devil that many Chinese did. As long as their stock options increase, what does Google care that they are helping to oppress people on the other side of the world. Do No Evil as long as you can Get More Money.
Ten years from now are we going to see Google employees claiming they were "just following orders?"
Tank Man is going to stay with me for a long time.
---
## Hivearchive.com Launched
- URL: https://mattmichie.com/2006/04/11/hivearchive-com-launched/
- Date: 2006-04-12
- Categories: hivearchive
I've setup a Wordpress weblog at [hivearchive.com](http://hivearchive.com).
Check it out, thanks!
---
## ClaimID Review
- URL: https://mattmichie.com/2006/04/11/claimid-review/
- Date: 2006-04-11
- Categories: claimid, web 2.0, review
I surf the web. A lot. Way more than average. I revisit sites like
[Slashdot](http://slashdot.org), [Digg](http://digg.com), and the daily
[del.icio.us most popular](http://del.icio.us/popular) pages often. Doing
this, you will run across a lot of "Web 2.0" startups which have a beta you
can test as soon as you sign up for the site. I usually pop in my e-mail and
forget completely about the site. Occasionally, I'll even go all the way
through the sign up process, get bored and move on.
[ClaimID.com](http://claimid.com) was one such startup: _ "ClaimID is a
service that lets you claim the information that is about you online. That
information is then associated with your name, providing folks an easy way to
see what is and isn't about you online. In doing so, you get to influence the
search engines, and provide people more relevant information when they search
for you. It's time to reclaim some power back from the search engines. ClaimID
is about letting you have some say in what search engines say about you." _
This sounds mildly interesting, but it didn't solve a pressing problem for me.
If you search Google for Matt Michie or "Matt Michie" the top results all
relate to me and don't contain anything I wouldn't want a potential employer
to see. ClaimID popped back onto my sonar after I was doing some searches
manually. I am currently in the job market, and it would be foolish not to
check what Google and other search engines think about me. On my search
results, my ClaimID page was ranked very highly, which surprised me since I
hadn't added any links. Immediately, I began to use the service, to make full
use of the highly ranked result. It is obvious the ClaimID guys are doing some
good SEO on the site, and that other people are starting to link into it,
giving it some good PageRank juice. Google has changed their algorithm
recently to rank higher those pages which contain your search result in the
URL.
In this case, [my ClaimID](http://claimid.com/mmichie) contained parts of
my name, and this combined with ClaimID's PR of 5, boosted it right up. I was
able to put together a decent summary of my web presence in about 10 minutes
using the handy bookmarklet and a couple of categories. In the future, I will
probably put this URL on my resume so that employers can go directly there,
and I will worry a little less about what strange things they might attribute
or misattribute to me. ClaimID also conveniently caches the links that you
find, so if something is moved or deleted, you have a record of what you've
done or people have said about you. Even though it is still Beta, I haven't
found any glaring flaws. It is a bit odd that the picture you can post in your
profile isn't resized and saved on their servers, but I'm sure that is being
worked out. The interface is clean and has some nice AJAX goodness where it
makes a difference. The service is currently free and there are no
advertisements yet, so I'm not sure what the eventual business model is going
to be. They probably aren't either.
It is still a bit of a new frontier. I felt myself becoming a bit nervous about
how much information someone could glean from my ClaimID profile until
I realized they would be able to get the same information from search engines,
without my editorial control. In some ways, Scott McNealy was right in that we
don't have privacy, but with ClaimID I won't have to get over it and I can start
claiming it.
## Links
* [ClaimID](http://claimid.com)
* [Matt Michie's ClaimID](http://claimid.com/mmichie)
---
## Hello World
- URL: https://mattmichie.com/2006/04/11/hello-world/
- Date: 2006-04-11
- Categories: wordpress
I've been sitting on this domain for awhile for a project that hadn't gone
anywhere, and I decided it was going to waste. I wanted to try out Wordpress
and start up the writing chops again. This seemed like a good opportunity to
do so. So far Wordpress has been pretty impressive, we'll see how this
experiment goes.
---
## PHPWiki -> DokuWiki
- URL: https://mattmichie.com/2005/11/02/phpwiki-to-dokuwiki/
- Date: 2005-11-02
- Categories: wiki
I have a PHPWiki backup that I want to convert to DokuWiki format, anyone know
of a script to do so by chance? It looks like I'm going to have to write it
myself...
---
## Been busy.
- URL: https://mattmichie.com/2005/10/22/been-busy/
- Date: 2005-10-23
- Categories: meta
Haven't really spent much time on the site lately, I have a backlog of BSOD
pics to post. Hopefully I'll get to them soon!
---
## Disable CDDB Lookup in Winamp
- URL: https://mattmichie.com/2005/06/15/disable-cddb-lookup-in-winamp/
- Date: 2005-06-16
- Categories: tips
To disable the annoying CDDB lookup with Winamp:
Right click on Winamp window -> Options -> Preferences -> Input -> CD/LineIn
plugin -> Configure...
Uncheck the use CDDB checkbox.
Joy.
---
## PC Magazine Likes Us
- URL: https://mattmichie.com/2005/06/05/pc-magazine-likes-us/
- Date: 2005-06-05
- Categories: bsod
Normally I don't put much stock in any type of "web awards", but I am tickled
a little bit that [PC Magazine](http://pcmag.com) decided to give some props
to the [Blue Screen of Death](/archive/bsod/) gallery. Unfortunately, their
marketing department decided to inform me about this after the magazine was
already pulled off the rack. Smooth, they could have gotten a couple sales from
me just so I could brag a little.
[Named to PCMag.com Top 100 Sites for 2005, Fun, Games & Oddities
Category](http://go.pcmag.com/2005bestwebsites)
---
## New hivearchive member
- URL: https://mattmichie.com/2005/03/27/new-hivearchive-member/
- Date: 2005-03-28
- Categories: sysadmin
I setup [Faultline's Blog](http://faultlined.com/blog), along with the
infrastructure to make it all work. DNS, Mail, Hosting, Database. Its pretty
satisfying when it all comes together. Give his blog a read.
---
## Microsoft Disconnect
- URL: https://mattmichie.com/2005/01/16/microsoft-disconnect/
- Date: 2005-01-16
- Categories: linux
I know that Microsoft has quite a few brilliant people working there, but I
was amused by the disconnect that [Linux in Embedded
Systems](http://blogs.msdn.com/mikehall/archive/2005/01/13/352470.aspx) showed
towards embedded Linux. I like the fact that someone posted a link to my [BSOD
Gallery](/archive/bsod/) showing how well Microsoft has done on the embedded
market. I love my WRT54G which runs Linux on it and has been extremely stable, I
can't imagine any reason why someone would run CE or XP embedded in a device
like a wireless router. Linux seems the perfect choice.