Saturday, December 30

Superman

Although it seems I am also (disturbingly) 72% Wonder Woman and 72% Supergirl...

Your results:
You are Superman

























Superman
90%
The Flash
75%
Wonder Woman
72%
Supergirl
72%
Green Lantern
70%
Robin
65%
Spider-Man
65%
Iron Man
65%
Catwoman
55%
Batman
50%
Hulk
40%
You are mild-mannered, good,
strong and you love to help others.


Take the Superhero Personality Test

Wednesday, December 20

Jiim

Oooh, they grow up so fast!

Branding the Captcha

I really dig Seth's idea for a centralized Captcha server everyone could use for free. His monetization suggestion of "Type the brand you see above, please" has lots of potential in its simplicity.
There could be conflict of interests, like being shown a NetSuite's ad whilst signing up for a Salesforce service.

Very juicy and thought-provoking, in typical Seth fashion.

Update: it didn't take too long to see this one implemented: cool, online demo here.

Tuesday, October 17

Joy



Video is also available on Transbuddha.

Thursday, September 14

Wednesday, September 6

Monday, September 4

Quotes Entirely Relevant to Software Engineers

Bodies are like diskettes with tags. You click on to them and you can see the size and type of file immediately. On people, this labeling occurs on the face.


by Douglas Coupland

Saturday, September 2

Tuesday, August 22

Step-by-step guide to TestNG

TestNG is a flexible testing framework developed by Cédric Beust and Alexandru Popescu. It is a much more powerful alternative to JUnit that fixes and improves many of its shortcomings.

In this introductory guide I will show how to setup and integrate TestNG with IDEA, hoping to highlight specific gems of TestNG in the process.

TestNG at a Glance

Here's a short list of my favorite features:

  • Ability to run existing JUnit test without any problem, providing a smooth transition path from JUnit to TestNG;
  • Ability to specify individual method thread pools;
  • Ability to specify certain test methods as dependent on the successful completion of others;
  • Separation of Java code from the way tests are run -run all tests, some tests, or only a few test methods of a given class. No need to recompile classes to run a different set of tests or suites;
  • Seamless integration with IDEA and Eclipse;

IDEA Setup

  • Download the latest TestNG library from http://testng.org/doc/download.html. My examples here are based on version 5.0.
  • Unzip the contents of the archive onto a directory of your choice.
  • Launch IDEA and create a new project of Java Module Type. I created one labeled testng.
  • Go to File->Settings, or press CTRL+Alt+S, to launch the IDE Settings panel.
  • From within the IDE Settings panel select the Plugins tab on the left hand side panel.

Figure 1 - Download and install the TestNG plug-in for IDEA [click on image to enlarge]

  • Download and install the TestNG-J plug-in from the right hand side panel. This will integrate the library with IDEA. You may need to restart the IDE for the changes to take effect.
  • Right-click on the newly created project and choose Module Settings.

Figure 2 - Module Settings of project [click on image to enlarge]

  • On the Module Settings panel, pick the Libraries (Classpath) tab, and then choose Add Jar/Directory to add the TestNG's jar to your project's classpath. I'm using JDK5.0, so I chose the testng-5.0-jdk15.jar archive.

Figure 3 - Add TestNG jar to project's classpath [click on image to enlarge]

This completes the integration of the testing library with IDEA, and we are now ready to write and test some code.


Exploring the Next Generation of Testing

Simply put, a TestNG unit test class is a POJO with annotated methods. There is no requirement to extend a specific class or implement a specific interface, just tag methods with Java annotations. A very simple Test class looks like this:

package testng.basic;

import org.testng.annotations.Test;

public class FirstTest {
public FirstTest() {
}
@Test
public void isOneEqualsTwo(){
assert(1 == 2);
}
}

I wrote a simple Java class and will use it to illustrate some key features of TestNG, namely the ability to specify individual method thread pools, the ability to specify certain test methods as dependent on the successful completion of others, and the seamless integration with IDEA.

Create a new class named ThreadUnsafe on IDEA and copy and paste the code below:


import org.testng.annotations.Test;
public class ThreadUnsafe {
private static int[] accounts = new int[] {0, 0};
private static int MAX = 1000;

@Test(threadPoolSize = 1000, invocationCount = 1000, timeOut = 2000)
public void swap(){
int amount = (int) (MAX * Math.random());
accounts[1] += amount;
accounts[0] -= amount;
System.out.println("Account[0]: " + accounts[0]);
System.out.println("Account[1]: " + accounts[1]);
int balance = checkBalance();
assert(balance == 0);
}
public int checkBalance(){
int sum = 0;
for (int i = 0; i < accounts.length; i++){
sum += accounts[i];
}
System.out.println("Balance : " + sum);
return sum;
}
public static void main(String[] args){
ThreadUnsafe tu = new ThreadUnsafe();
tu.swap();
}
}


