Jon Aquino's Mental Garden

Engineering beautiful software jon aquino labs | personal blog

Saturday, December 30, 2006

FeedChopper: Turn any long document into a daily RSS feed


For the past day I have been building a new web service called FeedChopper. Basically you paste in a long web article or list of links or quotations, and it gives you an RSS feed that delivers one section (or link or quotation) each day to your feedreader.


I created it because I'll often come across some long article or tutorial and I don't have an hour to read it in its entirety. Or someone will recommend a good collection of links, but it would be overwhelming to read them all in one sitting. With FeedChopper I get the information in daily bite-sized pieces.

(FeedChopper is also a good simple demo of the Ruby-on-Rails-like PHP framework that we use for new apps at Ning. View the source code.)

My hope is that by chopping up long articles into daily "lessons", this service will be useful to busy people who love to learn.

Thursday, December 28, 2006

Page-Load Times for Firefox 2, Internet Explorer 7, and Opera 9.2

IE 7 seemed to be faster than Firefox, so I decided to measure page-load times for the two browsers on four popular websites.


My test setup is shown below. None of the three browsers had any extensions installed. Page-load times were measured using IBM Page Detailer on my IBM T43 laptop with a wireless connection to a cable modem, in Victoria BC, Canada.


IBM Page Detailer measures the total page-load time, including all CSS, Javascript, and images. (It can also display a "Gantt chart" of the load times of each of these assets, making it a great for performance analysis).

Tuesday, December 26, 2006

Using Diigo (social annotation tool) to highlight links you've already visited

I've got a few pages listing links that I want to read through (currently, Danah Boyd's articles on social networking, Douglas Crockford's Javascript articles, some links on Catholic evangelism, and Brian McCallister's API design references).

The problem is that I'm often not sure which links I've already visited.

So I'm now using a browser extension called Diigo that lets me highlight text on the page (e.g. the links I've already visited). Seems to work pretty well - when I come back to these pages, my highlighting is shown in yellow. It got a good review on TechCrunch.

screenshot showing highlighting

PMD Duplicate-code finder for Java and PHP

Useful tool that finds duplicate code in your source tree (Java, JSP, PHP, C, C++): PMD Copy/Paste Detector.

You can also launch it from your browser with Java WebStart.

Monday, December 25, 2006

Live *HTML* editing with Firebug 2 extension

A great feature in the Firebug 2 extension is Edit HTML - you right-click on any HTML element, click Edit HTML, and you can edit the HTML live. Comes in handy for debugging CSS issues, or trying out some new code.

Saturday, December 23, 2006

The lost art of letter writing

Inspired after reading Stoddard's book Gift of a Letter in one sitting, I marched down to the local fine stationery store and purchased some fine note cards and envelopes (with gilded border and understated decoration), as well as a Lamy italic pen, and dashed off a couple of thankyou notes (must credit Yoz again for an article on this art). Also ordered a used copy of Fred Eager's The Italic Way to Beautiful Handwriting, which I've learned from in the past.

It's often fun to turn to low-tech tools, like letter writing, to bring at least a semblance of sanity to our lightspeed technological culture.


Friday, December 22, 2006

Books Worth Reading (mostly technical)

Received an early Christmas gift - a big Amazon gift certificate. Here's what I chose.
  • Design Patterns. This must be the third time I've purchased this book. My first copy was lost; my second, left at my previous employer. When I first encountered this book in 1997, it was a revelation - these beautiful structures and patterns, crisply named and catalogued - Observer, Memento, Adapter, Visitor, Façade… Brilliant stuff.
  • Refactoring. Second time I've purchased this one. An excellent toolkit for cleaning up code - the explicit steps are helpful especially when you don't have an IDE to perform the refactoring for you e.g. PHP. A key to performing refactorings safely is to back them with unit tests - wondering how feasible this is for GUI's.
  • Refactoring to Patterns. I'm averse to reading books I've read before, so I'll be reading the highly recommended Refactoring to Patterns - DP and Refactoring will sit on the shelf as reference.
  • The Little Schemer. Recommended by the great Javascript guru Douglas Crockford. Evidently improves one's ability to think recursively, and introduces neat concepts like the Y combinator.
  • Mastering Regular Expressions. Possibly more than I want to know about regular expressions (delves into their implementation, which could be useful for optimizing performance). But I'm sure I'll pick up several tricks for making better use of this powerful tool.
  • Javascript: The Definitive Guide. Best Javascript book / reference as far as I can tell from the Amazon reviews. A weighty tome. While the Dojo library has already made Javascript an order of magnitude more powerful, safer, and easier to use, I'm still looking forward to this book as a way of increasing my knowledge of the intricacies of the language.
  • Agile Software Development, Principles, Patterns, and Practices. Been a few months since I've read a software process book (last one being Schwaber's Scrum book, which I didn't get a lot out of, and – way before that – The Pragmatic Programmer, which was for me profoundly influential, as was Extreme Programming Installed), so it's time to read another one. This book by Robert Martin is supposed to be full of good ideas.
  • Rapid Development. I keep hearing about McConnell's book, so it's time to see what the fuss is about. I read his Code Complete several years ago – a bit dated, being from the early nineties, but still had some good coding guidelines and tips (see PragProg for something more contemporary).
  • Streamlined Object Modeling. Another book recommended by This one's flush with good Amazon reviews.
  • CSS Mastery. Intermediate-level CSS book. I'd already read CSS Anthology (meaty – good stuff) and Cederholm's Web Standards Solutions (like CSS Anth., but fluffier), so I didn't want another intro-level book (which is why I passed on Cederholm's Bulletproof Web Design). This book, by well-known designers Andy Budd, Simon Collison, and Cameron Moll, seems to be the next step up.
  • The Cyberiad. Hitchiker's Guide-like novel recommended by my colleague Tim. By Stanislaw Lem – evidently one of the sci-fi greats.
  • Startup. Lessons learned from one man's startup. Supposed to be an entertaining read.
  • Dealers of Lightning. Recommended by my colleague Fabricio Zuardi. On the glory days of Xerox PARC.
  • Too Deep For Words. On lectio divina, or meditative reading of scripture.

