We Are Flanders Fields

On this Remembrance Day, as always, we think of our armed forces. We watch them parade, we wear poppies, we listen to speeches. We share our moment of silence. It is on Remembrance Day that we make time to honour those who have served as heroes. Many of us think we could never give so much. Could never be so brave. Impossible. Impossible.

But we forget that heroes are just everyday people in extraordinary circumstances. In forces past and present, the ranks were filled with everyday people; electricians, bakers, farmers, students, and cooks. Whatever their origin, whatever their reason, a call was heard. They answered. They became heroes, dead and alive; wounded or miraculously unscathed. They showed us then and now what it means to stand for others, to stand for us, to stand for you.

On this Remembrance Day, remember them as you remember yourself. Full of fears and hopes. Longing and pride. Itches, sneezes, and swears. Remember them as everyday people.

On this Remembrance Day, remember that we and they are the same. We are everyday people. They stand for us. We stand for us. They serve. We serve.

On this Remembrance Day, you too can serve. Your city, your neighbourhood, your home. Find three ways to serve – because you too are everyday people.

And everyday people do the impossible.

Continue Reading

Focus Zoom Just Like Mama Google Used To Make

I hate math.

When I say I hate math, I’m not saying that math is objectively bad. Mathematics have elegance and simplicity. They’re the purest expression of logical thought that I can think of. Mathematics are involved in every single technological advance since the wheel of sliced bread on fire 1. Computers, fundamentally math based machines, provide me my living. I literally eat because of math.

Still, though, I hate math. At least when it’s happening to me. It’s an activity that requires me to hold a multitude of abstract concepts, complex mappings, and relative truths in my head at once. Math is just too dense for my brain to comfortably unpack it and relate it to the real world. It’s like surgery. I’m 100% on board with mathematics when an expert doing it, but when I have to get involved, I’m just the guy standing with a knife wondering which part to cut.

That’s the real problem that I have with math. Once all the parts are labelled, and all that’s left is rearranging stuff to get the desired result, I’m golden. Regardless of my preference, I have to actually do it from time to time. 2

The most recent case was writing a Google Maps style scroll zoom for a recent contract. They have a viewport div with a much, much larger content div, and a desire to move about it.

The behaviour is easy to describe:

  1. it should pan when the mouse is dragged
  2. it should zoom the content canvas when the scrollwheel turns
  3. it should hold the point under the mouse cursor fixed when zooming
  4. it should not jump about as though you threatened it when you zoom

Panning was dead easy, just set the viewport’s leftScroll and topScroll properties. For zoom, though, it just liked to break rule number four. Strategy One was to find out if anyone had already described the solution somewhere. Zilch.

Strategy Two, then: mimic what I could reverse engineer from Google’s approach, and then fix the rest. Turns out that they use CSS transforms and set the transform-origin to the mouse location, which makes a lot of sense. At first, this worked for me too, but then fell apart once I zoomed at a different location.

Strategy Three consisted mostly of crying and fiddling desperately for a couple minutes with various parameters in the vain hope that I’d stumble upon the solution by accident. Maybe if I scale the – no, that’s worse… what about unscali – nope.

There are just so damn many points relative to other points in differently scaled units to come at it head-on. To complicate further, this is a graphical problem, making it hard to get meaningful data, and even harder to locate the failure points. I knew I needed to pan to offset the “movement” caused by the scale.

Ugh. Fine. It’s math time.

Immediately, this:

Movie Math

“Math is whooshy” – Hollywood

Turned into this:

Movie Math

“Maybe they only said they wanted zoom, but meant waffles instead.” – Me

So, just like in grade seven, I went to my dad. He’s an electrical engineer, much better at math than me, and has actually had to deal with a similar problem for a project of his own. Through many trials, he eventually got me to stop chasing deltas and explained that the easiest way is likely to do everything with units, like physics, and work on the unscaled version. He made the first incision and helped to label everything, which is exactly why you should make your dad be an engineer, too.

Here’s what we came up with:

First, everything we do for X can be repeated for Y, so let’s focus on one dimension.

Next, There are two units of measurement. Screen Pixels (px), and scaled virtual distances, Canvas Units (cns). The scale factor is the ratio of px/cns.

Call the point we want to zoom around Focal Point, which for us is the mouse cursor. Since everything is relative to something, lets use a second subscript to denote what it’s relative to. For example, the viewport’s origin, relative to the canvas, is Xvc.

