— tomauger.com

Check this code snippet out. Include jQuery and the most excellent lettering.js jQuery plugin by Dave Rupert and the guys at Paravel, inc, and then paste this into a script tag, or whatever you do to get JavaScript on your page. Then, just customize the list of classes that will be “bumped”.

// Bump.js by Tom Auger (http://www.tomauger.com). Free to use for anything. Maybe leave this line intact?
 
// Set up some customization here for the randomness
var classes = [
	// ['css selector', vertical-align variance (in pixels) eg: 2 = -2px to +2px, % chance of getting 'bumped']
	['.text', 1, 10],
	['#hours', 1, 50],
	['.textlist li', 1, 20]
]
 
jQuery(document).ready(function($){
	// Everything's been loaded, let's have some fun!
	for (var i=0, l=classes.length; i Math.random()) $(this).css('vertical-align', Math.floor(Math.random()*(shift*2+1))-shift + "px");
		});
	}
});
Read More

If you’re using DreamWeaver without its built-in Subversion support, or for whatever reason need to add newly-created files (that may still be checked out) to the repository, this one liner will do the trick:

svn st | grep "^\?" | grep -v ".LCK$" | awk '{print $2}' | xargs svn add

Let’s break it down, by pipes (reading left to right):

  1. Give me a subversion status: a list of all files that have been added, modified, or otherwise
  2. Using grep, only select those that start with a “?”, namely those files added to the working copy, but not yet under version control
  3. Using reverse grep (the -v switch), exclude any of those records where the filename ends with “.LCK” (the DreamWeaver lock file that indicates something is checked out)
  4. Using AWK, only output the second field (which translates to the filename without all the SVN flags in front of it)
  5. Using XARGS, pipe this (now filtered) list of files to the svn add command.
Read More

I had no idea, but in researching the expression “Yak Shaving”, it appears that it applies to many, if not entirely all, of my daily activities.

Including writing this post, as a natural result of trying to import a new project into my SVN repo while ignoring a directory. Totally relevant of course.

Read More

Since I’ve gotten back into Magic: The Gathering, a lot of things have changed, mostly for the better (though, seriously, who came up with the whole Planeswalkers idea? I thought we tried that with thos ugly oversized “Character” cards back in the day).

One of the great new things Wizard has given us is the Gatherer, their online card search database. I was surprised to learn that it allows Regular Expressions in its search terms. This makes for some seriously powerful search possibilities.

Since I realize that not all MtG afficionados might be programmers or even care what RegExps are, I am compiling a list of cool searches using Regular Expressions that will give you comprehensive card lists that you just wouldn’t be able to get any other way.

I’ll be adding to this list from time to time, so be sure to bookmark it for your own deck building / collecting research!

All red cards that deal direct damage:

http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&color=+[R]&text=+[m/deals\s\S*\s?damage/]

 

All cards that put a card from a graveyard directly into play

(plus a bunch of others that put Zombie tokens into play instead  (I’ll need to refine this one):

http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/from\s(\w+|his\sor\sher)\sgraveyard.+(into\splay|(on)?to\sthe\sbattlefield)/]
http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/return.+(from|of)\s(your|his\sor\sher|target\splayer's|any)\sgraveyard.+(into\splay|(on)?to\sthe\sbattlefield)/]
http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/return.+(from|of)\s(your|his\sor\sher|target\splayer's|any)\sgraveyard.+(into\splay|(on)?to\sthe\sbattlefield)/]&cmc=+%3C[4]&color=+[B]


Note that there’s a bit of a bug with Gatherer right now in that it will lose the “?” in the URL when you click on any of the pagination links. So, in order to go to the second, third etc. pages, you need to modify the url by adding “&page=X” where X is the page number – 1. So to get to page TWO:

http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/from\s(\w+|his\sor\sher)\sgraveyard.+(into\splay|(on)?to\sthe\sbattlefield)/]&page=1

 

 All cards that grant an additional combat/attack phase:

http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/additional.+(attack|combat)\sphase/]

 

All cards that donate a creature (token) to your opponent:

http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/(into\splay|onto\sthe\sbattlefield).+under.+opponent.+control/]

 

All Cards that can be sacrificed on ETB

http://gatherer.wizards.com/Pages/Search/Default.aspx?page=1&action=advanced&text=+%5Bm/enters%5Csthe%5Csbattlefield.+sacrifice%5Csit%5Csunless/%5D

 

All cards that have player gain or lose life equal to a creature’s Power or Toughness

http://gatherer.wizards.com/Pages/Search/Default.aspx?action=advanced&text=+[m/(gains?\slife|deals\sdamage).+equal\sto\sits\s(power|toughness)/]
Read More

Named Ranges in Excel are pretty cool. They enable things like drop-down lists in your Data Validation. You can define a series of values in a column, give that column a name, and then you can refer to that range by name instead of its coordinates (ie: A1:B5).

One of the frustration with maintaining these lists is that as soon as you add a new value, you have to go back to Formulas > Name Manager and redefine the range to include the new value. To avoid this, you can create what’s called a Dynamic Range, by using a formula instead of a hard-coded set of coordinates. This is most often handled using the OFFSET( ) function as you’ll see below. Googling “Excel dynamic range” will return tons of results that all have variants of:

=OFFSET(Sheet1!$A$1, 0, 0, COUNTA($A:$A), 1)

The Basic Formula, Explained

