Matt Brundage
Sunday, 27 October 2013

Antisocial media

Tanya, being a babyBefore Tanya was born, Annie and I agreed that we wouldn’t be the kind of new parents who posted on social media every time their newborn did something cute or, say, had a particularly interesting bowel event.

While we’ve had no trouble keeping that informal agreement, our enthusiasm for Tanya (and burgeoning media collection) needed a proper outlet. To that end, this site now hosts more baby photos than you’ll know what to do with. And in June, I had the pleasure of coding a videos section, which — for now at least — is exclusively Tanya-centric.

I will admit that no one gets more enjoyment out of all this media than Annie and me. The videos section was developed mostly so that Annie could have an accessible way of viewing our growing collection. Otherwise, the files would have just languished somewhere on a hard drive, deep in hard-to-reach directory trees.

And putting all of this up on Facebook didn’t seem right, somehow — as if I wouldn’t fully own it anymore. Facebook (or whatever site) can change their privacy policies or terms of service whenever they feel like it, and we’re all seemingly at their mercy. That’s not for me. Especially not for something this important.

Thursday, 7 March 2013

Tanya Alexa Brundage

Tanya Alexa Brundage I am in love.

Tanya greeted the world on March 5, 2013 at 8:17pm. She clocked in at 9 pounds, 11.3 ounces (or 0.004403 metric tons!) and a length of 20.5 inches.

Tanya comes home with us on Friday to begin her life as a full-time baby.

Wednesday, 24 October 2012

Big-ass salad

The salad, in all its glory. This evening, I took Leo Babauta’s advice and made myself a big-ass salad. I used the biggest serving bowl that Annie could find. You can’t really get the scale from the photos, but the pile of vegetables is about the size of a regulation-size basketball. It was a manly pile of salad and took me close to half an hour of non-stop eating to polish this thing off.


Red-leaf lettuce, spinach, kale, Chinese broccoli, raw mushrooms, mushrooms An alternate view of the salad. marinated in red wine vinegar and minced garlic, a carrot, an orange bell pepper, a roma tomato, a handful of cherry tomatoes, sun-dried tomatoes marinated in olive oil and Italian spices, non-marinated sun-dried tomatoes, green olive tapenade, pistachio nutmeats, shredded Parmigiano-Reggiano cheese, and toasted corn kernels. Tomato juice to wash it down.

Sunday, 19 August 2012

Weighty disconnect

At my heaviest in March 2008, I was 208 lbs, with a BMI of 27.4. By the criteria set forth by the World Health Organization’s CDC, I was considered overweight. And yet, during that heavy time in my life, no one commented on my weight or urged me to lose weight.

Strangely, the only critical comments I’ve received happened after I dropped a significant amount of weight and got back down to my ideal weight of 160 to 165 lbs. For the record, 165 lbs on a 6″ 1′ frame equals a BMI of 21.7, which comfortably falls within the normal range, according to the CDC. Furthermore, a study in the New England Journal of Medicine asserts that, by lowering my BMI, I had decreased my relative risk of death. At a certain level, this is just common sense, but it’s nice to see it proven with data.

My BMI, 2008 and 2012

Even considering my current BMI (21.7), I actually still have room for improvement! According to the same NEJM study, I could theoretically drop another 20 pounds and further decrease my risk. But oh, the comments I would get.

The irony of all this is that as I was decreasing my relative risk of death in 2009 and 2010, people began to get concerned for my health! Yet, during my twenties, no one said a word as I slowly packed on the pounds, became overweight, and was statistically likely to have a lower life expectancy.

Sunday, 29 April 2012


My dearly beloved website clients: over time, your sites are loading faster and faster1 — and there’s nothing you can do about it. Just another fringe benefit of having me as your web developer.

Homepage speeds (all data points), Oct 2010 to Apr 2012

Google page speeds

Homepage speeds (averaged), Oct 2010 to Apr 2012

Google page speeds

Coincidentally, our happy little graph here appears to evoke a logarithmic trend.

1: As measured with Google’s Page Speed extension for Firefox, which rates a page’s loading speed based on these criteria.

Sunday, 12 February 2012

Coding on the shoulders of giants

Isaac Newton I write and edit code for a living. Because I enjoy what I do, I have this insatiable thirst for knowledge and self-improvement: “How can I write this function in fewer lines?” “How can I make this CSS bullet-proof?” “How can I make this page load faster?” Not for a second do I purport that I come up with solutions solely on my own. I have this small army of disparate web developers at my disposal — a collection of developers that, for all intents and purposes, functions as an extension of my own brain.