Now, the Focus Point, relative to the canvas (Xfc), can be described with: 3

            Xvc px + Xfv px
Xfc cns = ------------------
             S px/cns

Now to scale it. Let’s prime everything to denote after-scale values:

             X'vc px + X'fv px
X'fc cns = ---------------------
               S' px/cns

There are a couple of facts that are helpful here:

  1. X’fv px = Xfv px, because they are both the focus point, relative to the viewport in raw px, and so does not change.
  2. Further, X’fc cns = Xfc cns, since they both refer to the same logical location relative to the canvas and in canvas units.

We can sub in the equivalences and rearrange to solve for the X’vc px. This is what the viewport’s offset needs to be to compensate for the scaling.

X’vc px = ( Xvc px + Xvf px ) * (S’ px/can / S px/can) – Xfv px


  1. An invention far ahead of its time.
  2. Math, that is, not surgery. Though I prefer to do both in a dark alley.
  3. Here we divide by the scaling, because we’re stretching the canvas, not the viewport. If your viewport was scaled, then you’d multiply.
Continue Reading

TinyMCE, poltergist, and minification

We’re working on a project now that needs a good WYSWIG type editor. Our old favourite, TinyMCE, wins the spot. TinyMCE, of course, is Javascript and so we need Capybara to run Poltergeist to be able to test.

Minified TinyMCE downloaded and installed. Runs fine in a browser from localhost, but then fails to load in Poltergeist, stating that it couldn’t find its files. For some reason, it was looking relative to the root path. You can use the baseURL attribute in settings to point to a direct location, though.

That solved the location problem, but then produced errors like:

Failed to load: /javascripts/lib/tinymce/plugins/save/plugin.js
Failed to load: /javascripts/lib/tinymce/plugins/autoresize/plugin.js

Notice the lack of a .min.js extension? What wasn’t made clear in the SO post is that baseURL must be paired with the suffix attribute to load minified files:

tinymce.baseURL = '/javascripts/lib/tinymce';
tinymce.suffix = '.min';

There you go: I just saved you a half-day of annoyance. Exit through the gift shop.

It’s a little gross if you need to switch between full and minified, and there may be a better setting to use, but I’ve spent too much time on this problem already. If you know a better way, feel free to drop me a line.

Continue Reading

When to Use HTTP 401 vs 403

I’ve been making a Sinatra plugin to better support Tenjin‘s Story Oriented process 1.

Here’s my final decision: 401 is for Identification, and 403 is for Permissions.

HTTP Code Server Says Server Means
401 Unauthorized I’m not telling you anything until you show me some ID
403 Forbidden Your ID is valid, but you don’t have clearance

This is a little contrary to what the spec actually states, but with good reason. The full RFC includes a statement that (emphasis mine):

If the request included authentication credentials, then the 401 response indicates that authorization has been refused for those credentials.

To me, applying this rule would make 403 nearly or totally useless. If there is a file that nobody may ever access via HTTP, it’s better that the server not tell anyone about it (404). Sharing existence information would only be potentially harmful; it’s admitting that a file exists that is also important enough to protect.

As a developer, I’d rather have a distinction between “I don’t know you” and “you can’t do this” over trying to detangle both. I’m not the only one to feel this way, either.

Just because something is standardized, doesn’t mean it can’t change. Those original standards are from fifteen years ago, and the way we use the internet has changed drastically. We’re moving away from the web-addresses-as-file model and toward web-address-as-command. Holding on to irrelevant or misguided standards just because they’re standards won’t help anyone.


  1. More on this later. There are half-written posts, I promise.
Continue Reading

So This Is Goodbye

Grooveshark shut down this past Thursday.

It hit me harder than it arguably should have. Yes, it is a fundamental, unexpected interruption to the way that I work, but there’s something more to it. It’s just a music service after all. I didn’t know anyone who worked there, and I didn’t have any stock in the company.

Maybe it’s because my ravenous exploration of new music helped me through the difficult transition period around 2011. Grooveshark was the provider of much-needed colour in my life. Grooveshark hummed away while I finished my degree, redefined myself, grew into leadership, and built a business. I had discovered thousands of tracks and organized them carefully into task-oriented playlists.

And here I was, scrambling to hopefully retrieve whatever data I could before it was gone forever. Search and rescue for refugee data from a failed corpo-state. My computing wizardry skills at least meant that I managed to make it out with around 60% to 80% of my collection’s listing. That’s more than some can say.

