FoundryVTT Module Test Automation

I really loath manual testing. In a pro­fes­sion­al setting, nearly all of my projects are developed using TDD (test driven de­vel­op­ment). However, a bit to my em­barass­ment, most of my personal projects haven't received this level of care. In this article, I'm going to overview how I bucked that trend by in­tro­duc­ing testing to a friend's project.

Back in 2017, I started GM'ing the FFG Star Wars Tabletop RPG for my friends. Over the years, folks moved and eventually the game migrated online. In early 2021, a friend suggested I explore FoundryVTT. It quickly became our favorite tabletop RPG platform due to its ex­ten­si­bil­i­ty.

We used the Star Wars continue.

String Concatenation - Root of all Evil

After college, I spent three years in software security acting as a pen-tester. It was my job to identify security vul­ner­a­bil­i­ties in the company's software via ex­ploita­tion. During that time, string con­cate­na­tion was the root cause of the vast majority of my findings. For that reason, it is my general philosophy that:

If you're con­cate­nat­ing strings, you're doing it wrong.


To make my point easier to grok, let's start with a simple example:

>>> person.first_name + " " + person.last_name
'Bob Smith'

We've joined a person's first and last name with a space. The con­cate­nat­ed value can be thought of as a space delimited string. In of itself, this is continue.

Vertical Rhythm

I've always found interface usability fas­ci­nat­ing. Subtle dif­fer­ences in coloring, spacing, and layout can dras­ti­cal­ly impact the func­tion­al­i­ty of your ap­pli­ca­tion. I think it's important for pro­gram­mers to understand some of the basic principals of usability.

A few years back, I read about a design concept referred to as Vertical Rhythm. The way I like to think about it is to imagine a web page as a sheet of lined paper. All text is written upon the lines, which is referred to as the baseline. A heading could pass through multiple lines, but it shouldn't impact the following text's ability to align with the baseline.

Why go through the continue.


I love the notion of a clean, repeatable install. In my side projects, I've his­tor­i­cal­ly ac­com­plished this through strict doc­u­men­ta­tion practices and directory or­ga­ni­za­tion. However, this process inevitably breaks down for me when a machine becomes multi-purpose.

Either locally or in the cloud, I'll end up installing packages, hacking together con­fig­u­ra­tion, or otherwise making the en­vi­ron­ment murky. In fact, the server that currently hosts this blog is a perfect example. This instance hosts this site, riiga.net, and has been a sandbox for toy projects I've worked on over the past two years.

While I'm reasonably confident I can redeploy this machine within a couple of hours, it would be far continue.


For a long while I've wanted to host this blog rather than utilize a service like Google's blogger. My biggest hesitation was blogging software tends to be a common means of getting pwned. I could write straight HTML, but then the content is mingled with the markup - it feels dirty. FrontPage you say? Well, that's just not cool enough.

Enter Acrylamid, a simple, but powerful means of generating a static website. Out of the box, it supports:

To convert the contents of the old blog, I downloaded it using Google Takeout. Through a com­bi­na­tion of xpath, html2text, and some python hackery, I converted the continue.

CakePHP's error handling

Whenever possible, I like to trigger the ap­pro­pri­ate HTTP status code for an error. CakePHP has a mechanism to throw 404 errors by simply calling:


This is handy when a request to a view action passes an id that doesn't ac­tu­al­lyex­ist. However, what about 403 or 500 errors? If you're like me, you probably stumbled upon AppError in the CakePHP book.

I defined a simple error403 method, and used it where ap­pro­pri­ate throughout my ap­pli­ca­tion. But when I rolled out to production, every 403 became a 404! Upon a bit of digging around in the code, I found the root of the problem in the Er­rorHan­dler con­struc­tor. In continue.

Asus P4C800 Rev 2

This board has been my latest personal hell. Back in the year 2005, my Asus P4C800 Deluxe fried. After taking their time, Asus sent me a re­place­ment board. I simply assumed that it was a Deluxe and re­in­stalled it. Un­for­tu­nate­ly, it was actually a P4C800 Rev 2. There are three models of the P4C800: P4C800, P4C800 deluxe, and P4C800-e deluxe. From what I can tell online, the Rev 2 is actually the e deluxe, but it looks like a hacked together mix between the P4C800 and the e deluxe.

This is where I made a mistake. One night when trying to get suspend to work in Linux, I continue.

GBA Development on a Mac

In my media devices ar­chi­tec­ture class, we are developing on the GBA. Un­for­tu­nate­ly, most of the students are developing on windows machines, which leaves me and a few others the odd men out. On macs, we're using devkitarm as our compiler with a provided makefile. Un­for­tu­nate­ly, the Makefile had a few flags mis­con­fig­ured.

The stock makefile worked perfectly until we started dealing with sound. The problem was two fold:

  1. Setting the interrupt handler would cause the GBA to reset
  2. Sound files larger than thirty seconds would overflow the ewram

There were two macros in the make file that were used for compiling and linking re­spec­tive­ly:

MODEL = -mthumb -mthumb-interwork
SPECS = -specs=gba_mb.specs

The continue.

Microsoft Natural Ergonomic

I decided I wanted to enable the zoom key on my "Microsoft Natural Ergonomic Keyboard 4000" under Linux. Ideally, this would be used for scrolling up and down a page instead of triggering Compiz's zoom feature.

Un­for­tu­nate­ly, the kernel fix is triaged on ubuntu's bugtracker. This of course meant re­com­pil­ing the kernel manually (or semi-manually since Ubuntu makes this task relatively easy). You'll notice, if you care to check, that there is a patch in the bugtracker to remap the zoom and spellcheck keys to something that xev (and therefore X11) can read.

If you don't know how to recompile your kernel, this fix probably isn't for you. However, continue.

Mac OS X Snow Leopard Port Wine

Currently, wine is not happy with my 64bit upgrade to Snow Leopard. Just for the record, I find no fault in either port or wine for this, because I was an early adopter. I upgraded port with a simple reinstall. (I know there are more elegant solutions than this, but I was being lazy.) After upgrading port, installing wine resulted in the following error:

Error: wine 1.0.1 is not compatible with Mac OS X 10.6 or later. Until wine 1.2 is released, please install wine-devel instead.

This is pretty straight­for­ward. Obviously, the next step was "port install wine-devel". However, I was promptly stopped with another error in continue.