‘OFFSET’ will return a range based on a STARTING POSITION, the ROW OFFSET (that gets added to the starting position), the COLUMN OFFSET (added to the starting position, the HEIGHT (number of rows down) and the WIDTH (number of columns across).

STARTING POSITION is usually the top left cell of your named range

ROW OFFSET is usually 0, since we have defined the starting position of our range

COLUMN OFFSET is also usually 0, for the same reason

HEIGHT is the number of rows to include in the range (here we’re using another formula – more on that below)

WIDTH is the number of columns to include in the range (must be at least 1)

Expanding the Range Dynamically

So clearly, OFFSET by itself doesn’t do that much for us – in fact, if you’re just going to plug static number into OFFSET, there’s actually no use for it – just plug in your range directly and leave it at that. The reason you use OFFSET is because it allows you to substitute any of its parameters (arguments) with some other formula. This is where the ‘dynamic’ part comes in.

The typical dynamic range formula you’ll find on the Interwebs uses COUNT( ) (for numerical columns) or COUNTA( ) for text columns. COUNT and its text cousin COUNTA count the number of non-blank cells. If we count the number of non-blank cells in a row and use that as the HEIGHT parameter of OFFSET, we get a range that starts at the starting coordinate and continues on up to the last cell that contains a text entry. In theory.

In actuality if you read the fine print, what you’ll get is a range of cells that starts at the first cell and continues down for as many cells as were counted by the COUNTA function. If there are blank cells in the middle of your range for some reason, this number will be wrong. That’s because the non-blank cells are not counted, so your range will be shorter than it should, and the last cells in the range will be left off. So be aware of this subtlety.

Read More

For those of you that just want the straight goods, here’s how we delete everything EXCEPT the ‘backup’ directory:

find . -maxdepth 1 ! -name 'backup' ! -name '.*' | xargs rm -rf

Here’s a bit of a (simplistic) explanation:

  1. ‘find’ is the magic sauce here. We’re using it to recursively search through all the files (and directories) starting at ‘.’ (the current directory)
  2. the ‘!’ is the negation operator, which tells find that the operator that follow (-name) should actually perform a negative match (match everything that does NOT match this criteria)
  3. we also need to set up a negative match for ‘.’, ‘..’ etc, since find returns those files as well. Do note that one side effect here is that it won’t delete, for example, ‘.htacess’. You may need to modify this if you want to kill those ‘hidden’ files as well
  4. find is recursive, so even if it doesn’t attempt to delete the ‘backup’ directory, it will still traverse the ‘backup’ directory and delete all the files inside it, leaving an empty directory! To avoid this, we use -maxdepth 1 which effectively turns recursion off. We then make sure we recursively delete the files in the OTHER directories by using the -r flag on ‘rm’
  5. xargs is one way to ‘do’ something useful with the list of files and directories returned by find (find also has an -exec operator which will be able to do almost exactly the same thing, but I like xargs’ syntax better, personally). We pipe the output to xargs and then follow it with the command that we would want to run once per file/directory, in this case ‘rm -rf’

Have fun! And please backup your shit before trying this, cause one mis-step and you can trash a whole lotta stuff!

Read More

There’s probably a better way, but I do most of my svn commands from the root of the project (eg: svn update). I really hate fully qualifying a path when I want to add a new file to version control, when that file clearly has a unique name. Is it a sign of hacker laziness that I would rather type 30 extra characters of shell code rather than type 25 characters of path name?

 

find -name 'my_unique_file_name_to_add.php' | xargs svn add
Read More

I just had two real-world examples that I wanted to share on record to remind us all why, as much as we absolutely loathe doing it (as designers), we still have to design for the utter, most horribly worst-case scenario.

IE6 is dead?

We at Zeitguys jumped on the pyre and enthusiastically joined the IE6 funeral, referred customers to Microsoft’s own website encouraging users to switch to more modern browsers, and decided that in 2011 we would no longer be designing for IE6. Guess what? Every single site we’ve designed has had an IE6 version either from the get-go, or retroactively tacked on. Or we wished we had.

Case Study #1

We were designing a low-budget website for a non-profit community-level organization. Accessibility was our primary concern and we focused all our energies in a simple design and some pretty advanced accessibility stuff. I instructed the team to “forget IE6″. Then I went to present to the client in their boardroom, with all stakeholders present, on their laptop (big mistake). Guess what was the only web browser Corporate IT supported? IE6. The presentation was a disaster.

Case Study #2

We’re in the process of designing what will be our flagship web project for the interior specialist Amovo, full of all sorts of truly remarkable bells and whistles. We knew this was a high-end site for high-end clients and to do what we wanted to do we couldn’t be bogged down with IE6 concerns. At our initial training session with the client to bring them up to speed on a vanilla WordPress install we discovered that the CEO’s laptop was only equipped with IE6.

Sigh. The Moral of the Story?

This is 2011. IE6 is still out there.

As designers, you need to have a very frank up-front conversation (a conversation, not a line in your Statement of Work somewhere) with your client about designing for IE6, costs, timelines and limitations. Just remember that no matter how great the site looks on your high-end Macs at the studio, when the client is pulling the site up at home on his home laptop which was an office hand-me-down back in 2004, he is very likely running some out of date shit.

960… by what?

Ever since the 960 Grid System  became a household (or studiohold) term, and even before, we’ve all sort of settled down to a reasonably common set of minimum width guidelines for web design. In 1996 Jakob Nielsen answered the quintessential question of “What Screen Resolution should I design for” with 1024 x 768 and that hasn’t really changed all that much in the better part of a decade. Hence the popularity of 960 grid systems and the like.

At Zeitguys we use a 960 pixel width as our minimum worst-case scenario for width. This gives a decent margin for browsers, once you take into account the browser chrome, the scrollbars and the fact that the window may not be maximized.

But then there’s all this talk about “the Fold” and staying above it (and all the usability luminaries who attemptto debunk this myth), and we’re still left trying to figure out how much vertical content of that initial web page view your “average” user will see. Regardless of how you weigh in on The Fold, we all agree that as designers, it’s that initial view of the website when it first loads the ‘index’ page, that sets the tone and the first impressions of the site.

Case Study #3

I was at home, in a pinch, my laptop was at the office, the home computer is still fritzing out, so I flamed up my wife’s Acer laptop. Yeah, it’s a 1280 x 800 display from 2005 but you know, it still runs GuildWars (one) just fine. I popped into Explorer (8, thankfully!) to check out an update to this website we’ve been working on. Take a look at what I saw:

 

You’ll want to click on the image to see it full-size.

Is that 5 Toolbars?

Yep. Five. Plus a menu bar and a tab. Each clocking in at about 30 pixels apiece. That 800 pixel real-estate shrank down to just over 500 pixels real fast. And here’s the scary part: my wife is actually reasonably technical. She’s the “IT” contact at her office, and she’s a gamer (hence the GuildWars reference earlier). And yet. I totally blame companies like Adobe, who, when you install fricken Flash Player, sneakily also installs Google Toolbar (unless you notice and uncheck the option).

Double Sigh. The Moral of this Tale?

Just because we savvy, aesthetic-oriented designers (who, according to a recent article I read are 30% more likely to customize their browsing environments) like a nice, clean browser and have huge monitors, does not mean the same is true for our wives, clients or most importantly our clients’ clients.

So design for the worst case my friend. And then think of an even worse case than that.

Read More

Okay, this has been a holy grail for me for a while, and just came to a head today as I accidentally copied a database containing about 15 separate WordPress installations (with different table prefixes) into what was supposed to be a dedicated single WP database. Ouch.

A little while ago I blogged about how you can avoid this situation altogether by only mysqldumping selected tables based on a pattern match of their prefix. Well, guess who didn’t drink his own milk (is that even an expression)?

So there I was, with a database full of wp_ and wpclientA_ wpclientB_ zg_ etc. All I wanted was to keep the original wp_ tables and just drop the hell out of the rest of ‘em.

Read More

If you’re not familiar with the fancybox jQuery plugin, I highly recommend you check it out. Lightweight, portable and powerful it is your basic Lightbox-style gallery viewer that supports embedding of images, inline content, iframe content, AJAX derived content and even SWF files (without the need for an external library like SWFObject). Very sweet.

Recently on a Zeitguys project, we had a situation where we had a gallery of dozens of SWFs (thankfully) all the same size. We wanted to display a static graphic in place of each SWF as the page loaded, and then on click, load the appropriate SWF in place. All of this is pretty easy to do right out-of-the-fancybox, so to speak. But there was an added catch: the whole thing had to be built on progressive enchancement principles, so we needed a structure that first worked perfectly with JavaScript disabled. In other words, each anchor tag in our gallery has to have a link to a static HTML page that contains just that SWF embedded on it. Only once that structure was working, could we overlay the fancybox functionality.

The challenge is that the way fancybox (and most of its other “competitors”) work is by hijacking the content of the href attribute of the anchor tag to which fancybox is attached. This is a Beautiful Thing if you have a bunch of IMGs wrapped inside A tags. The anchor’s href points to the IMG source and BAM, if JavaScript is enabled and you’ve attached fancybox to those anchor tags, fancybox reads the href on click and generates the necessary DOM elements to display it in a nicely-formatted, centered box.

But with a gallery of “poster frame” images that have to point to legitimate HTML pages for when JavaScript (or fancybox) are unavailable, we need to roll up our sleeves.

Read More

Here’s a quickie. For those of you finger hackers out there, this one-liner will look through all available logs (including backups) and come up with a count of unique visitors. Just in case your built-in server stats aren’t working and you haven’t signed up with Google Analytics.

zcat access.log*| awk '{print $1}' | sort | uniq -c |sort -n | wc -l
Read More

Okay, I’ll admit that I’m no friend to Adobe Dreamweaver, preferring a “real” programmer’s IDE (though to be fair, I haven’t yet settled on which that’s going to be), but hey, we all work in teams and depending on the project, you may need to jump in bed with the enemy.

What Dreamweaver does (reasonably) well is a sort of version / ownership control (though it can’t handle multiple edits to a single file by multiple users). The principle: if you’re going to edit a file, you put a “lock” on it (ironically, removing the visual “lock” icon that shows that a file is NOT being used by anyone #uxfail). This is called “checking out” the file, and it becomes tagged with your name to let everyone else on the team know: “back off, work on something else.” When you’re done making changes on your local, you “check in” the file, which Puts it to the remote version and then unlocks it (ironically putting the “lock” icon back on it – good job Adobe UX team) so that anyone else can edit it (by checking it out themselves).

Great. So you work on the site for a number of hours, and have now checked out a pile of files all over the place. It’s time to check them back in and relinquish control. But there’s no “check in all my checked out files” menu item (as far as I can tell – comment if there is!). So what’s the solution?

Read More