Shortly after hearing of the service’s demise, but before discovering the Reddit tutorial, I realized that my laptop would still have a copy of the last page I was on until I refreshed. Opening it, I saw the player there, forever frozen halfway through the last song Grooveshark would ever play for me: an alternatively-labelled Porcelain by Moby.

Call Me Ishmael

Sometimes life imitates art.

Continue Reading

Simple Kettle is Best Kettle

My parents bought a new electric kettle.

After nearly 4 years of regular trips up the centigrade scale, the rotund Hamilton Beach began sputtering out. Before a complete hot-beverage emergency could froth up, my mother began the arduous process of finding a replacement.

The old kettle.

Goodnight, sweet prince.

You might think that this would be easy, but you would be wrong. Kettles these days seem to either be made with flimsy material, poor ergonomics, 1 or a multitude of modes and configurations. Worse, the price of decently-made kettles has risen since the last purchase. In the end, only two finalists made it through the requirements grindhouse: 2 Simple Kettle, and Digital Kettle.

Digital Kettle has a 4-button control pad and an LCD display. It can boil to a precise temperature (in 5℃ increments), “Keep Warm” (also in 5℃ increments), and can hold the boil for the duration of a timer. The screen was on top, facing up, so you could only see it while standing over it. That screen also lit up, but only while you pressed buttons – there there was no obvious indication of the kettle being on, aside from the eventual boiling of water. I still don’t know if the settings reset every time, or if you needed to manually get it back to defaults.

Simple Kettle turns on and off and has a corresponding light in the switch. 3

If you’ve read this post’s title, then you already know which one was chosen. But this isn’t a story about kettles. 4 It isn’t even really a story about simplicity or clarity in design, either, though both are excellent goals. This is almost a story about user experience, but that’s not quite it either. I’m sharing a story about kettles to make a point about emotions.

Digital Kettle’s problem isn’t that it does too many things. It’s problem is that it leaves the person using it uncertain about what’s going to happen. People feel confused, uneasy, and frustrated. We didn’t want to use this kettle because it made us feel bad feelings. 5

You, me, and several billion other people boil water daily. Kettles don’t exist because water is cold; they exist because people need it to be hot. We need hot water to power our ambition with coffee. We need it to mend a broken heart over tea. We need it to ward off winter’s chill with hot chocolate. Emotion is the atomic driver of commerce. Your job as a designer, developer, and modern-day wizard is to build things for those living, breathing, thinking, feeling people. They’re already feeling things left and right before using your product, and they’ll keep feeling things throughout the entire process.

If you want people to use the thing you built, you absolutely must minimize the bad feelings and maximise the good ones.

And now we return up one level to User Experience (UX), because that’s what it is. UX design is designing emotional experiences. This is why Firefox started apologizing on errors with “Well, this is embarrassing”. It’s why Chrome displays a silly dinosaur and why Microsoft’s Cortana says “The internet and I are not talking right now” when they can’t connect to the net. These builders have recognized that you’ll be frustrated that it isn’t working, so they neutralize your bad feelings with a joke, or an apology, or a silly drawing.

Up another level to the goals of simplicity and clarity. These design tenets are just shortcuts to minimize bad feelings. When there are fewer things to go wrong, fewer things do go wrong. This is the philosophy behind Dirt: everything should do one thing and do it well; otherwise, we’re all in hot water.

Simple kettle is best kettle.


  1. Weight distribution and handling confidence is a big plus when carrying around scalding fluid.
  2. My parents made graphs, even. Okay, that’s a lie, but it wouldn’t be out of character.
  3. I’m told by my electrical engineer father that it’s a neon bulb. I learned a lot more about neon bulbs than I really needed to, because of a kettle. I like my family.
  4. Though they are a hot topic. Ba-dum-ptsh.
  5. Under the logo of Digital Kettle’s maker, Moulinex, is the ironic motto “Life Gets Easier”.
Continue Reading

Managing a GoDaddy email address through GMail

GMail is pretty great. Easy to use, accessible regardless of machine, and free. Both Jason and I like to use it for our primary accounts 1. Back in the day, as shiny new business owners, we obviously also wanted to have gleaming, veneered Tenjin-branded addresses.

So, we originally just set up GoDaddy 2 with “Forwarding”-type, <xyz> addresses and pointed the spam-cannons at our GMail nexus 3 accounts. Fast forward a couple years, and we need to set up a new email account 4. So we just go in, and make a new Forwarding account, right? Ha! Ha! Gotcha. DevOps, IT and other support never Just Works.

