Skip to content

Recent Articles


Fun with Framesets in 2012

One of the things I’ve noticed in web development is a trend toward avoiding older technologies.

There’s often a good reason for this – Newer replacements allow more flexibility, work more reliably, and are better supported.

But that doesn’t mean we should always abandon old friends – In this case, I mean the humble HTML frame.

Although deprecated in HTML5, there’s still fun to be had.

But aren’t frames evil?

One of the biggest criticisms of frames is that they aren’t reliably accessed – Their very nature allow search-engines (or users) to link to one specific frame, rather than to the frameset container you’re wrapping them with.

It turns out, we have a weapon against this, which has been around since 1998- The DataURI.

Rather than linking to a specific file, using the datauri, we can embed our frame elements directly INSIDE the original page.
They can be generated at the same time, with the rest of your code, and stored directly.
This eliminates the idea of a separate page that might ever accidentally get linked to.

<frameset cols="30%,*">
        <frame src="data:text/html;base64,CjxodG1sPgogICAgPGhlYWQ+CiAgICAgICAgPHRpdGxlPkZyYW1lIE1lbnU8L3RpdGxlPgogICAgICAgIDxiYXNlIHRhcmdldD0iY29udGVudCI+CiAgICA8L2hlYWQ+CiAgICA8Ym9keSBiZ2NvbG9yPSIjMDA5OUREIj4KICAgICAgICA8YSBocmVmPSJodHRwOi8vd3d3LnlhaG9vLmNvbSIgY2xhc3M9Im1lbnUiPllhaG9vLmNvbTwvYT48YnIgLz4KICAgICAgICA8YSBocmVmPSJodHRwOi8vd3d3Lmdvb2dsZS5jb20iIGNsYXNzPSJtZW51Ij5Hb29nbGUuY29tPC9hPjxiciAvPgogICAgICAgIDxociAvPgogICAgICAgIDxhIGhyZWY9Imh0dHA6Ly93d3cuZWJheS5jb20iIGNsYXNzPSJtZW51Ij5FYmF5LmNvbTwvYT48YnIgLz4KICAgICAgICA8YSBocmVmPSJodHRwOi8vd3d3LmZhbmRhbmdvLmNvbSIgY2xhc3M9Im1lbnUiPkZhbmRhbmdvLmNvbTwvYT48YnIgLz4KICAgIDwvYm9keT4KPC9odG1sPgo=">
        <frame src="data:text/html;base64,CjxodG1sPgogICAgPGhlYWQ+CiAgICAgICAgPHRpdGxlPkZyYW1lIENvbnRlbnQ8L3RpdGxlPgogICAgPC9oZWFkPgogICAgPGJvZHkgYmdjb2xvcj0iI0RERERERCI+CiAgICAgICAgPHA+SGVyZSdzIHdoYXQgaXQgd291bGQgbG9vayBsaWtlQSBnb29kIHJ1bGUgb2YgdGh1bWIgaXMgdG8gY2FsbCB0aGUgcGFnZSB3aGljaCBjb250YWlucyB0aGlzIGZyYW1lIGluZm9ybWF0aW9uICJpbmRleC5odG1sIiBiZWNhdXNlIHRoYXQgaXMgdHlwaWNhbGx5IGEgc2l0ZSdzIG1haW4gcGFnZS4KICAgICAgICA8cD5BIGdvb2QgcnVsZSBvZiB0aHVtYiBpcyB0byBjYWxsIHRoZSBwYWdlIHdoaWNoIGNvbnRhaW5zIHRoaXMgZnJhbWUgaW5mb3JtYXRpb24gImluZGV4Lmh0bWwiIGJlY2F1c2UgdGhhdCBpcyB0eXBpY2FsbHkgYSBzaXRlJ3MgbWFpbiBwYWdlLjwvcD4KICAgICAgICA8cD5BIGdvb2QgcnVsZSBvZiB0aHVtYiBpcyB0byBjYWxsIHRoZSBwYWdlIHdoaWNoIGNvbnRhaW5zIHRoaXMgZnJhbWUgaW5mb3JtYXRpb24gImluZGV4Lmh0bWwiIGJlY2F1c2UgdGhhdCBpcyB0eXBpY2FsbHkgYSBzaXRlJ3MgbWFpbiBwYWdlLjwvcD4KICAgICAgICA8cD5BIGdvb2QgcnVsZSBvZiB0aHVtYiBpcyB0byBjYWxsIHRoZSBwYWdlIHdoaWNoIGNvbnRhaW5zIHRoaXMgZnJhbWUgaW5mb3JtYXRpb24gImluZGV4Lmh0bWwiIGJlY2F1c2UgdGhhdCBpcyB0eXBpY2FsbHkgYSBzaXRlJ3MgbWFpbiBwYWdlLjwvcD4KICAgICAgICA8cD5BIGdvb2QgcnVsZSBvZiB0aHVtYiBpcyB0byBjYWxsIHRoZSBwYWdlIHdoaWNoIGNvbnRhaW5zIHRoaXMgZnJhbWUgaW5mb3JtYXRpb24gImluZGV4Lmh0bWwiIGJlY2F1c2UgdGhhdCBpcyB0eXBpY2FsbHkgYSBzaXRlJ3MgbWFpbiBwYWdlLjwvcD4KICAgICAgICA8cD5BIGdvb2QgcnVsZSBvZiB0aHVtYiBpcyB0byBjYWxsIHRoZSBwYWdlIHdoaWNoIGNvbnRhaW5zIHRoaXMgZnJhbWUgaW5mb3JtYXRpb24gImluZGV4Lmh0bWwiIGJlY2F1c2UgdGhhdCBpcyB0eXBpY2FsbHkgYSBzaXRlJ3MgbWFpbiBwYWdlLjwvcD4KICAgICAgICA8cD5IZXJlJ3Mgd2hhdCBpdCB3b3VsZCBsb29rIGxpa2VBIGdvb2QgcnVsZSBvZiB0aHVtYiBpcyB0byBjYWxsIHRoZSBwYWdlIHdoaWNoIGNvbnRhaW5zIHRoaXMgZnJhbWUgaW5mb3JtYXRpb24gImluZGV4Lmh0bWwiIGJlY2F1c2UgdGhhdCBpcyB0eXBpY2FsbHkgYSBzaXRlJ3MgbWFpbiBwYWdlLgogICAgICAgIDxwPkEgZ29vZCBydWxlIG9mIHRodW1iIGlzIHRvIGNhbGwgdGhlIHBhZ2Ugd2hpY2ggY29udGFpbnMgdGhpcyBmcmFtZSBpbmZvcm1hdGlvbiAiaW5kZXguaHRtbCIgYmVjYXVzZSB0aGF0IGlzIHR5cGljYWxseSBhIHNpdGUncyBtYWluIHBhZ2UuPC9wPgogICAgICAgIDxwPkEgZ29vZCBydWxlIG9mIHRodW1iIGlzIHRvIGNhbGwgdGhlIHBhZ2Ugd2hpY2ggY29udGFpbnMgdGhpcyBmcmFtZSBpbmZvcm1hdGlvbiAiaW5kZXguaHRtbCIgYmVjYXVzZSB0aGF0IGlzIHR5cGljYWxseSBhIHNpdGUncyBtYWluIHBhZ2UuPC9wPgogICAgICAgIDxwPkEgZ29vZCBydWxlIG9mIHRodW1iIGlzIHRvIGNhbGwgdGhlIHBhZ2Ugd2hpY2ggY29udGFpbnMgdGhpcyBmcmFtZSBpbmZvcm1hdGlvbiAiaW5kZXguaHRtbCIgYmVjYXVzZSB0aGF0IGlzIHR5cGljYWxseSBhIHNpdGUncyBtYWluIHBhZ2UuPC9wPgogICAgICAgIDxwPkEgZ29vZCBydWxlIG9mIHRodW1iIGlzIHRvIGNhbGwgdGhlIHBhZ2Ugd2hpY2ggY29udGFpbnMgdGhpcyBmcmFtZSBpbmZvcm1hdGlvbiAiaW5kZXguaHRtbCIgYmVjYXVzZSB0aGF0IGlzIHR5cGljYWxseSBhIHNpdGUncyBtYWluIHBhZ2UuPC9wPgogICAgICAgIDxwPkEgZ29vZCBydWxlIG9mIHRodW1iIGlzIHRvIGNhbGwgdGhlIHBhZ2Ugd2hpY2ggY29udGFpbnMgdGhpcyBmcmFtZSBpbmZvcm1hdGlvbiAiaW5kZXguaHRtbCIgYmVjYXVzZSB0aGF0IGlzIHR5cGljYWxseSBhIHNpdGUncyBtYWluIHBhZ2UuPC9wPgogICAgICAgIDxwPkhlcmUncyB3aGF0IGl0IHdvdWxkIGxvb2sgbGlrZUEgZ29vZCBydWxlIG9mIHRodW1iIGlzIHRvIGNhbGwgdGhlIHBhZ2Ugd2hpY2ggY29udGFpbnMgdGhpcyBmcmFtZSBpbmZvcm1hdGlvbiAiaW5kZXguaHRtbCIgYmVjYXVzZSB0aGF0IGlzIHR5cGljYWxseSBhIHNpdGUncyBtYWluIHBhZ2UuCiAgICAgICAgPHA+QSBnb29kIHJ1bGUgb2YgdGh1bWIgaXMgdG8gY2FsbCB0aGUgcGFnZSB3aGljaCBjb250YWlucyB0aGlzIGZyYW1lIGluZm9ybWF0aW9uICJpbmRleC5odG1sIiBiZWNhdXNlIHRoYXQgaXMgdHlwaWNhbGx5IGEgc2l0ZSdzIG1haW4gcGFnZS48L3A+CiAgICAgICAgPHA+QSBnb29kIHJ1bGUgb2YgdGh1bWIgaXMgdG8gY2FsbCB0aGUgcGFnZSB3aGljaCBjb250YWlucyB0aGlzIGZyYW1lIGluZm9ybWF0aW9uICJpbmRleC5odG1sIiBiZWNhdXNlIHRoYXQgaXMgdHlwaWNhbGx5IGEgc2l0ZSdzIG1haW4gcGFnZS48L3A+CiAgICAgICAgPHA+QSBnb29kIHJ1bGUgb2YgdGh1bWIgaXMgdG8gY2FsbCB0aGUgcGFnZSB3aGljaCBjb250YWlucyB0aGlzIGZyYW1lIGluZm9ybWF0aW9uICJpbmRleC5odG1sIiBiZWNhdXNlIHRoYXQgaXMgdHlwaWNhbGx5IGEgc2l0ZSdzIG1haW4gcGFnZS48L3A+CiAgICAgICAgPHA+QSBnb29kIHJ1bGUgb2YgdGh1bWIgaXMgdG8gY2FsbCB0aGUgcGFnZSB3aGljaCBjb250YWlucyB0aGlzIGZyYW1lIGluZm9ybWF0aW9uICJpbmRleC5odG1sIiBiZWNhdXNlIHRoYXQgaXMgdHlwaWNhbGx5IGEgc2l0ZSdzIG1haW4gcGFnZS48L3A+CiAgICAgICAgPHA+QSBnb29kIHJ1bGUgb2YgdGh1bWIgaXMgdG8gY2FsbCB0aGUgcGFnZSB3aGljaCBjb250YWlucyB0aGlzIGZyYW1lIGluZm9ybWF0aW9uICJpbmRleC5odG1sIiBiZWNhdXNlIHRoYXQgaXMgdHlwaWNhbGx5IGEgc2l0ZSdzIG1haW4gcGFnZS48L3A+CiAgICA8L2JvZHk+CjwvaHRtbD4KCg==">