ThreadUnsafe
is a very simple class that swaps random values from one account to another, ensuring the balance remains zero. That is, when we add an amount to one of the accounts, we subtract the same amount from the other.

Compile and run the code. It should exit printing Balance : 0.

Specifying thread pools

The only different and interesting thing on the code above is the annotation @Test on method swap():
@Test(threadPoolSize = 1000, invocationCount = 1000, timeOut = 2000)

This annotation is saying "give me a pool of 1000 threads, invoke this 1000 times, and exit if an invocation takes longer than 2000 milliseconds to return".
If a method takes longer than the specified timeout, TestNG will interrupt the method and mark it as unsuccessful.

To debug this sample project select the TestNG tab from the Debug panel. From there we can specify the desired granularity of the test, which can range from the swap() method to the whole package. I chose to test the ThreadUnsafe class itself.

Figure 4 - Debug granularity of TestNG [click on image to enlarge]

The output of running the project in debug mode can be seen below (values will vary):

Figure 5 - TestNG output [click on image to enlarge]

On the output console shown above we can see that after a few successful runs the value of Balance is 0 as expected. However, later on some weird values start showing up. Thus, multiple threads interfered with each other and the test shows the code to be thread unsafe.

This brute force thread safety testing can be useful to confirm a bug report due to improper synchronization, though it can be tricky to come up with a representative number of threads and repetitions.

Specifying method dependencies

The ability to specify certain test methods as dependent on the successful completion of others is a very useful feature. Let's move the initialization into a method of its own. Note changes on the accounts variable declaration and init() method.


import org.testng.annotations.Test;

public class ThreadUnsafe {
private static int[] accounts;
private static int MAX = 1000;
@Test
public void init() {
accounts = new int[]{0, 0};
}
@Test(threadPoolSize = 1000, invocationCount = 1000, timeOut = 2000)
public void swap(){
int amount = (int) (MAX * Math.random());
accounts[1] += amount;
accounts[0] -= amount;
System.out.println("Account[0]: " + accounts[0]);
System.out.println("Account[1]: " + accounts[1]);
int balance = checkBalance();
assert(balance == 0);
}
public int checkBalance(){
int sum = 0;
for (int i = 0; i < accounts.length; i++){
sum += accounts[i];
}
System.out.println("Balance : " + sum);
return sum;
}
public static void main(String[] args){
ThreadUnsafe tu = new ThreadUnsafe();
tu.init();
tu.swap();
}
}

The difference from the previous code is that initialization is now done on the init() method, which is itself a @Test annotated method that will be included in the testing report.

Now running the code in Debug TestNG mode results in an error because the array accounts used by the swap() method has not been initialized.

Figure 6 - NullPointerException caused by non-initialized dependency [click on image to enlarge]


What we want here is the ability to tell that a certain test method, swap(), depends on the successful completion of a previous test method, init().
We want to guarantee that certain methods or groups of methods are always invoked before others.

TestNG let's us do that with the dependsOnMethods annotation.
To specify swap() as being dependent on the successful execution of init(), we use the dependsOnMethods annotation as shown below:


@Test(dependsOnMethods = {"init"}, threadPoolSize = 1000, invocationCount = 1000, timeOut = 2000)
public void swap() {
...
}

Running the code in debug TestNG mode now results in a successful execution:

Figure 7 - Method dependency with TestNG [click on image to enlarge]

For unreliable systems TestNG introduces the notion of partial failure:
@Test(timeOut = 10000, invocationCount = 1000, successPercentage = 98)
public void waitForAnswer() {
while (!success){
Thread.sleep(1000);
}
}

The example above instructs TestNG to invoke the method a thousand times, but to consider the overall test passed even if only 98% of them succeed.

All the above are simple yet very powerful examples that are either very hard or impossible to do with JUnit.

Resources

Thursday, August 17

Business need: Digg for Consumer Electronics

I'm on the prowl for new gadgets (smart-phone, wide-screen TV, games console), and I think a market like Digg for consumer electronics would help prune the search space.
With the number and combination of brands, specs, makers, designs, features, personal preferences and whatnot involved, such an application would tap into the wisdom of crowds and transform many diverse opinions into a single collective judgement.
This is the central thesis of the Wisdom of Crowds:

"With most things, the average is mediocrity. With decision making, it's often
excellence. We've been programmed to be collectively smart
".


