I had the need to show some folks example screens of webapps I’m working on recently. Using those screenshots, the other party could have a better feel of things, we could have a clearer discussion. But the irritation [for me] is always the setup

  1. The app I’m working on is still in flux, i.e. design & data attributes will likely change, often
  2. The content I have is often imported from real data sources, and hence is somewhat private & sensitive
  3. I’m too lazy to think up fake names, fake scenarios, fake photos to fill my database, just so I could have a fragile, demo screenshot (I’d need to redo / update later)

What I’d really like is

  1. To be able to use my current webapp, as-is
  2. To be able to use my current data, as-is
  3. To protect private & sensitive data

Smells like a bookmarklet? So here it is Loremipsumizer.js. After installing it, I can anonymize any webpage instantly (then take a screenshot, annotate or print & discuss with somebody else, without worrying about the sensitivity of content)

Click here to try it on this webpage!

The Loremipsumizer will anonymize all text, scramble all numbers, replace images, flash embeds (& video tags?) with wireframe-ish cross-boxes (via data uri). Unfortunately I didn’t have an elegant solution to anonymize background images (css sprinting, image size, etc) so I’ll need suggestions there.

In any case, here are a few screenshots of webpages I’ve anonymized. No prizes for guessing which websites:

Note: Loremipsumizer does not require any JS library, and have not been tested on irritating browsers. Patches are welcome.

FOAF Rewards

The Joneses is an interesting idea: if you push product placements all the way to 11, you'd have it done in real life. But how do you attribute a [growth in] sale of product P, to the "Joneses" team member? Target market of product P + geography of the sale? And what if the network effects is far reaching and has no geographical boundary (i.e. internet)? So, no two "Joneses" teams should pimp the same product? No good.

What if we try something more pre-emptive, using something more direct - FOAF. So when customer Charlie buys Product P, your CRM picks up that amongst other customers who bought P, customer Betty is in Charlie's FOAF network (Facebook, Twitter, email, blog, flickr, etc).

With this knowledge, you could directly credit Betty a referral reward and hope to gain an army of MLM team. But this risks displacing Betty's original reason of buying your product with a weaker, extrinsic motivation.

Alternatively, you could credit Betty with a discount on her next purchase. This approach is good and already exist informally. But it is also unsurprisingly inefficient in its current state: the connection happens if you manage to make the sales assistant remember you and they bother to inquire about referrals when serving a new customer.

Wouldn't it be great if a hypothetical "iCashRegister (now with FOAF)" exist to make this more efficient?

To cap the potential hemorrhage of "discount credits" on heavily connected customers, if there are several customers connected to this new customer, they'd only each get a slice of the credits. Also, for some business, it might make sense to attribute a referral based on the transaction of the same product. For other businesses, it might make sense to attribute a referral based on purchase recency.

So now any customer connected to a subsequent customer gets discount credits. And all this can happen regardless of whether (you) the business owner is servicing the customer, or if it was just your part-time sales assistant in the shop.

To hell with wimpy loyalty cards. Why isn't your business using "iCashRegister (now with FOAF)"?

Update: Do check out Anafore if you're interested in this topic!

Yet another $5 iPad stand - this one is for the Brits

Finally, our bulky British Standard power socket design is useful for something.

Only $5.50 - but you'll probably already have one in your house. No warranty. RssPaper app sold separately.

You're Doing It Wrong - ACM Queue

What good is an O(log2(n)) algorithm if those operations cause page faults and slow disk operations? For most relevant datasets an O(n) or even an O(n^2) algorithm, which avoids page faults, will run circles around it.
the results coming out of the CS department would be so much more interesting and useful if they applied to real computers and not just toys
- Web annotation on You’re Doing It Wrong - ACM Queue

Since @replies can come from anybody

Someone, let's say Yahoo, could roll out their own twitter-like service (let's call it yatter). And all yahoo mail users "become" yatter users automatically, like how they became Openid accounts.

  1. when a yatter user "joe" yatts, "@twitter/charlie what are you doing?"
  2. yatter's twitter bot called "yatter" relays the tweet, "yatter/joe: @charlie what are you doing?"
  3. twitter user "charlie" sees the message in his @replies stream, and can respond, "@yatter/joe hitting my refresh button again and again"
  4. a yatter.com bot called "twitter" relays the message, "twitter/charlie: @joe hitting my refresh button again and again"
  5. yatter user "joe" sees that in his @replies stream in yatter.com.. (repeat from the top)