See this in action

If your browser supports the “data:text/html;charset=UTF-8,” type (webkit seems to like this better than others) you can make this even easier, and embed your normal HTML, straight into the original page.

This will work somewhat similarly to a resizable-div, but using 1998-level technology.

<frameset cols="30%,*">
        <frame src="data:text/html;charset=UTF-8,<html>
        <title>Frame Content</title>
    <body bgcolor='#DDDDDD'>
        <p>Here's what it would look likeA good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>Here's what it would look likeA good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>Here's what it would look likeA good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <p>A good rule of thumb is to call the page which contains this frame information "index.html" because that is typically a site's main page.</p>
        <frame src="data:text/html;charset=UTF-8,
        <title>Frame Menu</title>
        <base target='content'>
    <body bgcolor='#0099DD'>
        <a href='' class='menu'></a><br />
        <a href='' class='menu'></a><br />
        <hr />
        <a href='' class='menu'></a><br />
        <a href='' class='menu'></a><br />

See this in action

Why would I use this?

Honestly, I don’t think that anyone should 😉
But it does have certain advantages over “Splitter” style javascript –

  • It’ll work without JS enabled
  • It’s compatible with old browsers
  • The browser does the work of resizing, rather than requiring it to happen in JS

In all, it’s a fun hack, and I figured it might appeal to other people who haven’t forgotten about some of the older layers still with us in our browsers.