I hope this is what Jay Adelson [Digg's current CEO] means when he says:
"The best I can tell you is Digg as a concept can be applied to other content aside from news. Just wait and see what we’re going to apply it to."


In fact, Amazon is also in a good place to experiment with crowdsorting their results pages (and when you're at it Amazon, please let us also do column sorting so that we don't need to navigate through pages of results that we don't care about to find what we want).


[Update]:
Product Clash's clash and compare feature almost nails it:
"Now you can clash and compare your best consumer products for low price offers.
Product Clash features cheap cameras, cheap cell phones, cheap computers, cool
gadgets, cheap home entertainment, cheap peripherals and portable media
comparison clashes! Clashing is fun for movies, music, games and DVDs."



Useful Links:
Venture Voice Show #37 - Jay Adelson of Digg
The Wisdom of Crowds
Independent Individuals and Wise Crowds
The Observer: Here's Hoping This Group-Think Effort Is Full Of Wisdom
http://en.wikipedia.org/wiki/Crowdsourcing

The road ahead for OpenOffice

I agree 100% with these arguments, being an active but often frustrated OO user for over 5 years.
Decoupling the document from the vendor suite (with the Open Document format) was a tremendous achievement, but the road ahead for OO does not look so promising:

  • Instead of redefining and redesigning an Office suite tailored to user needs it is developing into a pale, MS Office-wannabe sibling. It confuses the (real) user need of a better Office suite with that of an open alternative to MS Office.
  • It has most of the same flaws of (older) MS Office with less of its (newer) functionality. The trade off is to its disadvantage, since it's now playing to catch-up with competition that is evolving.
  • It is still very buggy in critical areas such as the spell-checker and word count, which were also introduced late as proper features.
  • It is not modular, forcing one huge download and installation of the whole suite. I'd like to, in true open market fashion, be able to choose and use the best components from each suite.
  • It has a very slow and clumsy release cycle. The early 2.0 beta was an embarrassment.
  • It doesn't clean-up properly after an uninstall. There are no excuses for this.
  • It lacks a much needed auto-update feature. For the average computer user, upgrading a release is a pain.
  • Last but not least, it lacks truthful, constructive, and objective criticism -criticism is often regarded as a nod towards Microsoft. Most users and adopters of OO tend to be people that are somewhat partial in their reviews. The views within some parts of the open-source community mix blind, anti-corporate bashing with the open source ideal.
I tend to regard the less-than-100% compatibility issue as an overall successful struggle to reverse-engineer a proprietary document format.

As it stands, OO is an alternative to MS Office, which is a good thing to have. In fact, it is the alternative to MS Office.
But mostly for monetary or ideologic reasons, not based on the quality of the offering.

Friday, July 21

5 Useful Python Tips

Here are a few useful Python tips I’ve learned over time.


1. When using the '%' format operator always put a tuple or a dictionary on the right hand side.


Instead of:
  print "output %s" % stuff


Write:
  print "output %s" % (stuff,)


With the tuple on the right hand side, if stuff is itself a tuple with more than one element we'll still get its representation instead of an error.


Example:
  >>> def output(arg):
            print "output %s" % arg

  >>> output("one item")
  output one item

  >>> output(('single tuple',))
  output single tuple

  >>> output(('tuple','multiple','items'))

  Traceback (most recent call last):
  File "", line 1, in -toplevel-
  output(('tuple','multiple','items'))
  File "", line 2, in output
  print "output %s" % arg
  TypeError: not all arguments converted during string formatting


Now, if the function output is changed to:
  >>> def output(arg):
            print "output %s" % (arg,)

  >>> output(('tuple','multiple','items'))
  output ('tuple', 'multiple', 'items')


It will always work as intended and expected.


2. Use the built-in timer function proactively and aggressively to avoid "premature pessimization".


Python has a very useful built-in timing framework, the timeit module, which can be used interactively to time the execution of short pieces of code.
Suppose we want to find out if a hypothetical word_count implementation is faster using the split() method or using a loop.
We'd like to implement each variant, call each implementation many times, repeat the entire test a few times, and select the one that took the least time.

Timeit.py to the rescue. Let's test the implementation using split() first.

  >>> import timeit
  >>> def word_count():
            s = "long string with several words to be counted "
            return len(s.split())

  >>> word_count()
  8

  >>> t = timeit.Timer(setup ='from __main__ import word_count', stmt='word_count()')

  >>> t.repeat(3, 1000000)
  [4.6016188913206406, 4.5184541602204717, 4.5227482723247476]


And now let's test a loop variant.
  >>> def word_count():
            s = "long string with several words to be counted "
            return len([c for c in s if c.isspace()])

  >>> word_count()
  8

  >>> t = timeit.Timer(setup ='from __main__ import word_count', stmt='word_count()')

  >>> t.repeat(3, 1000000)
  [17.766925246011169, 17.784756763845962, 17.890987803859275]


We have our informed answer right there and then.


The first argument of repeat() is the number of times to repeat the entire test, and the second argument is the number of times to execute the timed statement per test.


You can even select the best out of X runs (3 on this example) by using the min function
  >>> min(t.repeat(3, 1000000))
  17.766925246011169


We can try and compare other implementations such as a loop without the (expensive) call to isspace().

  >>> def word_count():
            s = "long string with several words to be counted "
            return len([c for c in s if c == ' '])

  >>> word_count()
  8

  >>> t = timeit.Timer(setup ='from __main__ import word_count', stmt='word_count()')

  >>> t.repeat(3, 1000000)
  [8.8144601897920438, 8.7707542444240971, 8.7721205513323639]


Which proves faster than our second implementation but still slower than calling split().


Note:
Instead of repeat() we can call timeit(), which calls the function 1 million times and returns the number of seconds it took to do it.


3. Don't traverse to append, extend instead.


Don't do:
  >>> def bad_append():
            l1 = ["long","string","with","long"]
            l2 = ["elements","and","words","to","be","counted","or","words"]
            for item in l2:
                  l1.append(item)

  >>> t = timeit.Timer(setup ='from __main__ import bad_append', stmt='bad_append()')

  >>> min(t.repeat(3, 1000000))
  5.4943255206744652


Do instead:
  >>> def good_append():
            l1 = ["long","string","with","long"]
            l2 = ["elements","and","words","to","be","counted","or","words"]
              l1.extend(l2)

  >>> t = timeit.Timer(setup ='from __main__ import good_append', stmt='good_append()')

  >>> min(t.repeat(3, 1000000))
  2.3049167103836226


Calling extend() results in an almost 60% performance gain.


4. Beware of doing string concatenation using '+'.


Let's see why with "no fluff just stuff" by applying golden rule 2 above.
Bad:
  >>> def bad_concat():
            s = ""
            l = ["items", "to", "append"]
            for sub in l:
                  s += sub

  >>> t = timeit.Timer(setup ='from __main__ import bad_concat', stmt='bad_concat()')

  >>> min(t.repeat(3, 1000000))
  1.6777893348917132


Better:
  >>> def good_concat():
            s = ""
            l = ["items", "to","append"]
            s = "".join(l)

  >>> t = timeit.Timer(setup ='from __main__ import good_concat', stmt='good_concat()')

  >>> min(t.repeat(3, 1000000))
  1.3923049870645627


Needless to say all this adds up if these operations are done repeatedly and with bigger lists.


Also avoid:
  out = "output: " + output + ", message: " + message + ", param: " + param


Instead, use:
  out = "output: %s, message: %s, param: %s" % (output, message ,param, )


Which neatly combines rules 1 and 4.


5. Environment settings and variables are available cross-platform.


This is a very handy feature. Take a close look at os.path.expanduser() and os.environ on Linux and Windows.


*Nix:
  >>> import os
  >>> os.path.join(os.path.expanduser('~'))
  '/home/jcastro/'


Windows:
  >>> import os
  >>> os.path.join(os.path.expanduser('~'))
  'C:'


Useful Online Resources

The Python Coding Conventions
Python Performance Tips
Patterns in Python
Data Structures and Algorithms with Object-Oriented Design Patterns in Python
The Python Tutor Mailing List
My Python links on del.icio.us

Saturday, July 15

Happy Feet

Shown tonight, during the opening of Superman Returns



More here.

Thursday, July 13

RIP Syd



Thank you for the wonderful legacy.

Sunday, June 18

What's in a Name?

I had a Malay housemate called Kamarun Kamarundil (he would, when introduced, always give the shorter version Nick).
I have a Thai friend called Kamontip Sapphawaht.
I absolutely love their names, and can already see the trailer for a Hollywood romantic blockbuster titled When Kamarun Kamarundil met Kamontip Sapphawaht...

Monday, June 12

John Long Prize

On a letter dated November 2005 that I only had access to yesterday, I found out that my thesis was awarded the "John Long Prize for best research thesis"!

Thank you very much to all those mentioned in my acknowledgments section (and maybe a few others who were sadly forgotten)
If there is any cash involved a promise will be made right here and now to spend (some of) it well and wisely on a nice open BBQ with free drinks for all!
(sadly, no cash prize = no free BBQ+drinks for all)

Now ain't I a happy, lucky chap...

Monday, May 1

Out of (the) Box

Things I am missing from Box.net:

  1. Drag-and-drop files onto newly created folders. Currently we can change a file's location through its contextual drop-down menu)
  2. Share folders by drag-and-drop. Currently we have to share files by ticking each checkbox individually.
  3. Email notifications when friends access/download shared files. Otherwise, we have to poll them to acknowledge receipt.
So no, I don't think Box gets it yet.

Amazon suggests

http://www.mybigriver.com/

Thursday, April 6

Sand art



And there's more here.

Wednesday, April 5

My Personal DNA

My Personal Dna Report [hover on the image for details]


Get yours here.

2005 In Retrospect: Blogs

There is a group of blogs that I check once daily, labelled "important" on my Bloglines blogroll. When new blogs are promoted to this "elite" group other blogs are demoted to the "Quarentine" one. (helpful taxonomy inspired by this, this, and David Allen's Getting Things Done)

Below are 5 blogs of "elite quality" that I'm really enjoying reading.

All Kinds Of Stuff
John Kricfalusi is no other than the creator of the Ren and Stimpy tv series. With these credentials he didn't need much more to convince me, but you know what, his blog is very refreshing and inundated with precious teachings.

Let The Good Times Roll
Here's how to suck up to a blogger: when I grow up I'd love to be as charismatic, inspirational, charming, and overflowing with wisdom as Guy Kawasaki.

AVC
Fred talks from the Venture Capital world in ways that I can understand.

Enplaned
This is how the blogosphere works: Up until Joel mentioned them, I never thought I'd be interested in reading about the aviation industry. Now I can't stop.

Epsilon-Delta: Mathematics and Computer Programming
Yes, I like mathematics and I yes, maybe I can't stay too far away from computer programming. But I'll be damned if Ted Dziuba isn't a talented writer, able to make these two "scary-for-most-people" subjects attractive.


Runners up: The Dilbert Blog, Funny Cute, Post Secret, Tom Peter's Weblog, Niniane's blog


Related posts:
2005 In Retrospect: Technology
2005 In Retrospect: Music

"Loans that change lives"

I have been following Dav Yaginuma's blog, AkuAku, for a few years now. It is undeniable that he is a proper hacker and coder extraordinaire. To me, he also comes across as an inspirational, passionate, creative, dedicated, and humane individual. In this post, he introduced me to Kiva, a site where people can loan money to small business in developing countries. I like the empowering idea of a loan free of middle man, so I too have opened an account and donated.


Cheers Dav.

Tuesday, April 4

Let the good times roll - part II

Despite its evident flaws (and the fact that my feminine side is highly exacerbated by their algorithm), I really like MyHeritage.
I uploaded Sunday's pictures to find out a bit more about my friends. It turns out they have a lot to explain...

Deanna's real name is Maggie Cheung, Jia and Zhang Ziyi have never been seen together in the same place (raising suspicions they're one and the same), Peter is a Nicolas Cage clone, and Rachel and Alyson Hannigan are twins separated at birth. [Click on the images to enlarge]


Jang Nara is no one but Rachel in disguise, Willo's part-time-job-we-were-never-allowed-to-know-about is modelling as Song Hye-Kyo, and my good friend Bo goes undercover as the philosopher John Dewey.

Sadly, the system didn't pick up my face :(

Let the good times roll

Dinner at my place: not enough plates, wine glasses, chairs, and cutlery (!), but still good fun. Great to see everybody and catch up with what they're doing.

Left to right: Rachel, Willo, Bo, and myself.

Left to right: Deanna, Jia, Peter, and Rachel

Friday, March 24

Thursday, March 23

David Allen vs Tom Peters

It seems David Allen

Even as late as the 1980s many professionals considered having a pocket Day-Timer the essence of being organized, and many people today think of their calendar as the central tool for being in control.
...
What you've probably discovered, at least at some level, is that a calendar, though important, can really effectively manage only a small portion of what you need to organize.
...
The real issue is how we manage actions.
[from Getting Things Done]

fundamentally disagrees with Tom Peters
You = Your calendar.
THIS IS MY #1 BELIEF ABOUT MANAGEMENT

(also: am I the only one to think they actually kind of look alike?)

Wednesday, March 22

Poor usability 2: Google Video


I find this one quite evil. If the chosen video "is not playable in my country", it shouldn't have been made available to me in the first place. Out of sight out of mind, right?
About Face 2.0 has something to say too:

Considerate software uses common sense


This one is a fundamental problem with navigation implementations using HTML frames. As you progress on the list and select an item after scrolling down, the scrollbar returns to the beginning of the list every time a refresh occurs. Thus, we're constantly scrolling up and down the list to go through all items. My favorite web aggregator, Bloglines, suffers from the same (quite annoying) problem.
Of course, there is an About Face 2.0 quote applicable:

Considerate software is perceptive
Software should watch our preferences and remember them without being explicitly asked to do so. If we always maximize an application to use the entire screen, the application should get the idea after a few sessions and always launch in that configuration. The same goes for placement of palettes, default tools, frequently used templates, and other useful settings.

Poor usability: Adobe


About Face 2.0 to the rescue:
Considerate software is self-confident
Are you sure? Are you really sure? Are you really, really sure?

And
Considerate software doesn't burden you with its personal problems
Software whines at us with error messages, interrupts us with confirmation dialog boxes, and brags to us with unnecessary notifications. We aren't interested in the program's crisis of confidence about whether or not to purge its recycle bin. We don't want to hear its whining about not being sure where to put a file on disk. We don't need to see information about the computer's data transfer rates and its loading sequence, any more than we need information about the customer service agent's unhappy love affair.

Well, I certainly won't like to reboot -not now, not later. Since I'm updating your software, all I need to know is: do I have to reboot to successfully update? Nothing more, nothing less.


Perhaps this is just me being anal but I find the label 'Quit' on the button rather annoying. The installation is complete, so what exactly am I quitting?
The only operation left seems to be close the window. Why not simply say that?

Tuesday, March 21

StringTokenizer

Note to self:
StringTokenizer is deprecated. Should use the split() method of the String class instead. Split() is faster and returns an array of tokens ready to be used.

Monday, March 13

My 2 cents

I know, The Daily WTF does a great job at doing this, but I really liked these error messages I was presented with recently.
Writely showed me this very funny pop-up dialog box:



Windows Movie Maker annoyed me with this one:

I'll make mine the words of Alan Cooper on About Face 2.0:

Considerate software is conscientious
If we rely on a word processor to draft a new MicroBlitz Contract and then try to [save it in the same folder as an existing, but older, MicroBlitz Contract], the program offers the choice of either overwriting and destroying the old contract or not saving it at all. The program not only isn't as capable as [a human assistant who saw
the name conflict and appropriately renamed the contracts], it isn't even as capable as [a human assistant who put the two contracts in the same folder]. It is stupider than a complete idiot. The software is dumb enough to make an assumption that because they have the same name, I meant to throw the old one away.


And my own 2 cents on WMM's error message:

  1. If there is such a thing as an invalid filename, tell me before hand what my valid options are. Don't wait until I use "invalid" options to let me know I've used them, right? It is worth mentioning that even after the input validation I was not told what those invalid names were. This inconsiderate application seems to want me to keep trying until I get it right.

  2. What happened to the option to overwrite an existing file, asking for my consent? That was actually what I wanted to do but was forced instead to save the file with a bogus name, delete previous one manually, and then rename bogus-named one with the intended name. There seems to be total lack of attention to detail and lazy programming here.

Friday, March 10

Wednesday, March 1

Still got it...

You Passed 8th Grade Math

Congratulations, you got 10/10 correct!

Thursday, February 23

Wednesday, February 22

2005 In Retrospect: Technology

These are the top 5 'technologies' that impressed me and/or saved my butt last year:

  • Scriptaculous, Rico, AjaxTags - AJAX made easy (the latest version of AjaxTags uses Scriptaculous).
  • Python - always reminding me why I chose computer science in the first place.
  • Ruby On Rails - very promising. I've only gone through their 15 minutes demo and wrote 1-2 small prototypes for myself, but I am impressed.
  • Spring rules. 2005 was 'The year of AOP' for me, and Spring made it a wonderful, productive experience.
  • iBatis - I've spent so much time with Hibernate doing things behind the curtains for me that I forgot how nice it is to manage SQL by myself at times.
Related post: 2005 In Retrospect: Music

Tuesday, February 21

Tomcat HTTP/1.1 GZip compression

I found out about Tomcat 5's built-in HTTP/1.1 GZip compression on this comment. This feature is off by default.
Having this feature off by default causes confusion and encourages people to reinvent the wheel, multiple times, with different flavors.
Bless.

Saturday, February 18

Celebrity match

The face recognition algorithm of MyHeritage matches this photo of mine (age 6?) with these celebrities [click on photo to enlarge]:


Yes, some are a bit disturbing, like John Woo?? Try yours at MyHeritage

Fearless: the music video is a great trailer

Thursday, February 16

"Found is the new search"


Cool (and not so cool) things about mag.nolia:

  • Great domain name.
  • Superb tag line (the title of this post).
  • Saved Copies of Web Pages - I've bookmarked many pages that now return 404's. This feature alone might be worth a business model.
  • Private bookmarks - Though why would a community oriented service encourage private stuff?
  • Bookmark rating system - We all love our lists, right?
  • Terrific design and they're rightfully proud of it.
  • Network with some well-known names - Ted Allen is there, Zeldman is there too.
They certainly did their homework and thought things through. However, as attractive as their service seems to be, I find no compelling reasons to move away from del.icio.us (and even less motivation to use two bookmarking services).
Really hope there is room for two in their segment.

[Update]: There is a great writeup here on their design/development process.

Tuesday, February 14

Adopt a comedian (the AAC needs you!)

ZeFrank has done it again. The 1/4 mile longcar bit kills me...

Monday, February 6

Python for experts - Shipping part 1

The last one of my previous series of posts on Python addresses the issue of shipping Python applications.
Simply put, if I ask people to help my research by using an application that I developed, I do not want to force them to:

  • read large manuals
  • unzip and fiddle with my 'distributed zipped folder' with executables, DLLs, and other helper files
  • install/uninstall stuff on their machine
  • waste their time
Ideally, I want to give them a small(ish), standalone file they can download, double-click to run, and delete when they're done.
On Windows, I could only find two tools that claim to accomplish that:

py2exe
PyInstaller

Both have options to deliver either a distribution folder or a standalone file executable. I was only interested on the latter option.

py2exe seems to have problems with applications using Tkinter for the GUI. For my server module, which does not have a GUI, the setup file below did the job.


# setup.py
from distutils.core import setup
import py2exe

setup(data_files=[("abbreviations.txt")],
   name = "Jiim Server",
   description = "Cross-Linguist Server Prototype.",
   version = "1.1",
   author='Jorge De Castro',
   author_email='jorge at bcs dot org dot uk',
   zipfile=None,
   console= [{"script": "server.py"}]
)


This yielded a server.exe standalone file with 4.5Mb.

PyInstaller hit the spot. It is simple to use (simpler than py2exe) and their documentation is very good. Furthermore, after I installed UPX as instructed on their homepage, the executable created was compressed to less than half(!) the size (1.85Mb) of the one created with py2exe. The command line options I used are shown below:

> python Makespec.py --onefile --name=server C:\Workplace\python\jiim\server.py
> python Build.py server\server.spec


It seems possible to have py2exe do the same (or most) things PyInstaller does, but the latter is much nicer and easier to use. Plus, it just works as expected.
Be prepared to struggle with py2exe's (lack of) documentation if you want slightly more complex setups.

Friday, February 3

My Reusable Advice - part 1

Logging and tracing are separate concerns of an application (except for applications where this is an explicitly specified requirement). Thus, I was becoming increasingly annoyed with the


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
...



and corresponding logging calls all over core modules, business classes, and even POJOs that required occasional debugging.

Furthermore, any changes to logging policies/strategies required multiple changes across multiple classes and a rebuild.

AOP is the technology for separating crosscutting concerns into single units called aspects. An aspect is a modular unit of crosscutting implementation that encapsulates behaviors that affect multiple classes into reusable modules.
AOP is thus the best way to log & trace entry & exit methods on demand. My earlier reluctance was due to the slightly harder way to debug control flow, as exemplified below:


...
if (condition){
log("Doing X")
do X
}else{
log("Doing Y")
do Y
}
...


The scenario above is still possible but not so straight forward to do with AOP. But really, the gains outshone the limitations. Consider the advice below, using the SpringFramework:


import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MethodExecutionTimeInterceptor implements MethodInterceptor {
private final Log logger = LogFactory.getLog(getClass());
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
logger.info("intercepted method '" + methodInvocation.getMethod().getDeclaringClass() + "::" + methodInvocation.getMethod().getName() + "'");
long startTime = System.currentTimeMillis();
try {
Object retVal = methodInvocation.proceed();
return retVal;
} finally {
logger.info("method duration '" + (System.currentTimeMillis() - startTime) + "' msecs");
logger.info("resuming method '" + methodInvocation.getMethod().getDeclaringClass() + "::" + methodInvocation.getMethod().getName() + "'");
}
}
}


