All Posts (68)

Keirsey Temperament Sorter

According to the Keirsey Temperament Sorter, my personality type is E/I-N-F-J.

Here is a description of INFJ:

INFJs are gentle, caring, complex and highly intuitive individuals. Artistic and creative, they live in a world of hidden meanings and possibilities . . .

. . . They put a lot of energy into identifying the best system for getting things done, and constantly define and re-define the priorities in their lives . . . 

. . . INFJs are concerned for people's feelings, and try to be gentle to avoid hurting anyone. They are very sensitive to conflict, and cannot tolerate it very well . . .

Because the INFJ has strong intuitive capabilities, they trust their own instincts above all else. This may result in an INFJ stubbornness and tendency to ignore other people's opinions . . . On the other hand, INFJ is a perfectionist who doubts that they are living up to their full potential . . .

Read more…

Jon's 1-Month Rule

Are you trying to figure out if you should buy the expensive version of something or the cheap version?

Just use Jon's 1-Month Rule: Am I going to use this at least once a month?

If so, then buy the more expensive one.


The same applies to time and energy. If you are going to use it less frequently than once a month, then don't waste much time researching reviews, nor much energy stressing about your purchase afterwards, etc.

Read more…


This is interesting for Canadians waiting for the neighbourhood social network to open in Canada. It's called and it looks like the same sort of thing, but for Canadian neighbourhoods.

The funny thing is that there are only like 2 pages on the internet that link to it. Wonder why there aren't more articles about it.

Read more…

APA Style Validator

My wife needs to write some papers that conform to APA style/references. I looked on the web but couldn't find a validator/lint program for APA style.

So I wrote this one: APA Check. It only has a few checks right now, but that will grow. It's written in JavaScript so it's easy to hack and submit pull requests.

Read more…

You are Orange

"People who are ORANGE are often spontaneous and flamboyant. They need a lot of variety and freedom. They take pride in being highly skilled and in being able to do several things at a time. They enjoy "hands on" work and often are good in a crisis. They are risk takes, seek challenges and are optimistic."

From the True Colors Personality Test.

Read more…

Don't just "make something". Rather, "make good".

Every so often on Hacker News, there is an article calling upon everyone to "make something". There is the Maker Culture (Wikipedia) and Maker Faire and Maker Spaces. And the mantra is "just make something". Anything. It does't matter. Just Make Something!

I don't agree with this philosophy of life at all. It seems so shallow. A better philosophy is the Catholic (and Aristotelian) one given by Joseph Pieper in his book The Four Cardinal Virtues ( that the ultimate goal of a human being is to "love the good and accomplish it".

How to do that? Here are some examples from a Guide for Confirmation Sponsors that I received today from my parish:

  • Spiritual Works of Mercy
    • Be the first to bring peace; never hold a grudge.
    • Encourage those who are discouraged by difficulties in trials.
    • Give your sympathetic understanding to your friends and family when they are in sorrow
    • Pray for all the people that you know whether they are living or dead.
  • Corporal Works of Mercy
    • Freely give to charitable organizations.
    • Give useful clothing to the poor.
    • Help with babysitting.
    • Attend funerals.

I would rather do any of the above works of mercy than make a pinwheel operated by a DC motor controlled by a Raspberry Pi computer. 

Read more…

Fr. Larry's homily

Fr. Larry gave a nice homily last Sunday on the Feast of the Holy Family. Main point was that the family is all about:
  • Love: Giving of oneself.
  • Prayer: Going to the Source to fill oneself up with love to give to others.
  • Sacrifice: Uniting love and prayer.
  • Forgiveness: Essential for marriage.
Read more…

Photo Storage Strategy

My wife and I are taking more photos these days, and like most people, we now need a "photo storage strategy" - a solution for managing all of the digital photos we take. We have a couple of thousand old photos, and new photos coming in via our iPhones and our digital camera.

Our criteria for the system were:

  1. Easy-to-use photo management software for the wife.
  2. Large storage capacity (the 60GB on the Macbook Air was filling up fast).
  3. Cloud backup.

The solution we came up with was:

  1. iPhoto. Wife was already using it.
  2. 1TB external USB drive that we already have.
  3. CrashPlan $6/mo cloud backup.

We considered various alternatives.

  1. Alternatives to iPhoto: Picasa. But people say it's not so easy to use. Plus my wife already knows iPhoto, although she finds the photo-book functionality annoying to use. I told her to just use albums instead of photo-books.
  2. Local Storage: For network drives like Synology ($500) or Zyxel ($250) I'd rather not pay. A nice thing about the Synology is that you can do headless backups (no computer required) - I'm not sure about the Zyxel. There's also the WD MyCloud ($150) but it has terrible reviews.
  3. Cloud Backup: Google Drive and Dropbox don't seem to work well with external USB drives. MS OneDrive says that they do work with external USB drives, but I don't trust it, given that Google Drive doesn't. So I'm left with CrashPlan and BackBlaze, which are pretty much on par with each other.

One cool thing I discovered about iPhoto is that when I sync our iPhones and camera with it over USB, it figures out which photos have already been imported, so it imports only the new ones. Nice!