Of course, while it might work in Netscape 3.0, like anything fun, it doesn’t work in older versions of IE.


LinkedIn’s new Endorsement system is Viral SPAM. And that’s why it works.

Late last month, in an effort to increase user-engagement, LinkedIn launched a new feature which lets you ‘endorse’ your connections with one click.

This is intended to be a short-hand way of recommending people, designed to get the lazy among us to attest to the skills of their former coworkers. It might get clicks, but they’re meaningless noise.

It starts

The process starts when one of your colleges ‘endorses’ you using the new system.
This sends an email to your inbox, which looks vaguely interesting.


You click to investigate, and you’re presented with a list of your friends, asking if they have certain skills.

The UI makes it easy to mass-endorse your friends without even reading the dialogs, or to endorse each person with a single click.

After endorsing a skill, the dialog replaces them with with another skill for another one of your connections.

Endorsing them, however, just perpetuates the cycle. They will then receive the same email you did.
They’ll click and log in, thinking that someone might have had something meaningful to say about them, but be presented with the annoying Viral mechanism that caught you earlier.

Nowhere to run

While I appreciate that LinkedIn is trying to drive people to the site, encouraging contact-spamming seems one of the cheesiest ways to do so.
There is currently no way to disable endorsements entirely, and Unendorsing is a tedious process, requiring you to go to each profile manually.

I understand that LinkedIn is trying to ensure that LinkedIn is a tool people use every day, but this makes me more likely to simply killfile them in the future.


Pulling the Mixergy archive locally

MixergyLink is a great resource for interviews with various entrepreneurs, both famous and up-and-coming.

I generally enjoy listening to the interviews, but I recently I’ve begun trying to exercise more, and I’ve been enjoying listening to his podcast while I walk the trails.

Unfortunately, the podcasts are only available for a limited period of time, before they become premium only.

I don’t mind paying in order to download the back archives, but it’s not a straight fee-for-product transaction. At least when I last looked at it, you could only download individual interview files if you found them, one page at a time.

That’s great if you’re trying to download a single interview and listen to it, but if you want them all on your iPod to choose while walking or driving, it’s less than ideal.

Being an command line guy, I realized this should be a simple problem to solve using some bash scripting. I’m sure I could have done it in Python just as easily, but since I’m in the terminal anyway, Bash is a great Go-To solution to problems 😉

Logging in

Mixergy uses cookies for authentication, storing a login token, and then checking for it when you try to download a file.

This makes a lot of sense, and is straightforward to work with.

I logged in using Firefox, and exported out my cookies for, then saved them out to a file using a Firefox plugin.
I could then use this for the next set of requests.

Acquire List of Interviews

Since I couldn’t find a list of all the interviews on one page, I had to crawl backward on the news blog, harvesting each link.

I noticed that Mixergy always linked each interview in it’s own page, with “Read More” as the anchor text.

I tested pulling these links in, and it seemed to work reliably.

# Generate list of interviews

curl -L –cookies cookies | grep “Read more” | awk -F\” {‘print $4’}

This seemed to give me the list of interview-specific pages pretty well, so I iterated this out to the rest of the pages in the archive, moving through each page of the search results.

I added a sleep in between requests to avoid hammering the server.

# Pull ALL the Interview URLS.

for i in `seq 1 62`; do curl -L –cookies cookies$i/ | grep “Read more” | awk -F\” {‘print $4’} >> interviewpages; sleep 1; done

I then used very similiar logic to extract out the specific pages for the classes.

#Do the same for the classes.

for i in `seq 1 6`; do curl -L –cookies cookies$i/ | grep “<h2><span>”| awk -F”a href=” {‘print $2’} | awk -F\” {‘print $2’} >> classes; sleep 1; done