I can apply the logging unit above to any subset of classes in my application, or indeed to the whole application. The advice will automatically run whenever its pointcut matches a join point in my running program. Should logging requirements change or become redundant, I can remove the aspect without touching application code. The original code does not know of the logging aspect being applied to it.
This single aspect contributes to the implementation of a number of methods, modules, or objects, increasing both reusability and maintainability of the code.

For future reference, IBM DeveloperWorks as an extensive array of very useful articles on AOP.

A full logging example can be found here, many AOP resources can be found here, and a good introduction to AOP can be found here.

Thursday, February 2

2005 In Retrospect: Music

Here are the top 5 albums that were on heavy rotation on my iPod:

  1. Antony and the Johnsons, I'm a bird now - I first heard Antony & the Johnsons in 1999 (if my memory serves me well), when they opened for Current 93 at Sadler's Wells (I think). It was, together with David Byrne's "Monster in a Mirror Tour", one of the best and most intense live acts I have ever seen. Been a faithful fan ever since, and will never forget them.
  2. Bloc Party, Bloc Party - These Essex boys really rock! Keke, their frontman, has a quite a voice . Their sound has the rock'n'roll attitude of a Doolitle (I know, this is a bold statement!), the freshness of an early Blur, and can sometimes (Banquet) remind me of The Cure. "Like drinking poison, like eating glass" oh yeah!
  3. Coldplay, X & Y - Darnit. I admit I wasn't expecting much from this release but they certainly delivered. I give it up, Coldplay deserve to be right up there with the U2s and Radioheads: they simply have the talent.
  4. Royksopp, The Understanding - what a masterpiece, I love it! Karin Dreijer's voice in What else is there is unavoidably seductive!
  5. Zhou Hui - Something I brought from my trip to China in 2001. Just recovered my CD that was scratched due to overuse. She has got to have the most beautiful voice and sings like an angel. Can't even find an (non-Chinese) Internet link, that is how precious she is!