Kroc Camen

Where do I begin? Kroc was one of the first to fully embrace the still-emerging HTML5 specification, his Video for Everybody! just works, and his approach to writing CSS and .htaccess is refreshing and enlightening.

Dean Edwards

After Microsoft released IE6 in 2001, the company essentially stopped all browser development for five years. However, during that time, a man in the UK was busy writing a script that, when run in IE6, corrected many of the rendering bugs inherent in that browser and even added support for certain CSS rules that IE7 would eventually support. If you’re curious or pedantic enough to parse through Dean’s code, you will soon realize that he is insane.

Joe Hewitt and other Firebug contributors

When I write code, I usually have the Firebug pane open constantly. I wouldn’t be as efficient or effective at what I do without Firebug. Proper respects to Joe Hewitt and other contributors to Firebug: some anonymous, some not well known.

Paul Irish

I just know it: news will soon surface that the man known as Paul Irish is actually several Google employees working collaboratively under the same alias. The man seems to have his paws in everything. Deep breath: HTML5 Boilerplate. Move the Web Forward. Modernizr. CSS3 Please. HTML5 Please. W3Fools. HTML5 Readiness. Front-end Code Standards & Best Practices.

And it doesn’t hurt that he’s deeply knowledgeable, funny, and — might I add — handsome.

Steven Levithan

In the short 15 months that I worked alongside Steve, I learned more about web development best practices, regular expressions, and JavaScript than I had in all years prior. Many of my Oh My God, it’s full of stars! moments are because of Steve.

Jens Meiert

Jens is the expert and I enjoy reading his posts about code maintenance. He’s also a bit of a Renaissance man. I get deeply jealous if I think about it too much.

Eric Meyer

Eric, for a while, was the go-to guy for all things CSS. He wrote CSS: the Definitive Guide, for Pete’s sake! Eric is a dog who has had his day, but he can still churn out thought-provoking posts.

Ben Nadel

It seems that whenever I have a ColdFusion problem that I need to solve, my search ends when a Ben Nadel blogpost succinctly tells me exactly what I need to know. That’s not at all an oversimplification.

Chris Pederick

Chris, British-born but now residing in California, is the author of the invaluable Firefox extension Web Developer. Every time the extension has a major update, I send Chris a thank you gift from his Amazon wishlist. Along with Firebug, Web Developer is indispensable to developers — I couldn’t imagine the browser without it.

John Resig

The creator of jQuery, Resig made JavaScript interesting again and is arguably the man most responsible for its resurgence.

Steven Souders

Steve, an former employee of Yahoo (now with Google), is the one who got me interested in web page speed optimization. However, in a strange twist of fate, I never installed his YSlow browser plugin, but instead opted for a similar plugin, Google PageSpeed. But still, Souders wrote the book on front-end page performance.

Wednesday, 26 October 2011

Deer population control: the final solution?

Recently, Annie went walking in Sligo Creek Park and saw a sign announcing the ongoing deer population management initiative, which involves mass killing. The Montgomery County Dept. of Parks will be reviewing public comments through November 10th, and Annie felt compelled to respond.

The letter below is her response to the Montgomery County Dept. of Parks.

cute little deer While my husband and I understand people’s concern regarding the current deer population, we strongly oppose your plans for a mass killing of deer when there’s a more humane alternative available. We’ve found information about a protein contraception vaccine that has been effectively used in Gaithersburg and other areas[1]. We’ve also found information that supports the effectiveness and safety of this method and it shows a 60% reduction in the deer population[1][2]. The cost of this method is lower than what is shown on the reports cited on your website.[3]

From NIST: “Two-shot PZP vaccination programs, sponsored by the HSUS, have been more than 90 percent successful at blocking pregnancies for one year in white-tailed deer and wild horses in other areas of the country. In addition to its proven effectiveness, the PZP vaccine can be delivered easily by darts, cannot pass into the food chain, does not affect normal mating behavior, shows no side effects and allows a return to fertility when no longer administered.”[1]

Even if the contraceptive method has to be done annually, the deer population and the need for contraceptive vaccines will decline[2]. This is a better solution than the annual killing of these deer.

If deer have no natural predators, are we to reduce ourselves to the levels of animals and simply kill? What makes us different is that we have the ability to feel compassion. I’ve been in a car accident involving a deer; deer have eaten plants from my garden. However, I don’t see this as justification for a mass killing of these animals. Deer can’t come to public meetings, send emails, or protest for their right to live. It’s our responsibility to protect those who don’t have a voice and are being inhumanely treated.