Looking through these, I now had a list of URLs, each of which contained the text of the interview, and a link to the MP3 version.

Acquire Each Audio File

At this point, I just had to extract the links to the mp3s.
I tested with a single page-

#Generate list of MP3s

curl -L –cookies cookies | grep mp3 | awk -F “a href” {‘print $2’} | awk -F\” {‘print $2’}

This seemed to work – It gave me a URL to a single MP3.

I then rolled this through each of the single-interview pages I had downloaded before, to find the URLs of all MP3s.

#Get the MP3 list

for i in `cat interviewpages`; do sleep 1; curl -L –cookie cookies $i | grep mp3 | awk -F “a href” {‘print $2’} | awk -F\” {‘print $2’} >> interviewmp3 ;done

This gave me a list “interviewmp3” which contained a direct link to each file.
From here, it was a simple matter to loop through and download each one.

# Retrieve all MP3s.
for i in `cat interviewmp3`; do sleep 1; wget $i; done

And Success! I downloaded hundreds of startup interviews, and can load them to whatever devices I choose, and listen to them whenever I want.



PSA: Avoid information leakage via iTunes sharing of voice memos

While waiting for my flight home from SFO, I tooling around in iTunes to pass the time.
As I my flight became increasingly delayed, I started exploring the libraries of some of the other passengers, as they passed in and out of the airport.

One thing that I noticed on quite a few laptops as they passed by, is that people are sharing Voice Memos in iTunes — And I doubt that they intend to me.


I’m not the sort to listen through people’s personal voice memos, but further testing with some of my machines show that iTunes does generally attempt to block these files from streaming, even though it does display them.

I can see how this might cause problems if the file were named something like “Shocking Confession of infidelity”, but should otherwise be fairly benign.

We can take advantage of this, in order to remove them from the Shared list-
iTunes is able to detect these files, and by default will set the “Media Type” field to be “Voice Memos”, rather than “Music”.


What I’ve done to be avoid any potential issue, however, is to uncheck “Share Entire Library”, and only allow iTunes to explicitly share “Music”.



PSA: It’s often worth investigating business pricing, even for home use

Over the last few years, a lot of consumer facing services have become increasingly hostile.
ISPs have instituted data caps, and companies have complexified what ought to be very simple, in an attempt to make it easier for people who don’t understand the terminology.

For example, when setting up your home internet, the ISP may ask you run an App that goes through a step-by-step “Wizard”.. This is almost certainly easier for many, but becomes obstructionist if you’re trying to do things off of the beaten path. (Ex: If you don’t have a Windows/Mac machine, but want to activate your connection)

This is also reflected when you are first looking at services, and trying to understand their pricing.
For example, with Verizon Cellphones –
Before the site will tell you what the service even costs, it wants you to choose a model and quantity of phones, and enter your address/zip.

I can understand their reasoning, and I’m sure this fits a number of user stories internally.. But it also makes it very frustrating when you’re trying to compare multiple options.
If my needs are fluid (such as being interested in one or more lines, depending on price, or being agnostic on phones), then this does not work well :/

Verizon Consumer
Even after making best-guess answers, I’m given yet another wizard which tries to walk me through options :/
Verizon’s business offerings, on the other hand, are straight-forward, and easy to understand.
It’s a chart, and not a very big one 😉
Screen Shot 2012 09 13 at 11 49 52 AM

Screen Shot 2012 09 13 at 11 50 00 AM

The chart gives me all of the available options, very quickly and easily.
I can choose a number of lines, dataplans, and features. The pricing is straightforward and easy to follow.

This is sadly common

Unfortunately, this is see rather often.
Comcast obscures their pricing information behind time-limited deals, making it maddening to know what your actual pricing might be.
Screen Shot 2012 09 07 at 10 00 04 PM

The real pricing isn’t anywhere in the chart – There’s no asterisk to click on, no view at the bottom. You need to go to another section of the site entirely, and cross-reference by the plan name.
Contrast that with Comcast’s business page –
Screen Shot 2012 09 07 at 9 42 48 PM
They lay out the price, the size of the pipe, and the addons. Quick. Simple. Easy.

It’s straight-forward, no bullshit pricing – Fee for Service.

It’s kinda nuts that so many companies assume their corporate customers are the only ones without a head full of potatoes. :/


Exploiting Kickstarter’s success metrics for (fun and) profit.

Edit – Please don’t do this!

If you do, you risk having the project you are supporting banned, which isn’t what anyone wants
I wrote this article as a mental exercise in exploring the Street-Performer-Protocol Trust model, PLEASE do not try this.

Because I don’t believe in Whitewashing history, I’ve left the article intact below, but once more, I’d urge you not to do anything like this…

Original Article Follows

Screen Shot 2012 06 13 at 2 41 41 PM

With the resurrection of so many great Adventure Games via Kickstarter, I’ve ended up following the platform somewhat closely, and seen a number of projects come close to failing.

Kickstarter Overview

The basic premise behind Kickstarter is that people who are creating a project can use it to raise money from the general public.
Kickstarter manages this process by allowing people to “Pledge” an amount toward a project. If the project raises enough in Pledges to meet it’s fundraising goal, Kickstarter charges everyone’s credit cards, and gives the money to the creator.

If the amount pledged is even $1 shy of the goal, however, no money is deducted from people’s credit cards, and the project creator makes nothing at all.

Old Internet wonks might recognize this as similar to the Street Performer Protocol.

Where it differs from the SPP, however, is that the money is not in escrow after it’s pledged.

The money is only drawn from a user’s credit card after the project is successfully funded.