Runners up: dEUS - Pocket Revolution, Frank Black - Honeycomb, Gorillaz - Demon Days, Kings Of Leon - Aha Shake Heartbreak, Keane - Hopes and Fears, Sigur Ros - Takk

Wednesday, February 1

More WYSIWYG

In a previous post I referenced a few user-friendly, WYSIWYG editors for the Web. The good people at http://www.geniisoft.com compiled an extensive list with (all?) open-source and commercial WYSIWYG products in the market.
Nice one, thanks.

Sunday, January 29

PS3

Phew. I'm not a big war games fan but this trailer for Killzone blew me away!

Must-have developer tools

Venkman Javascript Debugger - Yes, farewell 'alert' messages!

Javascript Minifier - JavaScript compression for faster loading.

Javascript Verifier - Lookout for potential problems in the code (syntax, unused variables, ...).

IE Developer Toolbar - For IE development. Not as refined as the Firefox Developer Extension but better than nothing.

Monday, January 23

Applications for 2006

Following this earlier post, I'm now looking for software 'gems' that I may have missed in 2005. I've already found a few candidates, courtesy of the good people at Sitepoint, that I will use and test in the next few months. Who knows, maybe they will make my list at the end of 2006.
And the candidates are:

MWSnap, though not sure if I'll replace Cropper anytime soon
TopStyle
CCleaner
Fiddler, an HTTP traffic inspector
SnagIt, hmmmm maybe I'll replace Cropper after all...
MezerTools