I'd guess it makes sense for yatter apis to be fully compatible with twitter.com, in the ma.gnolia.com vs del.icio.us kind of way. So twitter clients just need to add a new config, "hostname", and we're done.

I think yatter.com could technically allow @yatter/joe to follow @twitter/charlie. The question is, would twitter.com allow their @charlie user to follow @yatter/joe?

Yatter could use the age-old hotmail trick and append the latest status message of the mail sender to the email footer. That should pique interests of recipients. Besides, "a signature" is an existing, understood concept that users can easily see why they'd would want to update their "yatter status"..

An iPhone optimized web page

[UPDATE: Proof of concept no more, RssPaper is now in the store!]

The defacto way of making a web page "optimized for iPhone" is to slap on iUI (or variants) to simulate the look & feel of a native app (i.e. the UITableView). You can click on an item in the list, and the page slides sideways to reveal another list, or more details… etc.

However, the starting point of trying to mimic meant we're aiming for the web site's experience is to be worse-or-almost-as-good compared to if it was a native app. e.g. m.cnn.com Can aim to be different instead?

In trying to mimic a native app, the iUI approach locks down the browser's width & scaling capability. I actually liked that part of browsing on the iPhone – its automatic zoom! To zoom-in, you simply double-tap on an area of the page. To zoom out, double-tap again. (There's pinching, but it is manual & I don't like tedious things)

Unfortunately, most layouts don't make it easy for iPhone to automatically zoom-in. The kicker is, a good & fluid CSS layout actually hinders! e.g. the text is still small after double-tapping on jnd.org

Turns out, the automatic zoom is controlled [only] by the width of the page segment.. meaning, the page's font size can be infinitesimally small – it doesn't matter. As long as the containing width is also small (e.g. contains 5 words across 1 row), the user can still comfortably zoom in and get big text with sharp font of 5 words across the entire screen width!

Taking this to an extreme, we could have all our site's content render in tiny little font inside narrow columns on 1 single page and the iPhone visitor can still effortlessly zoom in and read everything! No click, ajax, network lag, read content, back, click another, .. etc.. i.e. instead of content hierarchy behind deep navigation, we could have it based on font sizes.

Sounds like a newspaper huh?

To try this out, I'd hacked up this proof-of-concept a few days ago, and have been using it to read my RSS feeds on my bus rides the past few days. While the app itself is not there yet, the zoom interface experiment has really been working out very well!


Have an iPhone/iPod touch? Try it and lemme know?

PS: A more extreme sell for a zoom-based UI is Microsoft's famous Seadragon demo.
PS: this whole experiment was sparked off when I tried to read the beautiful hacker-newspaper.gilesb.com on my iPhone.

9.99 Reasons to Love IE6

A friend showed me this website today: http://www.bringdownie6.com/ "Bring down!" Such angry words. There's so much negativity on the Internet regarding a browser.

Instead of 1) getting good folks to put feeble badges on websites, or 2) resigning to fate & cursing whenever you have to fire-up IE6 and check, or 3) getting bigger, better tools to do stupid things faster… Maybe we can be more constructive.

Here's an idea:

Dear Developers & Designers,

Save your sanity: At $0.00 cost to you, we make your website work in IE6!

Step 1. Register your website with us
Step 2. Just copy-paste this into your website's <head> section: <script src="http://weloveinternetexplorer.com/bff.js"></script>
Step 3. *chuckle* There's no Step 3!

How this'll work is that, all your IE6 site visitors will be gently redirected to our payment page, explaining nicely:

We're sorry but Website XYZ no longer works with your old, antique Internet Explorer browser. BUT for just US$9.99/month (1 movie ticket!) the hardworking engineers at weloveinternetexplorer.com will fixup the website for YOU, and make this problem go away for you! It'll just take 30 seconds! We accept all major credit cards & Paypal (maybe even 淘宝! Alipay (correction by @xtinegoh) )