This opens up a rather substantial exploit, in that users are able to pledge amounts they have no ability to pay.

From Kickstart’s FAQ-

What happens if a backer’s credit card is declined?

If a credit card is declined, an email is sent to the backer every 48 hours with a link to fix the
issue. The backer has seven days to correct the problem. If they do not correct the payment during
that seven day period, they are dropped as backers from the project and are no longer eligible to
receive rewards. You can view the status of all your backers on your Backer Report.

Essentially a project is declared “Successful”, and Credit Cards are charged, when Pledges reach the goal, regardless of if the pledges can ever be paid.
For many project Creators, receiving slightly less than their target goal is better than having the project fail entirely.


Let’s say that you’re watching a project that’s trying to raise $1000, and it’s going to buy a new swingset for the park down the street.
Over the last few weeks, the project has only managed to raise $750, and you can see project is going to expire later today.
Since it hasn’t reached the goal of $1000, the project will fail, and the park will remain swingless.

But Wait! You know that they sell other swings in the world. There are some that sell for only $700, rather than $1000..
Sure, it might not be as nice as the one originally pitched, but it’ll do.

Being the dastardly do-eviler that you are, you create a fake account on Kickstarter, and link it with a fake Amazon Payments account.

As on 2011, Amazon REQUIRES you to give it a SSN to sign up for an account.
This is bypassable, however. If you create an account, but close the browser window when it asks for a SSN, then re-log back in using the “Confirm by email” link, you can proceed without giving it a SSN.

Regardless, if this hole is fixed, you could use a normal Amazon Payment account, just ensure it’s empty.

You remove all credit cards from your Amazon Payments account, save one lonely $10 Prepaid card.

Then, you pledge the amount necessary to save the project.


Since the amount of pledges is now above the goal, the project is successful! Everyone’s card is charged!

Amazon tries to charge your card, but it fails, since it was only a pre-paid tiny card.

Hi there,

Amazon was unable to charge your credit card for your $300.00 pledge to Super-Swingset. This is usually caused by a recently expired, canceled, or maxed-out credit card. No need to worry — it’s a simple fix.

Just click the link below to complete your pledge with a different credit card:
Update your Pledge.

The rest of the pledges go through, however.

The money is charged, and the project is successful!


Thanks to you and 136 other backers, Super-Swingset has been successfully funded. Amazon will now charge your credit card.

You saved the park!

On the other hand, you defrauded Kickstarter, Amazon, and all the other pledgers, who won’t get their money back now.

What can Kickstarter do?

It seems like the easiest way to avoid this problem would be to either do a Credit Card authorization hold when they first pledge, or to withdraw the money at pledge-time, and keep it in escrow.

With either of these strategies, however, Kickstarter is inconviencing their users, who lose access to the money during the month, or may need to pay additional interest due to KS withdrawing the money early.

It seems a pretty thorny problem, and I hope that KS is able to come up with a decent solution.
I’ve never used this tactic to save a project, but I can’t say I haven’t been very tempted.

Thoughts welcome.


Compress any file into a Tweet?!

This morning I launched, an online tool for reducing any file to a tiny, almost impossible size.

Screen Shot 2012 04 09 at 12 50 53 PM

I launched a fun website for it, as a portmanteau of “Hash” and “Shrink”.

The theory behind it was one I first started playing with in 2008, which is the idea of creating every possible iteration of a file, to find all the hash-collisions.

You’d then reject any candidates that didn’t fit certain qualifications. For instance, you might reject any file that isn’t a valid MP3, or any file that doesn’t match a perceptual hash
After all the filters, you’d indicate which hash-collision generated the correct version of you file.

I wrote up two versions to play with the idea, and see what it might look like.

Writing it was a lot of fun, and I got more practice using multi-processor code in Python.
Unfortunately, it’s entirely impractical, at least without Quantum Computers.

The problem is, even a fast machine using the GPU can only do 400K hash collisions per second.

At this rate, it would take more time to re-create the file, than has so-far elapsed in the universe.
That’s a bit slow 😉

In any event, I figured it’d be fun to make up a website for the project, and put a demo online, which calculates how-long your file would take to return.

After a bit of playing and a cheap template from ThemeForest, I put together some images for it.

The logo was a lot of fun, trying to emphasize the dual-nature of the name.

I also had fun trying to make images which ‘pop’I hate this word, and get practice using some flash tools to cycle between them. was born.


Identity Based Trojans

Alt. Linkbait title- “Is your iPhone Spying on you? [1]


Apple is famous for their “Walled Garden” approach to the iPhone and iPad.
No software ships on the phone without their expressed approval.
The downside of this approach is that Apple has control over what you are allowed to use- They can block eReaders, Podcast software, and Torrent client, and there’s not much you can do about it.

In exchange, the protect you from having to worry about Trojans, Viruses, and other Malware.

The problem is, there’s a whole class of Malware that Apple hasn’t (and really can’t) do much to protect against at all.

If you’re dedicated to stealing info from someone’s cellphone, cleverly written apps are a good way to get started.

Your Apps know who you are

Every app you install has various ways of knowing who you are.

It can use various hardware unique identifiers to compare against other databases, it can check your address book, and see who you say you are, and although Apple is starting to restrict these, there are still alternatives for tracking you across multiple applications.
Apps can pull your phone’s name from APIs.
Using undocumented APIs, apps can directly even pull your email address without explicit permission.

The app could also just load the Phone Number directly. This method has been Exploited Before.

Or, if everything else fails, it can ask you to sign up for an account, and give it an email and password. Almost everyone uses the same email address for all their programs, so it ties them fair uniquely.

