The epic Fisticuffs Espresso by Handsome Coffee, in the process of being pulled by the awesome Keaton Violet:

Fisticuffs Espresso

A beverage at The Shop in the South Perry District:

The Shop

Curiosity, philosophy, and open-ended games

An awesome half-review, half-philosophical dive into Minecraft by Jonathan Gourlay:

Being and Nothingness and “Minecraft”

I was born in Minecraft alone and without defense. […] It is a powerful experience to be cast into Minecraft‘s blocky paradise without direction or preparation. On my first day, I thought the game was about punching pigs. So I punched pigs. Then night fell and a demon, kind of like a Hong-Kong hopping vampire, crept toward me in my loneliest loneliness and exploded. […]

Another morning in Minecraft and with the help of fan-made survival manuals I am now equipped to survive the nightly night of the demons. Safety ensured, I must climb my pyramid of needs toward Minecraftian self-actualization. But what is that, exactly? What do I do now? In Minecraft, as in Sartre, existence really does precede essence. There is no goal, no point, no reason at all in this godless universe for playing Minecraft. But then, there is no point to playing with blocks either. There are things you can do with blocks. There are things you can do in Minecraft. You can find an elusive saddle in an underground monster lair and use it to ride a pig. But you don’t get anything — no badge or narrative or points to spend at an online store — for riding a pig. Pig riding is an end in itself. When you have accomplished it, that is simply how you chose to live your Minecraft life. Quit to title. You are your life and nothing else, pig rider.

I love that last part, especially: “no badge or narrative or points to spend at an online store […] Pig riding is an end in itself.”

I’m a sucker for sandbox games and other open-ended games that stretch the classic idea of “sandbox” — at times I’ve played MLB The Show and NCAA Football in the "Franchise Mode" for season after season for that same open-endedness. I’ve played a tiny bit of Minecraft (along with it’s spiritual predecessor, the MMO Wurm Online, which Notch extensively developed before quitting to work on Minecraft). I tinkered on one map of Sim City 4 on-and-off for two years.

I seem to enjoy the lack of focus and the tinkering aspects of games like these. It’s embarrassingly good boredom fodder. And, provided you suspend disbelief long enough, the only thing you truly have is the pride in accomplishing whatever it is you set out to do — most of these games have few or no “achievements” in these open-ended modes. There are few built-in incentives or biases to cause you to do one thing or another: you simply have the framework of the game, your own curiosity, your own ideals, and possibly a few things you’ve heard that you want to try yourself. (In Gourlay’s piece, it’s his ideal of nostalgia and memories that drives him to build a rendition of a home he once lied in.)

These are the kind of games (or game modes) where only curiosity and experimentation can make the experience viable. If you don’t have that, then there clearly is no game here for you. (And funny enough, I don’t think many people I know actually would enjoy any of the things I play in my down time.)

2011

About twelve months ago, I wrote an incomplete blog post about my goals for 2011. This isn’t it, but digging that up inspired some points in this quick year-end recap.

Notable Work

Spent the first four or so months of the year working on Census data: launched the Spokesman-Review Census Center right after the first data dumps came around. I got invited by the awesome NICAR folks to help hack on census.ire.org. (Took the original NationBrowse down in mid-November since the Spokesman project functionally supersedes it.)

Coming off of that Census high, we started putting together more “data browse” tools at the Spokesman-Review.

Notable Personal Developments

  • An illness in the family at the turn of the year. Hustled to visit for a week in January. (Everything’s fine now and I’m thankful for that.)
  • Came close to leaving Spokane for good, for the shine and glamor of Silicon Valley. Couldn’t bring myself to leave loose ends and burn bridges that way.
  • Ran the 12k Lilac Bloomsday Run with nearly no training, more or less out of shape. (And fared better than I thought I would.)
  • Started going to the gym a couple times a week.
  • Took a day trip to a missile silo.
  • Took a weekend trip to northeast Washington and Nelson, British Columbia
  • Witnessed the final Space Shuttle launch in person.
  • Some absurdly awesome baseball happened this year, too. (Outside of the Cardinals: who could forget the last day of the season? [1] [2] [3])
  • Oh, and I moved in with a girl. That’s something that people do, right?