But you choose not to :-( you may install any of these free, modern browsers and use Website XYZ through them: [firefox logo] [safari logo] [google chrome logo]

WeLoveInternetExplorer.com Team

If the IE6 compatibility work has not been complete yet, the above pay-wall will not be shown. Instead, we'd display a cool 1990s construction worker icon that these folks will be extremely familiar with!


All paid users can of course transparently continue to use the web site (and all other websites that uses this service).

PS: Designers & developers that would like to do Internet Explorer compatibility work (yes, all 3 of you out there, 尤其是中国的同胞朋友, Hội lập trình viên Việt Nam, and сотрудник российских программистов !!!!) Please contact me

Why pick a different domain name for asset_host - and not just subdomains

Some sites, e.g. Github.com, uses subdomain for images & assets

assets from subdomain

Whereas others, e.g. Yahoo.com, uses a different domain name.

assets from different domain

Because cookie bandwidth does add up.

PS: I spot George Oat's picture on Flickr frontpage still. I wonders if it is a form of respect or neglect.

How to really Post Load Google Ads (while keeping document.write happy & page rendering snappy)

So you have a web page and it is getting some hits. One day, you decide you might as well earn some pennies off that traffic and began copy-pasting some Google Ads into it.

But you know, Google Ads suck. They use document.write. Yep, the things we were warned against. But that's not all. Their document.write actually pulls in more javascript, which in turn say "weeeeell, while we're at it!" and start to do even more document.write! (In this aspect, Microsoft ads seem more thoughtful, or it seems from Digg's homepage).

Anyways, this chokes the browser & makes them stutter. Your web page now renders to your audience in stops and starts:

some content appear > ads appear (stall) > more content appear > ads appear (stall) > rest of content appear

A necessary evil? There are a few things that will fix to a certain extent: 1) use "script defer" or 2) hacking document.write. Not ideal in terms of fragility, and subsequent maintenance of ads embed codes.

Let's look at the problem again: 1) Google wants you to paste the script where the ad appears, 2) Wherever the script is pasted, the browser will stutter & stall the content that comes after it.

For #2, maybe the "solution" is to paste the script AFTER all content? But wait – doesn't that mean #1 the ads get rendered there & not where I want them? Yes, but only initially.

Why not reposition these ads to where they're supposed to be after they are constructed:

all content appear > ads appear (below the fold, stall) > ads appear in position

Let's say that works, unfortunately it sound convoluted & a hassle, the site has too many existing ads to migrate & our guy managing the ads doesn't code, he just copies whatever Google provides & blah blah blah…

That's what the postload_google_ads Rails plugin is for :-) site-wide benefit for minimum fuss (upfront & subsequently)

To see it in action, see this demo. Click on "Before" and "After". They 2 pages are essentially the same, but only one of them applies an "after_filter":

The postload_google_ads plugin is an "after_filter" in Rails. This means that after your webapp has done its thing & generated the dynamic HTML, the after_filter transplant the ads' script tag to the bottom of the DOM tree, leaving behind some placeholders. This modified html is then sent back & rendered on the user's browser. After all your content renders, the ads will construct themselves (document.write all they want). After the ads are done, a little javascript repositions the rendered ads based on the absolute position of their corresponding placeholders.

Until ads nework catch up to use unobtrusive javascript, I guess I'll have to settle for this.

git svn rebase - could not detach HEAD (howto fix)

Sounds gross but that is the curt message:

$ git svn rebase

First, rewinding head to replay your work on top of it…
could not detach HEAD
rebase refs/remotes/trunk: command returned error: 1

Not very helpful, no clue, can't even buy a vowel. But if you try something else, the error message begin to make the problem more obvious:

$ git co refs/remotes/trunk
error: Untracked working tree file 'public/images/plugout_button.gif' would be overwritten by merge.

Well… then git-svn should've said so!

$ rm public/images/plugout_button.gif
$ git svn rebase
First, rewinding head to replay your work on top of it…
Applying ….

So there. This post is so that I commit it to my long term memory, aka Google.