To be updated as I find more of them gems.

Sunday, January 22

Public Domain Name Servers

This comes in handy if the SMTP server isn't an open relay, or when traveling and accessing the Web via different ISPs.
Just configure the SMTP server (
Free SMTP is free) with the DNS field set to one of the IP addresses below.

Public (Level3) Name servers (these are OC192's)
4.2.2.1
4.2.2.2 (fast)
4.2.2.3
4.2.2.4
4.2.2.5
4.2.2.6 (fast)

Open to the Public
# ns1.la.us.opennic.glue (New Orleans, LA, US) - 68.15.165.12
# ns1.phx.us.opennic.glue (Phoenix, AZ, US) - 63.226.12.96
# ns1.sfo.us.opennic.glue (San Francisco, CA, US) - 64.151.103.120 (fast)
# ns1.co.us.opennic.glue (Longmont, CO, US) - 216.87.84.209

SpeakEasy Name servers
66.93.87.2
216.231.41.2
216.254.95.2
64.81.45.2
64.81.111.2
64.81.127.2
64.81.79.2
64.81.159.2
66.92.64.2
66.92.224.2
66.92.159.2
64.81.79.2
64.81.159.2
64.81.127.2
64.81.45.2
216.27.175.2
66.92.159.2
66.93.87.2

Sprintlink General DNS
204.117.214.10
199.2.252.10
204.97.212.10

Cisco
128.107.241.185
192.135.250.69

Useful Web2.0

http://instantdomainsearch.com/, as the name indicates, tells you instantly (as you type) whether the domain name is available or not.
Nice.

iPod ressurection

Here's a bunch of cool ideas for when my iPod runs its course.

Friday, January 20

Peugeot Ad

One of my favorite ads (together with these classics from Honda)


Fighting spam

Duke University has a Web email address 'obfuscator' available to the public. Maybe it is already too late but I'm still committed to reduce the huge amount of spam I get daily.

Icons for free

Flags: http://www.kidlink.org/icons/flagdir.html

All sorts of useful icons: http://www.famfamfam.com/lab/icons/

Tuesday, January 10

The Vincent Rooms

Fancy a different night out, with dinner cooked and served by future chefs spoiling you with attention?

The Vincent Rooms
Vincent Square
SW1P 2PD
02078028391

Thanks Kamila ;)