Works cited

[1] Deer Immunocontraception at NIST
[2] Deer Contraception Works!
[3] Immunocontraception (Deer Birth Control)

Tuesday, 4 October 2011

Jens Lekman and the improbable synchronicity

Small Image A few years ago, KEXP introduced me to the music of Jens Lekman, a Swedish-born singer-songwriter. I was immediately taken with his blend of indie pop, with a sound reminiscent of a less-snooty Sufjan Stevens, or perhaps a peppier Stephin Merritt or the Smiths. I picked up his second album, the excellent Night Falls Over Kortedala.

Recently, I put his album into heavy rotation again, for no single defining reason. I was particularly drawn to “Shirin”, a song in which Jens falls for his Persian hairdresser: the song’s namesake, Shirin.

When Shirin cuts my hair it’s like a love affair / Let those locks fall to the ground or let them stay mid-air…

Shirin pulls my head to the side, but in the mirror I can see a tear in her eye…

The song is charming (but not mawkishly so) and is impeccably arranged, with Beach Boys-esque “ooos” and “aaahs” rounding out an ample, wordless vocal tag. In short, “Shirin” alone is deserving of its own blog post, but wait, there’s more.

Last week, while walking home from work, I saw a generic-looking business card in the street gutter. Now, 99.9% of the time, I don’t just go picking up random pieces of garbage off the street, but for some reason this business card (lying face-down, mind you!) piqued my interest as I bent down to pick it up.

Shirin apparently works at Hair Cuttery

Friday, 12 August 2011

Stale cache mitigation with query string automation!

So you’ve been a good little developer and define expires headers for page assets such as CSS, JS, and images. Let’s say you specify that the caching of CSS files expires one week after initial access. But if you modify a CSS file, your visitors could potentially load stale cache for up to one week.

One solution is to rename the file. For example, main.css would become main.2011-08-12.css This will effectively create a unique cached version of the CSS file. But this solution could get cumbersome with frequent updates, or with disparate references to the asset. A second solution is to add a query string to any references to the asset, for instance, main.css?2011-08-12. Proxy servers will treat this reference as a dynamic file and will likely not cache it. Browsers will treat this as if it were a unique file and re-cache it.

A refinement to our second solution is to automatically add a query string to references to the asset, but only when it’s necessary to do so. The following function, assetQueryString(), does just that. It takes two arguments:

  1. The reference to the page asset
  2. (optional) Maximum file age (in days) in which the query string will be appended

The function determines the file modification date and determines whether or not to append a query string, and for how long. The value of the query string, conveniently, is the last modification date of the file. Or, more accurately, it’s the number of days between the Unix Epoch and the last modification date.


function assetQueryString ($filePath, $maxAge = 7) {
	$today = intval(strtotime(date("Y-m-d")) / 86400);
	$fileDate = intval(strtotime(date("Y-m-d", filemtime($_SERVER['DOCUMENT_ROOT'].$filePath))) / 86400);
	$days = $today - $fileDate;

	if ($days <= $maxAge) {
		$filePath .= "?".$fileDate;
	echo $filePath;

// usage:
<link rel="stylesheet" href="<?php assetQueryString("/templates/style/main.css"); ?>">


<cffunction name="assetQueryString" returntype="string" output="FALSE">
	<cfargument name="filePath" type="string" required="TRUE" />
	<cfargument name="maxAge" type="numeric" default="7" required="FALSE" />

	<cfparam name="Variables.unixFileDate" default="0" />
	<cfset Variables.expandedFilePath = expandPath(filePath) />
	<cfset Variables.unixEpoch = CreateDate(1970,1,1) />

	<cfif fileExists(Variables.expandedFilePath)>
		<!--- determine last modified date --->
		<cfset Variables.unixFileDate = DateDiff("d", Variables.unixEpoch, getFileInfo(Variables.expandedFilePath).lastmodified) />

		<!--- determine today's date --->
		<cfset Variables.unixTodaysDate = DateDiff("d", Variables.unixEpoch, Now()) />

		<!--- append unique query string to file path if the file was recently modified --->
		<cfif Variables.unixTodaysDate - Variables.unixFileDate LTE maxAge>
			<cfset filepath &= "?" & Variables.unixFileDate />

	<cfreturn filepath />

<!--- usage: --->
<link rel="stylesheet" href="<cfoutput>#assetQueryString("/templates/style/main.css")#</cfoutput>">