Turns out that Google has, in the interim period, changed its policy on how Send-Mail-As works. It needs to log in with SMTP over SSL 5 now.

After far too much googling about Google I managed to piece together some facts:

  1. There doesn’t seem to be any one place where this process, specifically for GoDaddy, is definitively outlined.
  2. Most people in the Google forums essentially tried random combinations until it worked
  3. The ones who didn’t likely gave up and started constructing a colourful logo-shaped voodoo doll
  4. I hate the internet. And the Web. And especially email protocols.
  5. On the plus side, this process will remove the ugly “via” and “on behalf of” sender tags that reveal the original GMail source.

Once many Bothans died to bring me that new information 6, I cobbled together The Solution. Here it is, generalized 7 so that all you need to do is replace “bob” with your appropriate email name, and “” with your own domain.

Tell GMail to manage a GoDaddy email

Bob wants to use to seamlessly manage his GoDaddy email,

  1. Create a regular Godaddy email account – not a forwarding account.
    1. Log into GoDaddy.
    2. Under Products, find Email. Click Launch
    3. If you have a forwarding account, you’ll need to delete it first.
    4. Click Create to create a regular account for the desired address (eg. We have enough from the addresses we’re managing, but you might need to buy a package or whatever.
  2. Login to your GMail account. If you don’t have one yet, create it.
  3. Tell GMail how to send mail through your GoDaddy domain.
    1. Click the Gear icon (top right), choose Settings.
    2. Click on -> Accounts and Import ->
    3. Under Send mail as ->, click Add another email address you own
    4. Name: Your name
    5. Email address: Your GoDaddy email address (eg.
    6. Click Next Step
    7. Use these settings
      • SMTP Server:
      • Port: 465
      • Username: Your full GoDaddy email address (eg.
      • Password: Your Godaddy email account password
      • Select Secured connection using SSL
      • Click Add Account
      • Log into your GoDaddy webmail and grab the verification code that GMail sent. Use that to complete the process.
  4. Tell GMail how to receive mail from your GoDaddy domain
    1. While still under Gear -> Settings -> Accounts and Import,
    2. Scroll down for the Check mail from other accounts (using POP3) section
    3. Click Add a POP3 mail account you own
    4. Email address: Your GoDaddy email address (eg.
    5. Click Next Step
    6. Use these settings:
      • Username: Your full GoDaddy email again (eg.
      • Password: Your GoDaddy email account password.
      • POP server: your POP mail server, which is at your domain (eg. You might also be able to use
      • Port: 995 [this is the SSL port. You want email to be as secure as possible.]
      • Check Always use a secure connection (SSL) when retrieving mail.
      • Leave Leave a copy of retrieved messages on the server unchecked. Enabling this would only eventually fill up the GoDaddy inboxover time. Since we want to use GMail entirely, it makes more sense for this setting to be off.

There you go. That should now run email through your own domain.


  1. I should call them “nexus” accounts. It sounds way cooler to call things a “nexus”.
  2. Yeah, deal with it. I’m sure there are better, hipper Dee Enn Esses out there. It’s a devil-you-know-slash-convenience relationship.
  3. See? I told you. Cool as a Canadian cucumber.
  4. For reasons to be explained later.
  5. Okay, maybe SSL isn’t technically required for it to *work* but I can’t imagine anyone wanting to do emaily things in the clear.
  6. I lie. I already knew #3.
  7. It’s possible that this might be even further generalizable to other DNS providers, but that’s left as an exercise for the reader.
Continue Reading

Switching from Capybara Rack-Test to Poltergeist

We’re upgrading our current project from a traditional multi-paged app to a single-page app. Of course, this means that our integration testing layer will need to change, but so far that’s been a reasonably calm sea.

Choosing a Driver

Following Larry Price’s quick tutorial got me running Poltergeist instead of Capybara-Webkit initially because that’s the order he described them in. I’m so far happy with the choice, and there are rumbles on the Internet that CW could use improvement, but it’s likely just strong in its own ways. In any event, Price’s multi-window woes don’t apply to this project yet, so we’ll forge ahead with Poltergeist and PhantomJS.

I can, however, definitely confirm that running Selenium is slower than the buraucracy at a molasses factory run by Ents 1. Friends don’t let friends TDD with Selenium.

There is a small caveat to running Poltergeist vs running Rack-Test: Poltergeist seems to fail tests much slower. I’m not too worried about it, though, since it would only be punishing if you constantly ran with failing tests.

Installing Poltergeist

To get Poltergeist running, you first need the headless Javascript engine it runs, PhantomJS. Go download and unpack the appropriate tarball into your /usr/local/share/ directory, and then link 2  the binaries into somewhere your path will get it. 3

I chose to link it thusly:

  sudo ln /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/share/phantomjs
  sudo ln /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs
  sudo ln /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/bin/phantomjs

… though you could probably just do the second one.

Turning It On

Next, install the 'poltergeist' gem. After that’s done, you need to tell Capybara to use it by adding this to your cucumber env.rb file.

# in env.rb:
# ...
Capybara.default_driver = :poltergeist

This will now use poltergeist for all tests.

Some Tailoring and Hiccups

HTTP Methods

We have some tests that directly talk to the web API, but Poltergeist’s driver doesn’t allow you to run those HTTP methods in the same way. The easy solution I found was to create the inverse of Capybara’s @javascript tag, which I tagged @no-js. This switches the driver back to the normal, Javascriptless Rack-Test, and lets us use our .follow trick from earlier.

Before '@no-js' do
  @normal_driver = Capybara.default_driver
  Capybara.default_driver = :rack_test
After '@no-js' do
  Capybara.default_driver = @normal_driver

Element Visibility

This was the most sneaky difference so far. Apparently, different drivers are allowed to have different default interpretations of what is “visible” to them. Rack-Test finds hidden form elements 4, while poltergeist does not by default. You can force visibility on, though, by providing visible: true to your Capybara find statements.

Now, next on my list is to be able to type poltergiest Poltergeist correctly on the first try.


  1. Over a minute with Selenium vs at most 18 seconds with Poltergeist
  2. Kudos to StackOverflow users shawn and Ciro Santilli:
  3. Either that, or add the binary directly to your path. You’re on your own for that one.
  4. Before anyone cries foul, we need to set timestamp form variables to make a deterministic test.
Continue Reading

A Capybara Gift From Past Robin

I’m writing this here so that the next time it comes up, I have a permanent record of my solution to this repeating problem:

How do I tell Capybara to follow the redirect after a POST/PUT/DELETE request?

There are likely others like me. Others lost in the bewilderness, pinging between dismissive Stack Overflow answers, blog posts whose solutions refuse to work 1, and the oh-so-helpful folk who dismiss the problem outright, claiming that you should only ever use Capybara through happy little forms and links.

Sometimes, a guy’s just gotta GET, POST, PUT, or DELETE direct to the server. No web form, no anchor tag. Just you and a web API.

The traditional wisdom is that you can call methods like:, param_hash)

… and that’ll send a POST request (or equivalent PUT/DELETE) with Capybara. This doesn’t help me, because these methods won’t follow the traditional RESTful redirect response as I needed. This is what I eventually found in Capybara’s source:

def follow(method, path, attributes = {}) ...

AHA! Gotcha. The secret revealed itself. Just call follow on the page driver instead of get/post/put/delete.

In my case, I used:

page.driver.follow(:put, "/users/#{user_id}", {user: data})

No env.rb tricks, no new gems.

You’re welcome, Future Robin.


  1. Also, whose link from Stack Overflow is now dead, but luckily can eventually be found because the author reposted it
Continue Reading

On Game Jam Virginity

This past Saturday was a sunny affair. A light breeze and a few fluffy clouds gave the entire day that carefree dreamlike quality that summer days are known for. I was fortunate enough to appreciate the Eden-monton 1 on my walk from the train to the coolest brick warehouse I’ve been to.

The Mercer building itself is a modernized hundred-or-so-year old red-brown brick warehouse, complete with floorboards, soft track lighting, exposed brick interiors, and a reassuring aroma of old, solid hardwood. Tall and narrow shipping openings that line the first floor’s north face have been repurposed as windows to the Mercer Tavern. Startup Edmonton’s floors above are dotted with wide latticed windows that welcome in light. Years of hard work have permeated the brick, and now the stalwart old edifice shelters shiny new businesses. It reminds me of an ancient sea shell 2 housing generations of industrious life.

It was there, on that cheerful June morning, that business partner Jason Duncan, former colleague “Young” Matt Church, 3 and I met to participate in a Retro Game Jam. While this was my first time with a jam that doesn’t spread on toast, I was aware of the general format: build as much as you can on a topic within a day or two. This particular jam focused on retro games to limit the scope to something reasonable to complete in a day.

A couple minutes after I filled out our duo to a trio, the organizer called everyone together to kickstart the event with a rough description of what was going on, a standard sponsor presentation & thanks, and then splitting us up into teams. Anyone with an idea could pitch, stand off in a corner, and be joined by those remaining. Most people there already seemed to have a group, though a couple singletons joined other groups. With or without previous connections, everyone there was friendly and welcoming.

We all broke off to get down to business. Young Matt and Jason had previously decided on using Asteroids as our inspiration. Since none of us is exceptionally artistic (in visual arts, anyway) we settled on a low-fidelity, doodle-inspired aesthetic. I got started on art assets while the other two paired on getting the logic into place. First a simple game world, then movement, then turning, then screen-wrapping. 4 It was cool to watch their progress while I got to churn out intentionally bad hand-drawn art and taking trips to record all our audio on my phone in a breakout room. I looked a bit crazy, running off to hide in a breakout rook alone under my jacket, 5 but one must be willing to look the fool for art.

I doubt that too many people there even noticed. The room was abuzz with activity from the various groups. We were lucky to also have sponsor-provided snacks (candy, chips, coke) early on, and sponsor-provided pizza lunch later. That saved us some time in having to go forage a few blocks away for quick, portable food caffeinated sugar.

Screenshot with space rocks

Pew Pew!

After lunch, Young Matt and Jason got the collision detection, shooting, and smokey particle effects in. In the last hour, Jason and I got asteroids spawning at random locations on the screen, with random velocity and spin, and made the game respawn more space rocks as the player pew-pewed them into fluffy oblivion. In the hurried rush of the final ten minutes, Matt added a simple scoring mechanism, I nabbed a font online, and we had our final critical path feature. We completed our build just as time ran out.

Whooshy swirlies that precede space rocks

We covered the random location spawning with a Oscar-worthy wormhole effect.

Overall, the day was a complete blast. Being able to complete a small, working game was a great feeling. A large portion of our success is owed to Young Matt. He came prepared with the Unity installers and previous knowledge of the engine. As always, he pushed ahead at an impressive speed, which is always an asset. 6 The energized environment provided helpful momentum to get past blocks, and kept morale high.

The low-key, just-for-fun atmosphere also prevented stress from mounting until the very last hour or so. I fully recommend attending an event like this if you’re interested in getting into the games industry, want to try a new technology, or just want to get a little side project started. Events like this are a great, low-risk opportunity to test-drive beyond hello-world exercises. If you are new to whatever tech you’re using, get familiar with it beforehand so that you don’t spend all your time learning the gas pedal from the brake.

Our tools:

  1. Unity Game Engine 4.5
  2. MonoDevelop (the unity code editor)
  4. HD Audio Recorder Pro by Motivity Labs 7
  5. Audacity

You can sign up for these things through Meetup, or Eventbrite. I recommend poking into the Startup Edmonton meetup groupbecause they have many different groups’ events listed there. If you’re shy, just bring a similarly-interested friend and you’ll definitely have an easier time. I’d love to see more women at these kinds of events in the future. 8

I’m quite pleased with how this project turned out. We got a full game out of the day, and I’m really happy with the result. The aesthetic was an excellent choice, simultaneously hiding any flaws while providing a chuckle. The gameplay itself was fairly easy to create in the allotted time, especially given a couple diversions down compiling-for-Linux 9 road.


  1. Edmonton is not always so cold as to require you to port a manteau.
  2. I’m told that if you hold it up to you ear, you can hear the internet.
  3. While we all worked at ScriptEase, Matt was so nicknamed for his youthful vigor, an homage to Young Neil of Scott Pilgrim vs the World. Also, he’s literally younger than Jason and I, so, there’s that.
  4. Wrapping was more difficult than expected. Kudos to the original Asteroid designers for doing it on limited resources
  5. A quick and dirty echo-dampening trick I picked up from game modding research. Ideally it would be a heavy-blanket, but I didn’t exactly have much on hand.
  6. Thanks, Matt!
  7. I am very happy with this one. It did exactly what I needed with a simple interface
  8. There was a Ladies Learning Code session held at the same time, and it sort of felt like a Jr. High dance. Hopefully we can get LLC strong enough to start getting more balance.
  9. Still unsuccessful, but it was worth a couple tries
Continue Reading