Read more…

Apple Maps GPS is way better than Google Maps GPS


* It gives you the information you need (turn arrow and distance to the turn) in a high-contrast, large font. With Google Maps, I glance down and I can hardly read the information – it's dangerous.

* The street lines are thicker and contrast strongly against the background (unlike Google Maps, which is white on cream).

* The view is tilted, like a regular GPS, unlike Google Maps, which is straight down.

Read more…

Vine video as the sonnet of this generation

I have been wondering what is the attraction of Vine videos - those six-second looping videos.

Then today I was reading about the sonnet (16-line poems), and how popular they were in England in the 16th century. Maybe Vine is the sonnet of this generation?

Consider the following description of the sonnet - note that it has some similarity to a Vine video with its 6-second constraint:

Very often these love poems were addressed to a small circle of congenial spirits—fellow poets, wits, ladies of fashion—whom the poet wished to amuse. The way to impress this company was to exhibit special ingenuity in devising new variations on the old theme or in polishing one's work to an impressively high gloss. The reproach that such poetry is “insincere” would have astonished any Elizabethan. The rules were there with all the weighty authority of tradition behind them, and they were there to be followed. To depart from them would be as incomprehensible as if a chess player were to propose a change of rules to his opponent in order that he “might express himself better”.

—Adventures in English Literature

Read more…

Programming by Equivalence

I would like to introduce a programming technique called “Programming by Equivalence”. You can't use it all the time, but when you can use it, it’s great.

Problem: You have an existing feature X, and you want to implement a similar feature Y.

Solution: For every line of code for X, create a line of code for Y.

The beauty of this technique is:

  1. You don't need to think much - just find each line of code for X and make an equivalent line of code for Y.
  2. You know when you are done: when every line of code for X has an equivalent line of code for Y.

Here is a script that can help you to do 1 and 2 above. Just tweak the variables in the script to match your own code. Suppose you have implemented Google +1 buttons in your codebase, and now you want to add LinkedIn buttons. Run the script, and you will get output like:

lib/XG_ConfigHelper.php::: return B()->getMainConfig('googlePlusOneEnabled') === '1';
lib/components/bundle/controllers/EntryController.php::: if (R('XG_ConfigHelper')->isGooglePlusOneEnabled()) {
lib/components/bundle/lib/EntryListService.php::: if (R('XG_ConfigHelper')->isGooglePlusOneEnabled()) {
lib/components/bundle/lib/MustacheTransformer.php::: ->socialButtons()->googlePlusOneButton($entry);
lib/mustache-templates/v1/bundle/article/list.mustache::: {{{googlePlusOneButtonHtml}}}
. . . . . . . . . .

Note that the script looks for the X string (in my case, googlePlusOne) and checks if a corresponding Y string exists. The script outputs any X lines that do not have corresponding Y lines.

Using this technique, the creation of feature Y becomes mechanical. You keep running the script, and keep implementing the lines that it finds. If there are any lines that are false-positives, you mark those lines in the script. When the script's output is empty, you're done.

Thus you can be quite confident that you have thoroughly implemented the new feature.

Read more…

Cool: LibaryThing tag cloud

This is cool - if you input all of the books you own into LibraryThing, you can get it to display a tag cloud of your interests. Here are mine. Catholicism, poetry, and programming pretty much sums it up.

Read more…

Studying the QuickDraw source code

According to the interview with Donald Knuth in the book Coders at Work, Bill Atkinson's work is "well-documented code with lots of pioneering graphics algorithms in it." Let's review his code together - I created this public code review of his QuickDraw code. Come and leave comments on it and let's learn together.

Read more…

Wow. Just yesterday I opened one of my favorite books, Revolution in the Valley, containing war stories about the creation of the Macintosh computer. I was reading all of the introductory matter carefully (the scans of an engineer's notebook) when I noticed that one of the pages contained signatures of several original members of the Mac team. Note in the accompanying photo the signatures of Woz, Bill Atkinson, Daniel Kottke, Caroline Rose, Andy Hertzfeld, Bud Tribble, and Susan Kare (with the ⌘ symbol).

This is really cool. It's funny to think that this is inside a book I bought for $12.99 from a used bookstore in Victoria BC several years ago.

Read more…

Literate Programming is a style of programming invented by Donald Knuth in which, instead of the usual style of embedding comments in code, you instead embed code in comments. The result is a long narrative of prose (describing how you are writing the code) with code snippets interspersed throughout.

This never caught on. Perhaps because programmers don't like writing documentation? However, I have noticed something interesting. Sophisticated programmers today write lengthy commit messages. It is an example set by the Linux kernel committers - check out their wonderfully descriptive commit messages. (I first learned about the high quality of Linux kernel commit messages from 5 Useful Tips For A Better Commit Message.)

It strikes me now - I wonder if commit messages are the new Literate Programming. It is said that programmers don't like writing documentation, but they seem to willingly put a lot of effort into writing long, descriptive commit messages. Here's an example of a meaty commit message from the Linux kernel:

commit d940878632e63d7f0c2af5e4ebfcf5135c48dcfb
Author: Jan Kara <>
Date:   Wed Jul 11 23:16:25 2012 +0200

    jbd: Fix assertion failure in commit code due to lacking transaction credits

    ext3 users of data=journal mode with blocksize < pagesize were occasionally
    hitting assertion failure in journal_commit_transaction() checking whether the
    transaction has at least as many credits reserved as buffers attached.  The
    core of the problem is that when a file gets truncated, buffers that still need
    checkpointing or that are attached to the committing transaction are left with
    buffer_mapped set. When this happens to buffers beyond i_size attached to a
    page stradding i_size, subsequent write extending the file will see these
    buffers and as they are mapped (but underlying blocks were freed) things go
    awry from here.

    The assertion failure just coincidentally (and in this case luckily as we would
    start corrupting filesystem) triggers due to journal_head not being properly
    cleaned up as well.

    Under some rare circumstances this bug could even hit data=ordered mode users.
    There the assertion won't trigger and we would end up corrupting the

    We fix the problem by unmapping buffers if possible (in lots of cases we just
    need a buffer attached to a transaction as a place holder but it must not be
    written out anyway). And in one case, we just have to bite the bullet and wait
    for transaction commit to finish.

    Reviewed-by: Josef Bacik <>
    Signed-off-by: Jan Kara <>
    (cherry picked from commit 09e05d4805e6c524c1af74e524e5d0528bb3fef3)
    Signed-off-by: Willy Tarreau <>

Reminiscent of Literate Programming, no?

Read more…

In Mustache templates, sometimes you just want to test if an array exists, without iterating over it. However, {{#myArray}}...{{/myArray}} will iterate over myArray. What if you just want to check if myArray exists?

Solution: {{#myArray.0}}...{{/myArray.0}}

This will operate on the first (i.e., 0th) element of myArray.

Read more…

Lisphp at Ning - Sample Code

Here is the Lisp that I have written as an experiment with Lisphp. It is probably not great Lisp code—I don't have prior experience with Lisp—so any suggestions for improvement are welcome. I encourage others to make their Lisphp code publicly available so that we can all learn. Another Lisphp example I have found is balrog.

This code is for rendering an activity feed (like a Facebook Wall). It takes a bunch of activity-item objects, processes them, then feeds them into a Mustache template. The processing step sets up variables for the Mustache template to use.

For new Lisp programmers, I recommend the use of an editor plugin that automatically indents your Lisp code. See my first Lisphp blog post for related recommendations.


;;; Top-level module for rendering an activity feed for the network.
;;; @param string title  the title for the activity section
;;; @param array feed-events  the feed-event objects, parsed from JSON
;;; @param integer excerpt-length  the length at which to excerpt activity items
;;; @param string like-type  the naming scheme for likes: like, promote, or favorite
;;; @param string network-name  the name of the network
;;; @param string network-url  the URL of the network
;;; @param string network-icon-url  48x48 network icon
;;; @return string  HTML for the network feed

(import 'lib/components/activity/lib/process-feed-events.lisp')
(import 'lib/components/activity/lib/add-type-specific-properties.lisp')

;;; Filters, caches, and processes the given network feed events.
;;; @param array feed-events  the feed-event objects
;;; @param array options  options: excerpt-length
;;; @return array  the feed-event objects after processing
(define (process-feed-events feed-events options)
        ;; Remove rolled-up feed events for now, until we implement handling
        ;; for them.
        (setf! feed-events (remove-rollup-feed-events feed-events))
        (setf! feed-events (add-basic-properties feed-events options))
        (setf! feed-events (add-type-specific-properties feed-events options)))

(setf! processed-feed-events
       (process-feed-events feed-events
                            (hash 'excerpt-length'   excerpt-length
                                  'like-type'        like-type
                                  'network-name'     network-name
                                  'network-url'      network-url
                                  'network-icon-url' network-icon-url)))

;; Send the feed-events into the Mustache template.
((-> B renderMustache)
   'title' title
   'feed-events' processed-feed-events))


;;; Functions for processing activity events.

(use floor)
(use xg_elapsed_time)

;;; Removes rolled-up feed events. This is a temporary measure until we
;;; implement handling of rollups.
(define (remove-rollup-feed-events feed-events)
        (filter (lambda (feed-event)
                  (not (array-get feed-event 'rollUpType')))

;;; Adds basic properties, such as humanReadableDate, to each of the feed events
(define (add-basic-properties feed-events options)
        (map (lambda (feed-event)
               (let* ([content-id (array-get feed-event 'event' 'properties' 'contentId')])
                 (arr feed-event
                      (hash (event-type feed-event) true
                            'humanReadableDate'     (human-readable-date feed-event)
                            'content'               (to-content-properties content-id (at options 'excerpt-length'))))))

;;; Returns the event type suffixed with "Type", e.g., createBlogPostLikeType.
(define (event-type feed-event)
        (. (array-get feed-event 'event' 'eventType') 'Type'))

;;; Returns a friendly date for the event.
(define (human-readable-date feed-event)
          ;; Prefix timestamp with @ so that strtotime will understand it
          (. '@' (floor (/ (array-get feed-event 'event' 'createdDate') 1000)))
          nil nil false))

Read more…