Thursday, January 31, 2019

finding files on a mac

I find it ironic that the MacOS file management program is called "The Finder" because finding files (like, with a search) is not really one of its strengths.

Here I am trying to find files with "tuba" in the filename:

Besides the clunkiness of having to use an autocomplete-like function to do a filename search rather than also searching file contents, this view is inadequate if you think it would be useful to know WHERE the result was at a glance. (For a while I was thinking you couldn't get the information at all, but if you select the file the path shows up on the bottom.)

Anyway, I prefer the clunky layout of the free app EasyFind:
It's easy to sort by location, which I find useful in many cases.

If you don't mind paying $8 or so some people prefer Find Any File, which offers a hierarchical view.

Heh - one of my first big tech rants was in 2004 when Windows switched to a sidebar integrated search vs the previously perfectly serviceable standalone mini-program. For Mac too, I find the habit of having just the same kind of display for search results as for folder contents as being a bit of a misthink.

Some people (not me in particular, but I was stuck on Windows til 2013) long for the old old days of Mac, where there was only ever one window for a folder, and it would remember its location etc. It added a certain realness and physicality to the file system, I think.

But then again, from Windows "My Documents" to iOS's too little too late "files" app, OSes kind of don't want regular users thinking in terms of filesystems. And to be fair, it probably is simpler for many folks, but as soon as the folks want to level up and, say, back up their files on their own, or in general not be so beholden to a particular cloud service, it's annoying. (In the windows days C:\DATA was always "my stuff", and transferring to a new PC was pretty easy. These days I stuff everything into Dropbox, which is nicely multiplatform and straightforward in its folder->server mapping.)

Monday, January 28, 2019

timelines title image

I wanted to add my recent timelines project to my alienbill portfolio page - recently I redesigned that page to have fancy titles for the main attractions - I thought for timelines I would take a whole-document screenshot (with Fireshot) than copy and paste lines from that into the title "TIMELINE" (Guess I don't need the S, really, which means all the letters are composed of straight segments).

Here was the first result as seen on the page:

It had some legibility problems, so I went it and hand cut the whitespace around each letter:

Not quite perfect, but good enough.

Sunday, January 27, 2019

amazing playful interactive artsy stuff in browsers by david li

A friend linked to choir, an amazing software toy - a bit like my old favorite mobile app Bebot (a "robot synth") but with a choir and fascinating pseudo-photo-realistic visuals and physics.  (On my old Macbook Air, chrome struggled with it but firefox was fine, as was mobile.)

He has some other amazing works as well - "Character Soup" was a lot of fun with some probably relatively simple but well done fluid physics - the combination of that along with characters to make it less abstract is phenomenal.

Besides his git repository being there, he tweets a tiny bit about his methods - he's doing a lot of stuff in low level wasm and crosscompiling from C++.

Man! I wish I had the chops to code up fluids and 3D.

Also kudos to Adult Swim for sponsoring this kind of stuff.

Friday, January 25, 2019

slack strike out and strikethrough

Daringfireball really ripped into the design work for Slack's new logo:

Before and After image from this page that has some more thoughts. I admit I am not a fan of the "squirting rainbow cucumber swastika" aspect, but YMMV.

Anyway, today I learned you can use tilde to surround text in slack and get a cross out effect. This might make sense to remove a top level comment that then turned into a thread, since you can't properly delete it otherwise.

Thursday, January 24, 2019

slightly fancier console logging

Hmm. Dan Abramov's Idiomatic React Video Course mentioned a few tricks for console supported in chrome and some other browsers (but not all, so you might want to look for undefined functions)

You can do and console.groupEnd do give some nice formatting/indenting.

Also, console.log('%c smurf','color:blue','!!!'); gives you a blue smurf. (Heh, the color console logging thing is very similar to the example trojan horse used in I’m harvesting credit card numbers and passwords from your site. Here’s how.)

Sunday, January 20, 2019

#Software10YearChallenge meet #Website20YearChallenge

#Software10YearChallenge isn't really taking off, and I'm not sure website even count, and it's not like my sites have set the world on fire, but anyway, thanks to the Wayback Machine it's pretty easy to get old views of my two most important sites  and  (I'm sure the name changes didn't help my google juice none.... )

Alien Bill was my first domain, with "Alien Bill Productions" being my fake-y company since my teen years. In the late 90s it looked like this:

Oh, man. What's best about this? The animated GIF at top? The Robotech font? The "Imperfect Web Design for an Imperfect World" slogan? The subtle titled background rockets and UFOs? Or the photorealistic icons I was briefly enamored with? Probably that.

I like the running alien bill (the repeating squares behind him are meant to emphasize motion.) And the micro-screenshots are kind of fun too. I took the animation from the old header and broke it out by frames.
Current day. I've been using the oversized hero image for a while now, and kind of love it. Recently I did a redesign to really try to bring people's attention to the stuff that I'm most proud of or that they might find the most interesting, and used the title fonts from my various works when I could, which mixes things up in a kind of fun way.

Then, my blog, coming up on 20 years. This is shortly after I started blogging, vs just having a more personal homepage-
I moved the personal homepage stuff to a sidebar... and hey, remember guestbooks? Those were kind of great. (I remember my websites guestbook served as an emergency contact pad on a day of surprise layoffs at work, useful in those pre-Social Media times.)

Hmm. Went a little nuts. The hand-doodled icons at top are kind of a throwback to the mid-90s stuff, like an even earlier version of alienbill:
But for the sidebar I had these delightful tiny minimalist things. (Also I used to be so weirdly enamored of that shade of turquoise, which I think showed up in Windows 3.1 or 95 a lot)

Also that was when I was changing gears from slightly longer form blogging to stuff I could mirror on twitter, the "...of the Moment" section. Over the years the UI I built for that became my primary way of adding stuff to the site, and eventually I blurred the visual distinction as you can see in the present day:
A few Christmases ago I embraced a kind of minimalism, and had some fun building up a visual language for the icons and the title at top. Also I added a tag system which is sometimes useful to me.

Wednesday, January 16, 2019

operator overload

Watching this Redux Crash Course video, Brad uses
I could guess what that was doing, but had to ask what that syntax was called - "computed keys" or "computed property names"

In terms of JS, there's definitely a drive for conciseness. Which can pay some dividends in terms of letting experienced coders recognize a complex trope quickly, but also comes with potential ambiguity - sometimes i personally wish the language was a bit more verbose, even if function() { }s are ugly,  bar fat arrows or random floating {}s can be so hard to parse.

Anyhoo, a coworker recommended this guide to ES6 features - it's pretty cool in showing the old and busted after the new hotness.

Of all the new syntaxes, one sticks out as clunky, and the other sticks out as just plain bad and confusing.

Custom Interprolation:
new hotness:
get`${bar + baz}&quux=${quux}`
is the same as 
get([ "", "&quux=", "" ],bar + baz, quux);

Dividing a string that way seems very strange.
But Parameter Context Matching seems really ugly when it starts letting you declare a local variable from a totally different argument map entry....
I mean 
function f ([ name, val ]) {
    console.log(name, val)
function h ({ name, val }) {
    console.log(name, val)
make sense and are pretty easy to read, but the renaming that goes on with
function g ({ name: n, val: v }) {
    console.log(n, v)
is bizarre - it feels like it's messing with left / right operands, every else in js land the key / variable name you're changing is on the left...

(Random note: the video made use of which seems pretty hip.)

hungarian notation

I realized I was almost on the verge of forgetting the term "Hungarian Notation" - a now mostly rejected idea of prefixing variable names with the type of the object. It was probably rejected because it was misunderstood and misapplied - like you shouldn't call your incrementer iCounter just because it's an integer, but if you have, say, a screen dimension that might be in pixels or might be in em, it might make sense to have "pxWidth" or "emWidth".

For instance, I'm fooling around with a gimmicky 3D for my timeline data, and some of my dates are objects containing a y and m key for month and year, sometimes I'm using a "count of months" (i.e. y * 12 + m) and sometimes I've normalized it to a value between 0 and 1. Hungarian Notation kind of makes sense here.

(To google up the forgotten term I had to search "notation petzold" - ah, the old Petzold book "Programming Windows", what an artifact of my first programming job...)

UPDATE: My online pal Jeremy Penner of Glorious Trainwrecks and the Fringe Games podcast worked with Charles Simonyi (inventor of "hungarian notation") and told me about his experience with it:
Anyway, the whole system was written from the ground up using Hungarian notation, and it turns out that it's actually a very interesting mental hack with very unintuitive properties

So, for example, the thing everyone complains about, where coming to a new codebase is totally impenetrable? Like "what the fuck is an mpfuidsibst?" It turns out that's a huge tradeoff that absolutely makes sense when you're building something totally new, in that you don't assume anything about what an mpfuidsibst is. You KNOW you don't understand it instead of believing you have a fuzzy understanding that is actually incorrect.
(mpfuidsibst is a name I gave a thing and it is my go-to example of "this name makes complete sense in context but is utterly absurd to outsiders")
The other huge benefit is that it allows you to talk precisely about different things that are similar and would be given similar names
So instead of talking about an "event", and being unsure of whether you meant a win32 API event, or an internal UI event, or a "document modified" event, all of which are dispatched slightly differently and have different properties, you would have a unique short name for each, that you use consistently
The names are cryptic because they're short, and they're short so that you always say the full name out loud and don't abbreviate, so you are always precise in what you're talking about
It's as much a research collaboration tool as anything
And once you've bought in to the system, and you learn what things mean, it's incredibly effective at preventing misunderstandings
Heh, interesting. In some React/Redux tutorials, I've noticed some times when the naming gets a little fuzzy, like "todos" might mean the JSON object map in memory as state, or as the reducers that tell you how to apply a change to the old state to get a new state

Monday, January 14, 2019

timelines: trying to capture four and a half decades on a screen

Everyone who hits middle aged gets shocked at how quickly life seems to pass (maybe because each year is a smaller fraction of the number of years we've already lived through). Also it's easy to lose track of whole years or even longer stretches. I'm hoping a visual timeline that says "here's where you were" will help me reclaim some of those "lost years" - let me connect with my past self of that era, however distant. Also, it might be interesting to compare different timelines - where was I living, vs who was i working for? Which times of my life had more change, and which had more stability?
A lot of the initial design came from Your Life in Weeks. I sort of loved the macabre nature of seeing all the weeks I was likely to get, with a kind of "You Are Here" in the middle of it. (and not on the early side of the middle either).

Quickly I was reminded that a year doesn't go easily into weeks - neither 365 nor 366 is a multiple of seven! So so either you line up the week columns, but they stick out scruffily on the sides, or you let the weeks shift left and right and you lose your nice rows and columns. And as cool as the "here are all your weeks" idea was, I realized it was orthogonal to getting a sense of history. So I threw that code away.
DOM version (2018.12.09)
Built a "city I lived in history" seeing what happens if I keep everything in the DOM - kinda ugly! Realizing what I want to do with captions doesn't really make sense (i.e. it would be hard to put one caption over several blocks etc.) And I was clumsy with my choice of colors - the old school term for that was "angry fruit salad". I think only labeling every multiple of 5 year was the right idea/
blocks version (2018.12.11)
Switched to p5 and canvas where I have a lot more control over finessing how things are positioned. I figure out how to get colors more or less under control. I also put in the raw data for jobs and romances. I both figured out how to center the captions things that took multiple years were only labeled once, reducing clutter. (Also I added little triangles for things that were going on into the future)
I like how the stacked look gives me a sense of time repeating - like how high school and college summers had their own feel, a kind of central column.
I was a little coy with most of the romances, using initials for the most part. At somepoint I will put a disclaimer saying these aren't all romance-romances, some are "its complicated" or mere crushes on my part. But I consider it all a part of my history and want to claim it.
yearserve (2018.12.12)
Kind of a digression -- I was thinking about getting back to a flattened look, but wondering if I could still get that sense of the looping nature of time - 4 years ago I noticed that my sense of a week and a year are both circular, and so here I am trying to balance that loopiness with a sense of the inexorable forward progression of time - and the seasons, as they are in the New England-y bits of the Northern Hemisphere. I am reasonably pleased with the result, but I don't think it's very useful for marking stretches of time on.
flat (2018.12.21)
If I decided to "flatten" time, I wasn't sure if I wanted to go vertical (the way I kind of visualized time going forward, from left to right) or down (which is more natural for webpages and mobile apps, TBH). Decided to start with Horizontal.
Since it gets soooo wide and to the right, I decided to start with it scrunched, and then zoom in on click. Also I put back in the season colors in - that returns a better feel of the years, but kind of looks like a faded out African Flag, which wasn't a reference I was thinking of.
Overall I think the scrolling to the side gets pretty tedious. I suppose an update with embedded, zoomable photos, say, might might be more compelling, but I'm kind of meh about this one.
UPDATE: I just realized some of these weren't working on iPhone. The error is "Canvas area exceeds the maximum limit (width * height > 16777216)" even though I thought I was setting it to 16470 x 280 = 4611600 which is less than that, but I think it's because of Retina pixel scaling.
Bummer. This might influence what I try next. Either vertical, maybe with DOM elements (some of the frustrations I had with DOM bits might be lessened if I have a simpler, "linear" display) or maybe I should stick with the "blocks" style, which was compelling in its own way.
flatplus (2018.12.28)
One last attempt at full horizontal before I give it up.
Here the idea is that if we move the labels out of the line itself, we don't have to ensure that each span of time is as long as its label, and can compress the entire thing and not make it scroll so far to the side.
The routine to make sure label boxes don't overlap (pushing them to new rows as needed) is slightly complex.
I also took some additional care with the endcaps of the time spans, where one picks up where the last left off the circle is split.
I like how the lines are visually more lightweight than the blocks I've been using, but overall the effect is still a bit jumbled. And I'd say I think "blocks" is still winning in terms of taking in the information.
vert (2018.12.30)
Back to DOM. Using the more sophisticated colors was a big help - and since now each column is a simple chronology (vs the earlier DOM version and "blocks" where years went down but months went across) this one was very easy to code - I even added a gradiant fade to black for things going on now to an unknown point in the future.
skinny (2019.01.02)
Pretty much just vert, but making the lines skinner (but with the caption like a sign on a signpost). Also fixed the colors so that if there's a repeated label in a timeline it gets the same color each time.
I'm learning more and more that this doesn't need to be about "exactitude" in terms of dates. I started rounding off to the nearest month for convenience, and that has proven more than precise enough for my requirements. In fact, for reasons of legibility and design I may play even faster and looser with exact dates.
skinnyphoto / skinnybig (2019.01.04)
Adding in images - This is where shtuff gets real - or rather, really emotionally resonate for me. And I think far more visually compelling as well.
Before this, I hadn't given too much thought about where I'd put the thumbnails - but because the time dimension is vertical, putting small thumbnails to the side seemed to make more sense, now that I'm here.
But I realized I could do better, making the entire block a "cover" image. CSS has pretty cool "cover fit" cropping and stretching, and by using an alpha color for the caption background, I was able to make legible overlays for the caption, keeping the colors aligned.
I also added "big trips" as a column - which has the added bonus of providing lots of images. Not sure if they are showing up in all the old prototypes (though all prototypes so far rely on the same data file)
All the images I grabbed were already in galleries I put online, but seeing so many photos from so many contexts really gets me the effect I was looking for, of telling a story of a middle-aged guys life in one place.
I'm digging "skinnybig". I think I may need to add a cheat so you can have bigger minimum heights, even though most "big trips" are less than a month.
I also want to add a "projects and groups" column - I think I want to design so that it can hold different bars simultaneously (i.e. right now the program assumes I can't, say, have lived two places at once or held
beta1 (2019.01.06)
On the home stretch, maybe. I've started making it so each new version doesn't rely on the common dataset, but makes its own copy.
For beta1 I added the idea of "events" - things that occur on a single year/month - in this case, big vacations and trips I took. I refactored some stuff so that each event takes up 3 months worth of space, so you can get a better view of the photograph.
I also punted on complex logic to make sure images don't overlap, instead putting in a "tweakpos" parameter in the data to nudge an event up a bit. Again one of the takeaways of this is that precision doesn't matter that much - as long as most things that happened around the same time appear side by side, that hits the point I want to get across
beta2 (2019.01.08)
Made a new option so that one collection of date ranges can appear in a single column - so a little logic to place the vertical bars in different sub-columns. Used it to show what bands I've been in. (Hm. Maybe this behavior should be the default, so people don't have to be strict about non-overlapping date fields)
As the display is now larger horizontally, I realized my trick for keeping the column labels pinned is broken. For some reason I can't get the CSS property "sticky" (supposedly a mix of relative and fixed) to function at all.
I also added the same "tweakpos" logic to move any photo blocks around so they don't overlap, and then further tweaks so you can change the y-position of a photo in a short block (vs having it centered).
Also: fixed the headers with position:sticky and made code for seeing the full photo when you click on it less idiosyncratic yet stupid.
final (2019.01.14)
I realized that with all the vertical space I'm taking up, and making a viewer scroll through, the sense of proportionality is lost- part of the mission of this display is giving me a sense that a lot of time has passed, I was living life there, even if I don't have the best recollection of it. To help address that, I added a minimap - showing what the current viewport is showing relative to my whole life so far. I then tweaked it by putting the years, which reinforce that, hey, the 2010s were happening. And also a rough age indicator, of how old I was.
I also tweaked the display of the range blocks, putting a faded-out background behind the entire time range. This is to counteract a feeling that the vertical space occupied by a photo was where the time range was, and not where "popsicle stick" stretched to. (Actually I had to remove that effect for the "multibar" columns where I allow overlapping ranges)

So that's it! Again you can see the final result and if you want me to to make a version with your own life story (you have to provide the dates and photos, I can handle much of the rest) let me know!
2020 UPDATE: I finally got around to making a display to answer a question, how long do these periods look if we line them up starting from the same position, like a bargraph, and invite side by side comparisons? And what period seems longest if we count it not in absolute days, but in what % of my life so far it covers? (So obviously the first event will be 100%). You can see the result here at time is relative.

2020 UPDATE 2: I finally got around to making another idea that occurred to me: what happens when put this into an arch? I write about that in this blog entry.
2021 UPDATE 1:
I combined that arch idea with the work I had done figuring out how to size and position masked circle images in p5...  here's the result, phototimearch...

Friday, January 11, 2019

scrolling minimaps with css and javascript

Remember the old arcade game Defender? And how they had a little minimap scanner at the top, that could show you where aliens were abducting your humanoids even as the screen was scrolling horizontally? For my timelines project, with a big vertical scroll, I wanted something similar - I want a generous amount of space to include images, but I wasn't liking losing the sense of "a whole life", so a small map seemed like the right idea, with a little frame on the map saying "you are here" (Kind of like a modern disappearing relative scrollbar, except it can hold a mini-me version of the whole thing.)

I might have cheated a little bit - I decided everything above the main content will be in a single block with an id of "header". The minimap and the frame moving in it then look like this:
<div id="minimap">
    <div id="frame"></div>

The CSS (fixed to one edge, and using opacity to let you see the real world beneath it)

#minimap {
    border:1px black solid;
    top: 40px;
    z-index: 100;
    overflow: hidden;
#frame {
    position: absolute;
    border:3px red solid;

Then I just call setupMinimap. The code is a little wonky for IE support:

function setupMinimap(){
    if(window.addEventListener) {
        window.addEventListener('scroll', onScrollEventHandler, false);   
        window.addEventListener('resize', onScrollEventHandler, false);   
    else if (window.attachEvent) {
        window.attachEvent('onscroll', onScrollEventHandler); 
        window.attachEvent('onresize', onScrollEventHandler); 

function onScrollEventHandler() { 
    const main = document.getElementById('main');
    const frame = document.getElementById('frame');
    const header = document.getElementById('header'); = (window.innerHeight / main.offsetHeight) * 100.0 +"%";
    let frameTopPercent = (100*((window.scrollY - header.offsetHeight) / (main.offsetHeight))); = frameTopPercent+"%";

    /*if(frameTopPercent < 0) { = 'none';    
    } else { = 'block';    

FOLLOWUP: you can see the end result on my timelines page

Thursday, January 10, 2019

position: sticky not working ?

So, there's a cool position: sticky CSS style - the idea is that it behaves like position:relative; but then once its containing element is scrolled it is like position: fixed --  good for column headers so they're always visible even when the body of the table or whatnot is halfway off the screen.

I was having trouble using it for my timelines project, it was seemingly ignored it - I resolved the problem by making sure its containing element had a height style explicitly set.

Monday, January 7, 2019

pretty css blockquotes

Literally probably a decade ago, a friend's blog had a neat bit of styling for quotes that I've always meant to emulate - it had a big ol' quote mark as background to the right. 10 Simple CSS Snippets for Creating Beautiful Blockquotes linked to this codepen that was in the ballpark of what I was thinking of:

<blockquote> and then a <footer> tag for the citation (some of the examples used a semantically better "cite" attribute on the blockquote but you can't really do more markup, such as links, in that.)

I don't use a CSS preprocessor for my blog, and so the code I ended up with looks like this:

blockquote.quote {
    position: relative;
blockquote.quote::before {
    content: '\201C';
    position: absolute;
    left: -0.3em;
    top: -0.2em;
    font-size: 6em;
    z-index: -1;
blockquote.quote footer {
    font-size: 0.9em;
    padding-left: 1em;
blockquote.quote footer::before {
    content: '\2015';  
So much of my blog is about quoting things, it's nice to have a flexible way of showing that it's not me speaking.

Saturday, January 5, 2019

capturing cmd-s and ctrl-s in browser

The homebrew backend for my personal blog is an ugly, aged, idiosyncratic mix of Perl and PHP
(to paraphrase yoda, "When 6580 days old you reach, look as good, you will not, hmm?") but I have total control and the editor I use has some features I like - 
  • convenience forms for "quick hits" vs longer pieces (the former auto translates linebreaks into <br> tags) along with a simple tab interface with back button support
  • scaling images taking care of iPhone rotation issues - but keeping the fullsize images around as well (wish I had done that years earlier, the blog really is my best archive of cool stuff) 
  • Relatedly, it's not really well integrated into the editor, but my new CSS-only thumbnail gallery system is still pretty keen.
  • a simple but slick way of saving me from typing up <a href> tags - I prefer to be in raw HTML mode rather than markdown, but still, the idea of "linkify this" using the highlighted text as the URL if it starts with "http" or as the clickable text if not works super well and doesn't require any other UI bits.
and now:
  • support for cmd-s to save
The code for that is a bit temperamental to setup: some similar variants don't do the job but this worked for me:

function setupCmdSIntercept(sel,clicksel) {
    jQuery(sel).keydown(function(event) {
            // If Control or Command key is pressed and the S key is pressed
            // run save function. 83 is the key code for S.
            if((event.ctrlKey || event.metaKey) && event.which == 83) {
                // Save Function
                return false;

Code modified from Pascal Bajorat's sample...
(oh the embarrassment - not only is it jQuery, but I can't even use the $ short cut because of the way it's embedded in even older Perl)

Of course the more general "edit any file on any of my subsites" edit system I refreshed last spring is going great (and probably why I longed to put the cmd-S support in the blog system as well.) The UI is idiosyncratic, but it's removed like 85% of my need to use an FTP program or ssh to do work (file upload, file deletion, and making directories are where it goes above and beyond the normal bounds of a browser based text editor)

FOLLOWUP (2019.02.01):
Here is a version that works without jQuery. Tested on modern chrome, safari, firefox, edge, and even old ie.

    if(e.key === "s" && (e.metaKey || e.ctrlKey)) {
        return false;   

Obviously you might want a more specific element than "document" (which I guess might need stopping propagation) but you get the idea.

Friday, January 4, 2019

find and regular expression tools to make json from file listings

Somehow I keep forgetting that I made a tool called regexcellent to let me do quick and dirty regex manipulations from the browser - stuff I used to do in text editor macros or small Perl scripts. (It and a bunch of other small tools, mostly for text manipulation, some of dubious quality, live at

I'm starting to add photos to my timeline project - they really add to the emotional power of it for me. I wanted to make a new timeline of big trips I've taken - I already have a lot of photo galleries online so it was a matter of harvesting from there, using the galleries both for the images and just as a reminder of what trips I've taken, and when.

I stumbled onto having "one folder per trip", each name "yyyy mm tripname" and each containing a single jpeg. And my JSON format for each entry is something like
 {name:'boston', from:{y:1991 , m:03 }, to:{y:1991, m:03}, 
  img:'trips/1991 03 boston/043_560.1991 jazz band in boston.jpg'},

so from the shell, I ran
find . | grep -i jp | sort
which was good enough to get me the list of jpegs in a format like 
./1991 03 boston/043_560.1991 jazz band in boston.jpg
and then at regexcellent the matcher was 
^\.\/(\d\d\d\d) (\d\d) (.*)\/(.*)$
and the output pattern was
{name:'$3', from:{y:$1 , m:$2 }, to:{y:$1, m:$2}, img:'trips/$1 $2 $3/$4'},

A little comma cleanup and I was done!

To quote Douglas Adams, "[I] am rarely happier than when spending an entire day programming my computer to perform automatically a task that would otherwise take me a good ten seconds to do by hand."