New books - one of life's sweet pleasures.

Thursday, December 21, 2006

Switching to IE7 for the moment - Firefox too slow

Man I don't know what's up with Firefox. It's slow as molasses. Maybe it's one of the many extensions I've installed that's slowing it down.

Anyway, picking up on a tip Yoz mentioned on Twitter, I'm using IE7 now and it is super-fast in comparison - like *instant*. Anyway, going to try it as my default browser for a while to see how it goes.

Images numbered 1-24, for testing

If anyone needs any numbered images, I've made some: zip of number pngs from 1-24.

Language-agnostic indentation

Just wanted to share a style of code-indentation that I've found to express clearly the logic of if statements and other control structures inside template files. That is, when PHP and HTML are mixed together, this technique can make it much clearer what's going on (in terms of nested structures, such as if statements, for loops, etc.).

You simply indent with each level of nesting, regardless of which language you are in; for example:

<li>Quarter Pounder</li>
if ($very_hungry) { ?>
<li>French Fries</li>
} ?>

This makes a dramatic difference with complex logic. For example:

Screenshot: Before

That if statement on line 18 - is it inside the for loop or not? Is it inside any other if statements?

Compare with:

Screenshot: After

Here the nesting is clear.

Tuesday, December 19, 2006

jEdit's very useful Highlight Text plugin

I have to put in a good word for the jEdit text editor again. Every so often I find some astonishing new feature in it (such as search-and-run-Java-expression-on).

Here's one that comes in useful for my current i18n project: Using the jEdit Highlight Plugin (and regular expressions) to highlight code that needs to be done (white), code already done (green), and code I don't need to concern myself with (dark blue).

You can color any text you want, specifying the criteria with regular expressions.

jEdit screenshot

Monday, December 18, 2006

CoComment: Tracking comments you’ve left on blogs

I’m trying a neat service / Firefox extension called CoComment. It sticks a toolbar at the bottom of blog-comment boxes and tracks blog-comment threads for you.

Saturday, December 16, 2006

Remember when...? 14.4 kbps modems and Word 2.0

Remember when you got your first computer? Modems were not a requirement in that day.

Then you got your first real PC. 14 kbps modems were alright, but for faster downloads from your city's BBS, you really needed a 56 kbps modem. And even with RAM at $50 / MB, it was worth the upgrade from 4 MB to 8 MB, even if it did hurt the wallet. Especially now that MS Word 6.0's come out. Word 2.0 is faster, but 6.0 looks so much better. Yeah, WordPerfect for DOS has a clever WYSIWYG interface, but Word is clearly superior now.

And using email for the first time on text-based terminals - overusing it, caught up in the newness of it, to the annoyance of your correspondents.

And then came this World Wide Web thing. It's neat to check the world news on Yahoo. AltaVista has the biggest search index, but Google cleverly ranks search results by number of inbound links. You can check your email on the web using Hotmail.

I want to create my own webpage; my ISP gives me 10 MB free space. I wish I could comment on that article. I can comment on that article but I need to wade through all these registration pages and banner ads. I think you can put a video on the web using OurMedia, but it takes a day to show up.

Then came Blogger. And

And Flickr. And Google Maps.

And Bloglines. GMail. Google Earth. MySpace. YouTube...

We live in an age in which anyone can publish information that becomes instantly accessible to everyone in the world. It's a great time to be alive.

descriptious + Google Reader = tech news bliss

(Update: Fixed the link - thanks Sean!)

I've mentioned before that my preferred source for tech news is (seems to be more relevant to me than Digg), especially the descriptious feed which adds user-supplied descriptions.

Now, combine that feed with Google Reader's 1-line summaries, and you have a beautiful, efficient summary of the zeitgeist for the day:

Descriptious feed in Google Reader Auto-discovery of music similar to what you like

This is neat: You type in a song, and it immediately starts playing songs with a similar genre, tempo, style, etc. You can guide it with the options shown below.


Tuesday, December 12, 2006

Jon's links of note (APIs, Javascript)

Joshua Bloch: How To Design A Good API & Why It Matters (video, 1 hour)