Your app can spy on you

One the Application knows you you are, it could begin selectively spying on you.
Once the App has identified that you are a target worth spying on, it has several options.

It could pull pictures from your camera roll.
It could take pictures of you, using either the frontside or backside camera, without showing you the viewfinder.
The phone could record audio of you, and upload it all to the badguy headquarters.

Wouldn’t Apple block the App?

If they found out about it, yes.
Once the fact that your app was doing that became public, Apple would almost certainly pull the App.
The problem is, if your careful, Apple is unlikely to know.

Appstore Reviews consist mainly of manually operating/examining the app, and automatically looking though the executable for internal-only APIs.
Apple doesn’t receive or review the source-code to your application, and can’t watch every execution path.
This is what allowed other applications to Slip through the review process.

If you are discreet in what you do- For example, only record video of a few select targets, it seems likely you’d be able to get away with this for quite some time.

What can I do?

Luckily, Apple is taking steps to make this exploit more difficult.
They’re making it more difficult to determine who you are, or to access the Address Book without your permission.
Down the line, they may decide to require a prompt before accessing the Camera or Microphone.

Until then, there’s not much you can do.
Unlike on the Macbooks, there’s no green light next to the camera when it is recording.
Even the NextStations had a hardware light when they were recording Audio

The best advice I have, if you’re paranoid, is
1) Don’t Jailbreak. This only adds other attack vectors.
2) Under Settings, General, Restrictions, you can disable the Camera.

This will stop applications from accessing it, but will also be rather inconvenient, if you ever do want to take a picture.
Perhaps, if you’re worried, you should carry a point-and-shoot.

Is this likely

No. Unless you’re famous, it seems possible, but unlikely, for you to be targeted for a customized attack.

[1] – No.

Portions of the title image copied from renaissancechambara.
Others from iStockPhoto.


Comparison of Open Source Licenses

As I’ve been working on my little Forum Project over the last few months, I’ve run across a number of code snippets that I’d love to use.

Often they’re little things, posted to blogs explaining how to format a URL or whatnot, but I can’t legally use any of them.

Under the Berne Convention, every single bit of text or code you create is automatically copyrighted.
You don’t need to put a © or date on it, and no one can use it without your expressed permission.

I’ve written to each of the authors, and received releases, but one common thread I’ve heard is that people aren’t sure what license is right for them.

I’m certainly not an expert, but I wanted to put together a quick comparison of different licenses, and the implications.
I’ve included links for each to read them yourself. Please read through the license before applying it to your project. I’m just a Sysadmin, not a legal advisor.

One thing to note is that if you wrote the code, releasing it under a certain license never limits what You can do with it going forward.
You’re welcome to release the code under the GPL, then keep all your updates closed-source and for-pay, and never release them under any open source license.
So long as you’re the one who wrote all the code, releasing under an Open Source license just explains what Other people can do with the code.

For example, For a long time, Mozilla released the Firefox code under the MPL, AND the GPL, AND LGPL, letting people choose whatever license they wanted for the codebase.
Oracle releases MySQL under the GPL, but will also sell you a commercial version under other terms.
As long as all the code in the project is yours, you’re free to do whatever you want.
The only warning is that when things are open, other people often want to help write code- You’ll want to make sure they either assign the copyright to you (letting you do whatever you want, as if you wrote it).

There are few elements with different licenses differ about:

Attribution– Different licenses ask that you recognize the author in different ways. Some let you take credit for the code, others ask for a line in the About section, and others want placement on all advertisements for any product that uses any of it’s code.
Some licenses include a clause that makes it clear that you shouldn’t use the name of the original company when talking about your own product. This is referred to as an “Anti-endorsement” clause.
Copyleft– Licenses that use Copyleft are sometimes called “Viral” licenses; If you include any code that uses that license in your code, then your entire program has to be released under a compatible license.
Their goal is to stop companies from taking your code, building on it, then keeping all the changes to themselves.
If they use your code, they have to release theirs.

  • A “Strong” copyleft license says that only programs which are under the same license are able to use this code.
  • A “Weak” copyleft license says that all changes to this particular code must be released, but other software can be built using this as a library, and that can software can be under a different license.

Patent Protection– Traditionally, software licenses, including Open Source Software licenses don’t deal with patents at all. This has lead to difficulties wherein a company might release their software as Open Source, but years later explain they have a patent on the underlying ideas. Even though you’re allowed to use their software under Copyright law, they can still come after you under Patent law. Some licenses include a patent license, to avoid this situation.
Web Application– Another shift we’ve seen is companies move from distributing software, to running offering hosted versions of that software on their websites. Some copyleft software licenses ask that Web Applications release their code, where others only apply if you actually distribute the software to someone else.
Permissive– Sometimes people will talk about how “Permissive” a license is. The more Permissive a license is, the more you are allowed to do with that software without the license coming into play. These range from Very permissive licenses, such as the MIT/X license, to more restricted licenses such as the EULA that commercial software packages have.

One important thing to note is that OSS licenses are almost universally licenses on Distribution, NOT on use.
Unlike a EULA, you do not need to agree to the license in order to use the software.

The license only comes into play if you are distributing it, either directly (GPL/LGPL/etc) or by exposing it as a webapp (AGPL)