Sunday, January 8

"I always wanted to be somebody.

... I should have been more specific."

From David Allen's Getting Things Done, attributed to someone named 'Lily'

Saturday, January 7

Note to self

Download paper:
X Zhang, VR Prybutok, 2005, How the mobile communication markets differ in China, the U.S., and Europe. Communications of the ACM, ACM Press New York, NY, USA

Export/download link

Want to keep the browser from displaying data you want the user to download? Try the code snapshot below on the controller:



String filename = ..............
byte[] content = ...............
String mimetype = this.getServletContext().getMimeType(filename);
response.setContentType(mimetype);
response.setContentLength(content.length);
response.setHeader("Content-Disposition","attachment; filename=\"" + filename +"\"");
FileCopyUtils.copy(content , response.getOutputStream());


The Content-Disposition header will force the browser to download the content as an attachment rather than display it on the browser.


STOMP is electrifying!

Go free, entrapped, primeval, tribal soul of my urban-self, go free! There are sounds and instruments in nature waiting to be played and listened to.
Very energetic, very creative, very funny.
My favorite bits? The broom piece, the rubber tubes section, the lighters bit, and the sinks masterpiece.

Tuesday, January 3

Blogs as bad PR

I wonder what is the impact of an entry like this from a widely read and influential blogger on future sales of Dell?
Are people listening?
Is Dell listening?

Monday, January 2

Online repositories

Whenever I need to send large files to people or groups of people I use http://www.yousendit.com/. It is simple, intuitive, and works well. The only caveat is that files are only available to download from their servers for 1 week.
Now, thanks to the cool people at http://www.workhappy.net/, I have been given choice:

I will soon be checking which one is better.

[Update]:
http://www.dropload.com/ has a 100MB size limit and 7 days time limit. Guess I won't be using this one fo'sho.
[Update 2]: http://www.dropsend.com/ will definitely have a closer look, since their founder's blog is one of my top reads.