Douglas Crockford: Advanced Javascript (three videos totalling 1 hour). On prototypal inheritance.

Firebug 1.0 beta extension for Firefox. I found the built-in page-load profiling feature so compelling that I made a donation. Screenshot below.


Sunday, December 10, 2006

Twitter: Increasing number of twitters shown in Twitter blog badge

I modified the Twitter javascript badge to list my last 10 twitters in my blog sidebar:

<script type="text/javascript">
var elapsedTime = function(createdAt) {
var ageInSeconds = (new Date().getTime() - new Date(createdAt).getTime()) / 1000;
var s = function(n) { return n == 1 ? '' : 's' };
if (ageInSeconds < 0) {
return 'just now';
if (ageInSeconds < 60) {
var n = ageInSeconds;
return n + ' second' + s(n) + ' ago';
if (ageInSeconds < 60 * 60) {
var n = Math.floor(ageInSeconds/60);
return n + ' minute' + s(n) + ' ago';
if (ageInSeconds < 60 * 60 * 24) {
var n = Math.floor(ageInSeconds/60/60);
return n + ' hour' + s(n) + ' ago';
if (ageInSeconds < 60 * 60 * 24 * 7) {
var n = Math.floor(ageInSeconds/60/60/24);
return n + ' day' + s(n) + ' ago';
if (ageInSeconds < 60 * 60 * 24 * 31) {
var n = Math.floor(ageInSeconds/60/60/24/7);
return n + ' week' + s(n) + ' ago';
if (ageInSeconds < 60 * 60 * 24 * 365) {
var n = Math.floor(ageInSeconds/60/60/24/31);
return n + ' month' + s(n) + ' ago';
var n = Math.floor(ageInSeconds/60/60/24/365);
return n + ' year' + s(n) + ' ago';
// Make date parseable in IE [Jon Aquino 2007-03-29]
function fixDate(d) {
var a = d.split(' ');
var year = a.pop();
return a.slice(0, 3).concat([year]).concat(a.slice(3)).join(' ');
function twitterCallback(obj) {
var html = '';
for (var i = 0; i < obj.length; i++) {
html += '<li>' + obj[i].text + ' (' + elapsedTime(fixDate(obj[i].created_at)) + ')</li>';
document.getElementById('twitter_list').innerHTML = html;
<ul id="twitter_list"></ul>
<script type="text/javascript" src=""></script>

Thursday, December 07, 2006

Jon's Christmas Wishlist

I've put my Christmas wishlist online as a Ta-da List. Ta-da lists are a bit old though – what's currently cool in Web 2.0 lists?

Tuesday, December 05, 2006


Here's a little Ruby script that you can use to see how your bank balance will go up and down. Enter recurring payments at the top and run it; it will print out a list of balances at various dates. You can then paste the output into a spreadsheet to visualize how it goes up and down.

It's a free alternative to the graphing functionality in MS Money.

def main

balance = 500
days_to_compute = 60
events = [
# 1st of each month,etc. [Jon Aquino 2006-12-05]*-.*-01/, "Job", +1000),*-.*-01/, "Bank service charge", -5),*-.*-01/, "Virgin Mobile", -30),*-.*-01/, "TextDrive", -15),*-06-15/, "Order of the Water Buffaloes", -500),
# Every 14 days, etc. [Jon Aquino 2006-12-05], "Jim's Mowing", -32,, 10, 11)),, "Rent", -300,, 11, 25)),

start =
1.upto(days_to_compute) do |i|
date = start + i
events.each do |event|
change = event.change(date)
if change != 0 then
balance += change
puts date.to_s + ', ' + + ', ' + change.to_s + ', ' + balance.to_s


class EveryNDaysEvent
attr_reader :name
def initialize(n, name, change, start)
@n = n
@change = change
@start = start
@name = name
def change(date)
return (date - @start).modulo(@n) == 0 ? @change : 0

class RegexEvent
attr_reader :name
def initialize(regex, name, change)
@regex = regex
@change = change
@name = name
def change(date)
# e.g. 2006-12-05 Tuesday [Jon Aquino 2006-12-05]
string = date.to_s + ' ' + Date::DAYNAMES[date.wday]
return string =~ @regex ? @change : 0



2006-12-06, Jim's Mowing, -32, 468
2006-12-09, Rent, -300, 168
2006-12-20, Jim's Mowing, -32, 136
2006-12-23, Rent, -300, -164
2007-01-01, Job, 1000, 836
2007-01-01, Bank service charge, -5, 831
2007-01-01, Virgin Mobile, -30, 801
2007-01-01, TextDrive, -15, 786
2007-01-03, Jim's Mowing, -32, 754
2007-01-06, Rent, -300, 454
2007-01-17, Jim's Mowing, -32, 422
2007-01-20, Rent, -300, 122
2007-01-31, Jim's Mowing, -32, 90
2007-02-01, Job, 1000, 1090
2007-02-01, Bank service charge, -5, 1085
2007-02-01, Virgin Mobile, -30, 1055
2007-02-01, TextDrive, -15, 1040
2007-02-03, Rent, -300, 740