License Attribution Required Anti-Endorsement Copyleft Applies to web apps Patent Protection Notes
Gnu GPL 2 Include in Source code None Strong No Indirect The great Grand-daddy of OSS licenses, The GPL2 covers the Linux Kernel, and is widely considered the progenitor of Copyleft licenses.
Gnu GPL 3 Include in Source code Various options available per project Strong No Direct In 2007, the FSF updated the GPL to version 3 to add explicit patent protection, and a provision to prevent “tivoization”,
which is when software is free, but only used on locked down hardware.
Many GPL2 licenses include a line allowing them to be dual-licensed under the GPL3.
AGPL1 Include in Source code None Strong Yes Indirect The AGPL1 is a version of the GPLv2 modified to say that websites that run webapps using the code need to distribute changes, just as if they had shipped it.

Include in Source code Various options available per project Strong Yes Direct The AGPL3 is a version of the GPLv3 modified to say that websites that run webapps using the code need to distribute changes, just as if they had shipped it.

Include in Source code None Weak No Indirect The LGPL2 is a version of the GPLv2 designed for libraries, or other small sections of code.
This requires that any chances to that component are contributed back, but software which uses the library does not need to be open.

Include in Source code Various options available per project Weak No Direct The LGPL3 is a version of the GPLv3 designed for libraries, or other small sections of code.
This requires that any chances to that component are contributed back, but software which uses the library does not need to be open.

MIT/Expat License
Include in Source code None No No None The MIT license (or Expat license) is a common and straight-forward permissive license.

MIT/X11 License
Include in Source code Anti-Endorsement No No None The X11 variant of the MIT license includes a provision to prevent people that use the code from saying they’re endorsed by the team that originally wrote the code.

2-Clause BSD
Include in Source code No None No None The 2 clause BSD license is permissive license similar to MIT/Expat license.
There is some confusion when people refer to “The BSD license” because there have been 3 versions of BSD licenses.
Because of this, people should always cite the number of clauses in the BSD license, or use something more straightforward.

3-Clause BSD
Include in Source code Anti-Endorsement No No None The 3 clause BSD license is permissive license similar to MIT/X license.
It adds a similar anti-endorsement clause to the 2-clause BSD license as MIT/X does to MIT/Expat.

4-Clause BSD
Include in all Advertising. Anti-Endorsement No No None The 4 clause BSD license (Or “original BSD license”) is a BSD variant which adds a clause to the 3-clause BSD.
Any time there is an advertisement for software which includes any code under this license, the original code needs to be mentioned. Most people are best avoiding this license entirely.

Apache License 1.0
Include in all Advertising. Prohibitions against using the Apache name No No None The Apache License 1 is a standard permissive license with an advertising clause.

Apache License 2
Include in Source code Trademark Protection No No Direct The Apache License 2 is a standard permissive license with explicit patent grants.

Include in Source code Trademark Protection Weak No Direct When Mozilla originally released their code, they created a ‘Business Friendly’ license. They’ve recently revised it to be explicitly compatible with the GPL family.

Include in Source code Trademark Protection Weak No Direct The CDDL is a version of the MPL1.1 that was modified by Sun to try to clarify language, in ways which were incompatible.

What a mess!
What’s even more “Fun” is trying to combine them.
Some of the licenses are compatible with one another, and others aren’t.
Still others are compatible, but only if you stand on your head and chant in latin.
I’ve included my personal understanding of how they combine below. As always, consult a lawyer, and let me know if I missed something.

I wrote this table from the perspective of, assuming I have existing codebase A, am I allowed to import code B?

Current code:

New Code:

GPLv2 GPLv3 AGPLv1 AGPLv3 LGPLv2 LGPLv3 MIT/Expat MIT/X11 2-Clause BSD 3-Clause BSD 4-Clause BSD Apache MPL2 CDDL
GPLv2 Yes [1] [1] [1] Result is GPLv2 [1] Result is GPLv2 Result is GPLv2 Result is GPLv2 Result is GPLv2 No No [2] No
GPLv3 [1] Yes [1] Yes [1] Result is GPLv3 Result is GPLv3 Result is GPLv3 Result is GPLv3 Result is GPLv3 No Result is GPLv3 [2] No
AGPLv1 [1] [1] Yes [1] Result is AGPLv1 [1] Result is AGPLv1 Result is AGPLv1 Result is AGPLv1 Result is AGPLv1 No No No No
AGPLv3 [1] Yes, result is AGPLv3 [1] Yes [1] Result is AGPLv3 Result is AGPLv3 Result is AGPLv3 Result is AGPLv3 Result is AGPLv3 No Result is AGPLv3 [2] No
LGPLv2 Yes, result is GPLv2 [1] [1] [1] Yes [1] Result is LGPLv2 Result is LGPLv2 Result is LGPLv2 Result is LGPLv2 No No [2] No
LGPLv3 [1] Yes [1] Yes [1] Yes Result is LGPLv3 Result is LGPLv3 Result is LGPLv3 Result is LGPLv3 No Result is LGPLv3 [2] No
MIT/Expat Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
MIT/X11 Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
2-Clause BSD Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Tes
3-Clause BSD Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
4-Clause BSD No No No No No No Result is 4-clause BSD Result is 4-clause BSD Result is 4-clause BSD Result is 4-clause BSD Yes Result is Apache + Advertising Clause Result is MPL with Advertising Clause Result is CDDL with Advertising Clause
Apache2 No Yes No Yes No Yes Result is Apache2 Result is Apache2 Result is Apache2 Result is Apache2 Result is Apache2 + Advertising Clause Yes Yes Yes
MPL2 [2] [2] No [2] [2] [2] Result is MPL Result is MPL Result is MPL Result is MPL Result is MPL with Advertising Clause Yes Yes No
CDDL No No No No No No Result is CDDL Result is CDDL Result is CDDL Result is CDDL Result is CDDL with Advertising Clause Result is CDDL No Yes