No projections for 2012. This year was ridiculous and I couldn’t have predicted it, so I don’t want to bother.

No concrete goals or resolutions, either. (The calendar is such an arbitrary measuring device and who keeps resolutions anyway?) Just this: do good, and do more awesome than last year.*

*Subject to change.

Django 1.4 first thoughts: CachedStaticFilesStorage

The first alpha release of Django 1.4 is out. I've been toying with trunk on and off for a while now, but hadn’t taken more than a passing glance at all the new features. At first glance: I’m thrilled.

I plan on writing a few posts about some new bits that stick out to me. Here’s the first.

CachedStaticFilesStorage and {% static %}

The new CachedStaticFileStorage stores your files but also creates a copy where the MD5 hash of the file's contents are added to the file's name. (i.e.: something like foo/style.css would be saved as foo/style.55e7cbb9ba48.css)

Taking a look at the implementation, it looks like a mixin (CachedFilesMixin) provides the functionality — and appears to be compatible as a plugin to any existing storage backend. The implications of this are pretty useful.

Say, for example, you’re currently using S3/CloudFront to serve your static files (by using the S3BotoStorage in django-storages: you’d simply do the following…

1
2
3
4
5
6
7
8
9
10
from storages.backends.s3boto import S3BotoStorage
from django.contrib.staticfiles.storage import CachedFilesMixin

class S3HashedFilesStorage(CachedFilesMixin, S3BotoStorage):
    """
Extends S3BotoStorage to also save hashed copies (i.e.
with filenames containing the file's MD5 hash) of the
files it saves.
"""
    pass

… and then set your STATICFILES_STORAGE to reference the above class. (Caveat: I haven’t tested the above yet.)

To get your templates to pick up the hashed versions of filenames, you'd use the new {% static %} template tag: just convert this…

1
<link href="{{ STATIC_URL }}style/base.css" rel="stylesheet"/>

…to this…

1
2
{% load static from staticfiles %}
<link href="{% static "style/base.css" %}" rel="stylesheet"/>

…and you’re now ready to rock with static files that you can cache forever without worry of them going stale.

Disclosure: I’m both excited and pissed because I actually spent a bit of time on a staticfiles hashing utility that wasn’t nearly as elegant as this mixin. Kudos to anyone who worked on these staticfiles enhancements.


Update (12:15PM PST): It isn’t mentioned in the docs for CachedStaticFilesStorage, but the filenames are cached in Django’s cache system (so the static files themselves do not need to be read constantly to generate the MD5 hashes). If you’re using memcached as your cache backend, this means that for deep directory structures and long filenames, you may hit the 250 character limit imposed on memcached keys. (Note that encountering this is rare outside of collecting static assets since models.FileField defaults to max_length=100 anyway.)

Solution: set up a function to shorten/hash your cache keys and point settings.KEY_FUNCTION to that function.


Another addendum: If you’re using multiple memcached servers and don’t want to incur network overhead just for those staticfile MD5 hashes, you can set a custom cache backend config — CachedStaticFilesStorage looks for a 'staticfiles' cache before falling back to the default, so you can force CachedStaticFilesStorage to cache these values in local memory instead of memcached (hat tip to Ted):

1
2
3
4
5
6
7
8
9
10
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '127.0.0.1:11211',
    },
    'staticfiles': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'staticfiles-filehashes'
    }
}

Oh look, a link relevant to my previous post.

Seth Godin, on the trap of social media noise:

If we put a number on it, people will try to make the number go up.

[…] In Corey's words, the conventional, broken wisdom is:

  • Follow a ton of people to get people to follow back
  • Focus on the # of followers, not the interests of followers or your relationship with them.
  • Pump links through the social platform (take your pick, or do them all!)
  • Offer nothing of value, and no context. This is a megaphone, not a telephone.
  • Think you're winning, because you're playing video games (highest follower count wins!)

This looks like winning (the numbers are going up!), but it's actually a double-edged form of losing. First, you're polluting a powerful space, turning signals into noise and bringing down the level of discourse for everyone.