Also note that I’ve simplified the result slightly, to reflect the practical effect. For example, I say that MIT/X11 + 4-Clause BSD Result = 4-clause BSD.
Realistically, the code is now combination of the two licenses, and you need to follow and include both code, but as far as effective restrictions, it now acts like 4-clause BSD.


In many cases, licenses contain a clause which allows you to upgrade to later versions of the same license.
For example, the default version of the GPLv2 includes a clause to allow users to “upgrade” to GPLv3.
If this cause was included, you can freely mix this code, with the resulting combination being covered by the newer license.
You should check to see that this clause is included. Some prominent software, such as the Linux Kernel, does not have it.

Other software may require BOTH sides to update to newer versions of the licenses
For instance, the AGPLv1 and GPLv2 are incompatible, but if both packages contain “Or later versions” clauses, they can be upgraded to AGPLv3 and GPLv3, which are compatible.


The MPL2 performs kind of a neat hat-trick
It indirectly allows compatibility with the GPL-series of licenses, by a bit of legal maneuvering.
The end result is that you can use combine them, but keep the MPL code MPL’d, and the GPL’d code GPL’d.


Thoughts on CloudFlare



Over the last few weeks, I tested CloudFlare as a low-cost CDN for

I did this partly to test the speed, and partly to reduce the bandwidth costs that I was seeing through MaxCDN.

A little background – CloudFlare works by taking over as the primary DNS provider for your domain- In order to use their service, you need to set CloudFlare as your domain’s primary name servers.
This makes some sense, since they can route to various servers on their site as necessary, but creates a bit of a headache-

I offer Robohash in both HTTP and HTTPS versions. In order to serve HTTPS through CloudFlare, you need to be a premium/paid member. That’s fine, and I don’t mind the fee, but you can’t upgrade your account until your DNS already is moved over.

This creates a bit of a headache in that you to commit to fully using CloudFlare before you get a chance to really test it. With most CDNs I’ve used, I can setup an Origin-Pull, and run both concurrently.


Subjectively, the site did feel faster. I also noticed the number of hits that were hitting my nginx instance were cut down dramatically. Within 2 days, the number of hits reaching my server were cut to 1/7th of what they had been prior.

That makes sense, since the content is HIGHLY cacheable. In the typical usage, such as a forum or blog, the Robot will be generated for the first user, and then every subsequent load will be from cache.

Pingdom didn’t report any clear change in the load times.
If anything, the page load times seem far more variable after moving over.


Enabling SSL support through Cloudflare was spookily simple.
CloudFlare accepts the SSL request to their site, and proxies it back to my origin over normal HTTP.

I didn’t need to give them a copy of my certificate, or give them any additional information.


Essentially Off

Security Setting

CloudFlare has a built-in feature which helps to protect your sites against attack- When users who are suspected being a threat (such as infected PCs, Spammers, or would-be hackers), CloudFlare blocks their access to your site.
Optionally, you can allow these users access, if they pass a CAPTCHA.

RoboHash is a pretty simple service, and I want to make it available to as many people as possible.
Since it loads as part of OTHER people’s sites, I don’t want it blocked. I don’t care if they’re actively trying to hack ME, don’t block it. I don’t want users of Robohash to have a degraded experience.

I emailed CloudFlare, and asked that we disable the blocks entirely. They admitted that there are false positives, and there’s no way to fully disable the feature. They suggested the ‘Essentially Off’ functionality, which is supposed to only challenge the worst of the worst.
Running the service for 2 weeks gave me over 30 blocked IPs, most for being part of a botnet.


I’m not at all comfortable with the number of blocks they were performing.
Further, CloudFlare sets a cookie on every request.

I don’t want this, and it’s not fair to downstream users of

threepwood:~ e1ven$ curl -I
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 27 Feb 2012 20:15:10 GMT
Content-Type: image/png
Connection: keep-alive
Expires: Tue, 26 Feb 2013 20:15:10 GMT
Cache-Control: public, max-age=31536000
CF-Cache-Status: HIT
Set-Cookie: __cfduid=d9c25dc8324ac644c1ae0f980ae487c311330373710; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/;

versus the native request

threepwood:~ e1ven$ curl -I
HTTP/1.1 200 OK
Server: nginx/1.0.2
Date: Mon, 27 Feb 2012 20:16:43 GMT
Content-Type: image/png
Connection: keep-alive
Expires: Wed, 29 Feb 2012 20:16:43 GMT
Cache-Control: max-age=172800

As an additional point of comparison, here is the result from MaxCDN, another CDN who I’ve had good luck with.

threepwood:~ e1ven$ curl -I
HTTP/1.1 200 OK
Server: nginx/0.8.36
Date: Mon, 27 Feb 2012 20:34:32 GMT
Content-Type: image/png
Connection: keep-alive
Expires: Wed, 29 Feb 2012 20:21:28 GMT
Cache-Control: public, max-age=172800
CF-Cache-Status: HIT
X-Cache: HIT

Missing Images


Finally, however, I started seeing an increasing number of missing images.
Every so often, maybe one in 20 page loads, I’d see a Robot not just appear at all.

That’s simply unacceptable.


Ultimately, I’ve removed CloudFlare from the DNS for Robohash.
I apologize for any inconvenience caused while I was using it.
I like the idea behind their service, and I can see how it might be useful for a large number of sites, but their offerings are tremendously invasive, give you limited control over disabling their ‘features’.

It’s a good deal if you’re looking to help protect your blog from the slashdot-effect, particularly as a solution that semi-technical users can implement. If you have the patience to learn, it seems like in most cases you’d be better off with a caching Nginx server, potentially combined with a cheap standalone CDN.

You’ll get better performance, more control, and fewer surprises.