Tuesday, December 27

Applications in 2005

Way back in 2005, these were the resident applications I had on my Asus W1 laptop:

uTorrent, small bit torrent client
Cropper, screen capture tool
Apache 2.0.5
Tomcat 5.5.12
PowerArchiver, data (de)compressor
GreatNews, RSS aggregator
RSSBandit, RSS aggregator
WinSCP, secure FTP client
WinCVS 2.0.2-4
VobSub 2.23, subtitles to movies
ArtRage 1.0, simply beautiful, even though I don't use it often
Handy Recover, recover damaged drives
CDex 1.51, convert .WAVs into .MP3s (or any other target format)
ColorPic, grab
color information from anything on the screen
DivX
Putty, Telnet/SSH client
StickIt, reminder notes floating on the desktop
Eclipse IDE
JBuilder 9 Enterprise

I did not have a similar list for 2004 but I can easily trace what changed now.
I replaced obese and clumsy Azureus with tiny and elegant uTorrent (I'm not alone in thinking uTorrent rules!); chubby and messy SmartFTP had its place taken by slim and tidy WinSCP; kept a previous version of ColorPic, since the newest one fell pray to the setup trap.
The trend was to replace setup installations with equivalent
executables.

But why
executables? Aren't executables soooo (pre) Windows 95?
The reason is setup programs are larger, bloated, cumbersome (when not impossible) to completely remove from the system, and much harder to revert after an update.

When there is a new version of an executable, I double-click on it and try it for a few days. If I like it, I keep it and delete the previous version; if I don't I simply delete it and that's it. No add remove programs panel, no search and delete registry entries, no disk cleanup.

For a setup program I have to uninstall the previous version or watch the newer version do that for me. Uninstall operations, even when successful, do not yield tidy and neat systems: surprisingly, (system+program A) - program A != system. If I preferred the previous version I'm left with a hard to follow and hard to get rid of registry and application data debris.
The SmartFTP uninstall left a few folders with 5+ Megs of data hanging about in my system; Azureus left trails of application data and whatnot; MySQL and its tools, left wrong, obsolete, and hard to remove entries on the Add and Remove Programs panel.
One otherwise awesome tool, Inspiration, sent me to hell and back to fully remove it from my system after their trial period was over. Yes, of course I did not buy it in the end.

And I think I had enough.
Now, every time I'm given an executable alternative with the same functionality and at least the same quality I will replace without blinking.

Prediction: in 2006,
Eclipse will forever replace JBuilder.

Monday, December 26

Too Darn Cute!

Do not miss this, not now, not never!

http://mfrost.typepad.com/cute_overload/

Happy Holidays!

Koma

My good friend (and C++ guru) Eurico won a prize with this one:

http://www.tecn.upf.es/master/mcv03/~eandrade/

Awesome!

Sunday, December 25

...And torrents for all

This site, http://www.publicdomaintorrents.com/, has classic movies and B-movies that became part of the public domain available for download. Some available titles:

Metropolis
Plan 9 From Outer Space (Oh God...)
The Little Shop of Horrors
Buster Keaton
Night of the Living Dead (I died laughing when I first saw this one)
Flash Gordon
Monster from a Prehistoric Planet
The Memphis Belle
Kong Island
Nosferatu


Maybe a similar repository can be created for old TV series and computer games.

Tired of talking to machines?

The bottom line is this:

companies just aren't getting it

Wednesday, December 21

A Taste of a Moscow Tube Station

Tube Map variations (great stuff!)

http://ni.chol.as/media/sillytube.html

Moscow Tube


I'm completely hooked up on this thread on Edward Tufte's blog -one of my favorite daily reads. It is satiating my long time fascination with underground systems and their corresponding maps, and it is full of many other goodies such as this (subway systems of the world presented on the same scale), and this (Tube Map Archives).
Great stuff, really great stuff!

LondonTown Tube - The Real Thing




(click on each image to enlarge)

Simply beautiful, huh?

Saturday, December 3

Prototype guide

Here is a concise, very informative, and easier to follow than Sergio Pereira's comprehensive reference:

http://particletree.com/features/quick-guide-to-prototype/

[Update]: and here is another one:

http://blogs.ebusiness-apps.com/jordan/pages/Prototype%20Library%20Info.htm

Right drive

For many years I've listened in silence my friends in 'the continent' critically refer to left hand side driving as yet another "yeah we're different just get on with it" attitude from the Brits.
There are many articles online proving it, and the bottom line is this: left hand side driving is how it all got started!
The arguments given here are pretty convincing:

In the past, almost everybody traveled on the left side of the road because that was the most sensible option for feudal, violent societies. Since most people are right-handed, swordsmen preferred to keep to the left in order to have their right arm nearer to an opponent and their scabbard further from him. Moreover, it reduced the chance of the scabbard (worn on the left) hitting other people.

Furthermore, a right-handed person finds it easier to mount a horse from the left side of the horse, and it would be very difficult to do otherwise if wearing a sword (which would be worn on the left). It is safer to mount and dismount towards the side of the road, rather than in the middle of traffic, so if one mounts on the left, then the horse should be ridden on the left side of the road.

The change to right hand side driving is also explained:

In the late 1700s, however, teamsters in France and the United States began hauling farm products in big wagons pulled by several pairs of horses. These wagons had no driver's seat; instead the driver sat on the left rear horse, so he could keep his right arm free to lash the team. Since he was sitting on the left, he naturally wanted everybody to pass on the left so he could look down and make sure he kept clear of the oncoming wagon's wheels. Therefore he kept to the right side of the road.

In addition, the French Revolution of 1789 gave a huge impetus to right-hand travel in Europe. The fact is, before the Revolution, the aristocracy traveled on the left of the road, forcing the peasantry over to the right, but after the storming of the Bastille and the subsequent events, aristocrats preferred to keep a low profile and joined the peasants on the right.

It was surprising to find out that in
Portugal, from where I hear the harshest accusations ;), people drove on the left until 1928 (!) Sweden only changed in 1967.

Tom Waits says it best: I'm so thankful for these friends I do receive". But maybe, just maybe, the 'Brits' have it right this time.

Sunday, November 27

Ideograms

For my research at UCL, I ran IM log analysis focusing on the English and Chinese languages. The statistical analysis assumed each individual Mandarin character/pictogram as 1 individual character, in order to compare them with their English equivalent.
This disturbed me then and disturbs me still,
because each Mandarin ideograph can in fact contain more than one pictogram.
Hence, how accurate and precise are results obtained this way, since there is no one-to-one mapping between all Mandarin characters and English words?
Perhaps I need to check each set of ideograms before matching them to an English word.

Monday, November 21

Disable form submission via Enter key

Here are 3 ways to disable form submission by hitting the ENTER key.

1. Submit the form using the onClick event handler instead of onSubmit event handler. It is necessary to return false from the onSubmit event handler to prevent submit on hitting the ENTER key.

2. Create a function that disables the Enter key, and apply it to each input textfield, ie, onkeypress="return noenter()"
Sample javascript code below:

function noenter() {
  return !(window.event && window.event.keyCode == 13);
}


Or

function disableEnterKey(e) {
  var key;
  if(window.event) key = window.event.keyCode; //IE
  else key = e.which; //firefox
  if (key == 13) return false;
  else return true;
}

3. Create a dummy form with a single hidden field.

Friday, November 18

A wink at Wicket

Choice is good.
Right now I can happily choose between several frameworks that I'm comfortable and familiar with (Spring, WebWork, Struts) for RAD development in J2EE. Struts seems to have been somewhat stagnant, since about mid-2004, and Spring comes across as having gained a lot of momentum these days.
However, this scenario can change. The "merger" of WebWork and Struts might inject (talk about dependency injection, huh?) new blood (and the good features of WebWork) into Struts; the rate of framework ideas and projects hasn't showed any signs of slowing down (Turbine, Expresso, Tapestry, Cocoon, Maverik, Laszlo, Echo, SOFIA, Verge, VRaptor, Jucas, MyFaces, Chrysalis, Wicket, and, the most recent one in my knowledge, Swato).

Because I want to be aware of developments within the frameworksphere and its future, I've been paying some attention to Wicket recently.
There are some reports claiming very high adoption levels for Wicket, which I frankly find hard to believe. Nevertheless, I'll keep an open mind -and an open eye to its future development.
There is a clean post at Code Poet on creating an Ajax autocomplete field with Wicket which I find attractive in its simplicity:


http://jroller.com/page/wireframe/?anchor=choice_is_good

Tuesday, November 15

Text Editor for the Web

One of the biggest usability issues of Web-applications is the text-editing support. Forcing users (often computer illiterate) to surround their text with HTML tags to bold or italicize it cannot be any more user-unfriendly.
Today Conor, my colleague at work, pointed me to this Text Editor for
the Web: http://www.fckeditor.net/

It looks good,


and it is pretty simple to use and integrate.






[Update:] And then there were t
wo. TinyMCE also looks good, it is even easier to install and configure, and in its simplest has a smaller footprint than FCK. Thanks to Micah for the link.

[Update:] I found a few more, each with different size/functionality tradeoffs. Screenshots below (click to
visit their respective sites):


widgEditor (from the very respectable Man In Blue)

Whizzywig (don't be put off by the uglier screenshot)

Monday, November 14

UUID Generators

In my J2EE world, every now and then I am asked to generate sets of a few hundreds/thousands of unique Strings -for reasons such as unique identification of vouchers sent. I usually *borrow* code that has been widely used and tested, such as Hibernate's UUIDHexGenerator or Tomcat's session id generator, the choice depending on the requirements for the String size.
Well, for future reference, here's a link to a very useful (and open-source) UUID generator library:

http://jug.safehaus.org/

String are
128-bit Universally Unique IDentifiers according to the IETF UUID draft specification. To give an example, generated Strings can look like this: a02c73a6-b8c9-46e9-a368-8b9f9ef8ff7f

[Update]
From this thread on Jason Carreira's blog, I found out about J-GUID by Steve Woodcock, whose code is currently used as the UUID generator in the XDoclet project.
Darren Hobbs usefully points out that Java has built-in GUID generation:
java.rmi.server.UID (unique over time within a JVM) and java.rmi.dgc.VMID (unique across all JVM's).
Finally, and to our utter joy, the JDK 5.0 already ships with a built-in UUID package.

Saturday, October 29

The Book

I wonder if there is a market for books on Information Architecture or usability-focused, user-centred software development. Maybe it's time I write one, since I've got the momentum. This has been on my radar for a few days now...

Thursday, October 20

The Book of Jiim

Chapters are now available on-line here.

Thursday, September 1

Abstract

Instant Messaging (IM) allows real-time, text-based conversations over the Internet. IM conversations between people with differing First Languages (L1) requires a common language that is the Second Language (L2) for at least one of the participants.
This project describes the user-centred design and evaluation of an interactive IM system that allows reading and typing of instant messages in a preferred language.
The design was informed by survey (N=162), log (N=8) and interview analysis (N=8). The prototype was evaluated by asking pairs of subjects (N=6) to perform a task where each participant read and typed in L1. Pairs consisted of a native speaker of English (L1=English) and a native speaker of Chinese with English as a second language (L1=Chinese, L2=English).
Task completion success rate, prototype log analysis, and a questionnaire were used to ascertain the usefulness and usability of the system, as well as the overall user satisfaction.
Results show preference to type in L1 was statistically significant -unlike preference to read, and the percentage of emoticons, abbreviations, alternate spellings and acronyms found is much higher than that perceived by users. These and other findings had implications to the design.
The conclusions were that pairs of subjects that did not speak the same language were able to collaborate and complete a task typing and reading in L1, translation quality was judged acceptable, and the prototype was rated highly on the specified criteria.
The results obtained are potentially generalizable to language pairs other than English-Chinese. The interface matched user needs and expectations. The system improved the process by which IM users' interact when they do not share a mother tongue, retaining the power and efficiency of communication in a preferred language.

Wednesday, August 17

The birth of Jiim

Jiim was born today, a beautiful healthy program weighting approximately 1000 LOCs.
Below is a Jiim prototype session between two IM users (click on thumbnail to enlarge)



Who is Jiim, I hear you ask? In due time, my friends. In due time.

Sunday, August 14

TimeOut JorgeTown

JorgeTown's weekly listings:

  • Monday, 15th - Birthday of The Mayor of JorgeTown
  • Tuesday, 16th - Deployment of Jiim
  • Friday, 19th - Birthday celebration for the Queen Of The Pugh
  • Saturday, 27th - Birthday of big Joseph-The-First

Wednesday, August 10

The Python King - Mayor's pride

Hmm, I have been I noticeably *excited* about this tiny, meaningless XML parser tool I wrote a few weeks ago in Python. After all, it's not like it's my first application -I have done many before.
Maybe it's because it's my first "full fledged" desktop application in like 5 years! Yep, all my development since I left this place in Frankfurt in 2000 has been Web/server-side based. Now it was really cool to play with the
OS API, menubars, toolbars, statusbars, file chooser dialogs, and all that jazz again. (not that this particular application needed all that anyways)




Sooo, the follow up to
1, 2, 3, and 4 looks like the above, though the final codebase only vaguely resembles what I posted then and many lessons were learned in terms of usability.

For example, in the 1st iteration of the tool I tried to keep user intervention to an absolute minimum. In that entry, I mentioned 3 steps: search current folder, search based on username heuristics, and search the whole disk.
Well, I obviously forgot that adventurous, living-on-the-edge users would want to tell the tool where they are keeping their logs, thereby avoiding search altogether. In fact, some users even keep their logs on a different partition (yes bro, I'm looking at you), something I wasn't expecting at all.
Hence, my final iteration of the tool gives users a 'Browse folders' facility.

Internally, the search functionality was also outrageously slow. I blamed it on the Windows API, where search is slow itself, but the truth is that there was room for improvement.
On the final iteration I make intensive use of regexes to prune the search space. Speed gains of over 80% were achieved (yes, the 1st iteration was that slow).

Saturday, August 6

'Cause I'm A Creep

So, have you been naughty recently? Apologise. It can't do you any harm.

Really.

Thursday, August 4

The Myth of Perseus

Hell, I don't like to diss things that are free, but I think I oughta write about this otherwise I'll bottle up a lot of anger and will need radical therapy.
I'll even out my karma by given them a free usability report later :)
So, a few months ago I googled for free-as-in-free-beer, research/student friendly, on-line survey providers. Of all the names found, Perseus seemed to be a popular choice among students and they even have a mouth watering free service to get you started.
I signed up, created my first survey (I promise I won't go into any detail on how long it takes to get one done and how painfully slow their interface is), and published the pilot. When I was ready to go live, I was greeted with the message below for a week, every time I tried to logon:


Huh? Now is this user-friendly quick response or what? A week of this! Now my question is: do they do this to their corporate users, too? I wonder.

So, patient as I am, I did what most people would: I changed provider.
Found QuestionPro and asked myself how come they were not my first choice earlier. More on them later.

Tuesday, August 2

Release The Pressure

How does this sound?

Awesome.

Python For The People - A Wee Secret

Here is a neat way to apply color to text boxes, using the tag_config property and eliminating the need to manually set the background color per text box. First, define your desired color configurations and give them aliases:

txtBox = Text(self, width=80, height=20)
# configuration for red (alias = "r")
txtBox.tag_config("r", foreground="red")
# configuration for blue (alias = "b")
txtBox.tag_config("b", foreground="blue")

This creates a list of alias/configuration pairs associated to the textbox's config object. Next, apply the configuration aliases' to the target text boxes, together with the content to be displayed:

txtBox.insert(END,"I am red ", "r")
txtBox.insert(END,"or I am blue\n", "b")

Smooth.

Monday, August 1

Python for experts - A kind of Magic

This turned out to have a simple and very neat solution, but boy was I struggling before.
The problem was that of calling the default mail client with an attachment ready to be sent, once my program finished parsing the XML log files (the attachment being the statistical analysis file).
Sounds simple? Yeah, right.


First, I struggled to find out how to get that done in VB or C#, replicating the behavior of right-clicking on a file and choosing the 'send to mail recipient' option. A reply from the python mailing-list hinted towards this direction too.
Integrating that with the python code wasn't
much of a problem but the solutions didn't work very well, certainly weren't cross-platform, and were everything but neat.

Then, also from the python-mailing-list came a precious tip: create a MIME encoded .eml file and run it from within python.

Voilà!

So, I saved an email draft of my own (with a text file attachment), opened it up, studied its contents, and created a file of my own from within my python program.
Works like a charm.
4-5 lines of code, excluding the .eml-specific content. Check out the recipe for yourself:


try:
  email_output = codecs.open("<filename>.eml", "wb")
  email_output.write(<dump .eml required blurb plus own content>)
finally:
  email_ouput.close()

import os
os.startfile("<filename>.eml')

Launching the file through os.startfile(<filename>) will cause the Operating System to open it with whatever program is associated with that extension, typically the default mail client.





Nice.

Friday, July 29

Python for dummies, Part III

Ah, the GUI at last. This wasn't really a requirement but I'd rather have something that looks more like a proper application than a command line interface -command line interfaces are sooo eighties. To combine this with my previous sections, I just need to import them and 'call' their functionality from within this class.
The code to create the user interface is listed below.

from Tkinter import *

class TemplateGUI(Frame):
# the outermost frame
  def __init__(self, parent=0):
    Frame.__init__(self,parent)
    self.type = 2
    self.master.title('GUI Template')
    self.buildUI()

  def buildUI(self):
    fFile = Frame(self)
    Label(fFile, text="Filename: ").pack(side="left")
    self.eName = Entry(fFile)
    self.eName.insert(INSERT,"example.txt")
    self.eName.pack(side=LEFT, padx=5)

# example of radio buttons to get gender data
    fType = Frame(fFile, borderwidth=1, relief=SUNKEN)
    self.rMale = Radiobutton(fType, text="Male", variable = self.type,       value=2, command=self.doMale)
    self.rMale.pack(side=TOP, anchor=W)
    self.rFemale = Radiobutton(fType, text="Female", variable=self.type,       value=1, command=self.doFemale)
    self.rFemale.pack(side=TOP, anchor=W)

# 'Male' is the default radio button selection
    self.rMale.select()
    fType.pack(side=RIGHT, padx=3)
    fFile.pack(side=TOP, fill=X)
    self.txtBox = Text(self, width=60, height=10)
    self.txtBox.pack(side=TOP, padx=3, pady=3)

# buttons to execute application functionality
    fButts = Frame(self)
    self.bStart = Button(fButts, text="Start", command=self.doStart)
    self.bStart.pack(side=LEFT, anchor=W, padx=50, pady=2)
    self.bReset = Button(fButts, text="Reset", command=self.doReset)
    self.bReset.pack(side=LEFT, padx=10)
    self.bQuit = Button(fButts, text="Quit", command=self.doQuit)
    self.bQuit.pack(side=RIGHT, anchor=E, padx=50, pady=2)
    fButts.pack(side=BOTTOM, fill=X)
    self.pack()

  def doQuit(self):
    self.quit()

  def doReset(self):
    self.txtBox.delete(1.0, END)
    self.eName.delete(0, END)
    self.rMale.select()

  def doMale(self):
    self.type = 2

  def doFemale(self):
    self.type = 1

  def doStart(self):
    filename = self.eName.get()
    if filename == "":
      self.txtBox.insert(END,"\nNo filename provided!\n")
      return

    self.txtBox.insert(END, "\nStarted application...\n")

    resultStr = "Success"
    self.txtBox.insert(END, resultStr)

myApp = TemplateGUI()
myApp.mainloop()

When run, the code above produces the GUI below:


Neat, huh?

Thursday, July 28

My color?






Green



You are a very calm and contemplative person. Others are drawn to your peaceful, nurturing nature.




Find out your color at Quiz Me!


Green? Hmmm.

Thanks to Michael Collins for the link. Check out your color here.

Wednesday, July 27

Python for dummies, Part II

In my previous Python entry I posted code to collect string/word information from a document/string, plus a simple MSN-specific parser that allows me to navigate a DOM document and extract its nodes and content.

Now, I need functionality to search for the files to parse on a disk and I need a
GUI.

Search first.
I spent an awful lot of time playing around with OS-specific code to traverse and navigate directory structures only to find out that Python has most of this functionality built-in, faster, and cross-platform.

I didn't want my disk search to take ages. Hence, I decided to split it in three phases:

1 - Search for log files on the current folder, in case the user drops the executable there. Assuming the parser from Part I is named 'my_parser':

import os, fnmatch
files = [filename for filename in os.listdir('.')]
for f in files:
  # only list XML files
  if fnmatch.fnmatch( f, '*.xml' ):
    my_parser.parse(f)


2 - Search for files, starting from the user's profile folder. This prunes the search space by avoiding OS and user specific folders. I separated searching the right folders from listing the log files;

import os, fnmatch, re
folders = []

files = []
r = re.compile(r'msn_username') # msn_username is passed by the user

def browse((r, folders), dirpath, namelist):
  for name in namelist:
# list folders' names starting with msn_username given
    if r.search(name):
      folders.append(os.path.join(dirpath, name))

def listfiles((wildcard, files), dirpath, namelist):
  for name in namelist:
    # only append 'wildcard'-specified filenames
    if fnmatch.fnmatch( name, wildcard ):
      files.append(os.path.join(dirpath, name))

userbase = os.environ['USERPROFILE']
# change directory to user profile folder
os.chdir(userbase)
os.path.walk(os.getcwd(), browse, (r, folders))

if folders:
  # populate the list of XML files from the folders
  wcard = '*.xml'
  for fld in folders:

    os.path.walk(fld, listfiles, (wcard, files))


3 - Search for files on the whole disk, in case none was found with the two previous methods;

# replace the userbase value with root directory
userbase = '\\'
os.chdir(userbase)
os.path.walk(os.getcwd(), browse, (r, folders))
...


And that's it. Amazing how simple it looks now. Part III, the GUI, will follow soon.

UPDATE: This module does most of the above in a nicer, more elegant way. No need to reinvent the wheel.

So very special

I wonder if Radiohead knows about this Flash video for Creep, a terrific match for the song, much better than their actual video. Thanks to Michael Collins for the link:

http://www.lowmorale.co.uk/creep/flash/lm_creep_(FLASH).swf

Thom Yorke has a superb talent for creating and singing simple, beautifully melodic chorus, two of which come to mind now:

"I wish I were special
So very special"
from the song Creep on the Pablo Honey album and

"If I could be who you wanted
If I could be who you wanted
All the time
All the time"

from the song Fake Plastic Trees on The Bends album.

The Unbearable Weightness of Being

Every time I go back home to my parents, they always remark that "I've lost weight" and "I look very skinny". Now if I had really lost all that much weight at each visit, I would be a popular skeleton model at some med school by now.
Interestingly enough, I've also noticed my scales seem to disagree with that observation, together with the fact that my food intake levels haven't seen any significant drop (quite the opposite!), and I feel myself "puffier".
Since they are also the only ones who notice this extraordinary weight loss of mine, I guess what they are really trying to say is "we miss you beloved son, we want you back at our dinner table like in the past, we want to cook for you, we miss your company!"
I love my parents :)

Saturday, July 23

Geek dinner

Yesterday I attended my first geek dinner, held at this place in central London. It was good to finally put some faces to the blogs I've been reading. Met a few 'famous' geeks such as Chris DiBona from Google -the man behind the Summer Of Code program, Jeremy Zawodny from Yahoo, alongside with Helen, Rachel, Peter, and some others whose names I can't remember or didn't get.

Thought it was very interesting to have a guy from Google and a guy from Yahoo together in the same table (which happened to be the table I was sitting).
Their personalities highlighted the current state of the companies they work for:

  • Yahoo, the colossal Internet mammoth now somewhat peripheral to the media hype, was represented by an obviously very intelligent but quite low profile Jeremy.
  • Google, on the other hand, is the place to be; the company-du-jour, the site at the forefront of most of today's technology innovation, and the company that probably has the highest levels of media attention in the corporate-sphere these days, was represented by a very eloquent, pervasive, excited, charismatic and over-confident Chris.

Tell me the company you work for and I'll tell you how you are?

Wednesday, July 20

Python for dummies

I have been using Python extensively in my research at UCL. Since it offers simple and elegant solutions for some issues I had, I'm posting my development sketches for future reference.
The IM logs I'm analyzing are stored in XML files and I'm extracting and normalizing the following data:

  • duration of sessions
  • number of messages
  • words per message
  • frequency of words
I addressed each of the above tasks separately and then combined them all (plus a GUI) in the final program. I wanted to collect some more data, such as the language preference of sender and recipient, but that is not kept by any IM client.
Collecting the duration of the session is a simple matter of keeping the start and end time of the session.
Counting the number of messages is a simple iterator.

Number of words per message is achieved with the pristine code:

lst = msg.split()
len( lst )

Frequency of words is addressed with the elegant:

freq = {}
for str in lst:
  str = str.lower()
  freq[str] = freq.get(str, 0) + 1


Next, some hardcore XML parser was needed. This took a bit longer to write, being that I was re-learning Python simultaneously, so I started by tackling MSN log files. Generalizing this to all other IM clients is a trivial task.

from xml.dom import minidom

def load(filename):
  return minidom.parse(filename)

def getElementsByTagName(node, tagName):
  children = node.getElementsByTagName(tagName)
  if len(children):
    return children
  return []

def first(node, tagName):
  children = getElementsByTagName(node, tagName)
  return len(children) and children[0] or None

def textOf(node):
  return node and "".join([child.data for child in node.childNodes]) or ""

if __name__ == '__main__':
  import sys
  document = load("msn_log_example.xml")
  for item in getElementsByTagName(document, 'Message'):
    print 'Message:', textOf(first(item, 'Text')
  print


Note that the example above is customized for MSN Messenger logs where the <Text> element (containing the message content) is contained in the <Message> tag. Part 2 of this tutorial will follow soon.

Oh no! (just for Seinfeld fans)

http://www.soupkitchenintl.com/default.htm

Saturday, July 16

Updating Ant on JBuilder9 Enterprise

From Tools -> Configure Libraries, select the Ant library on the left hand side panel. You should see the following under the Class tab on the right hand side:

%JBUILDER_INSTALL_DIR%/lib/ant.jar
%JBUILDER_INSTALL_DIR%/lib/optional.jar
%JBUILDER_INSTALL_DIR%/lib/jbuilder.jar

Replace ant.jar and optional.jar (all but jbuilder.jar) with your Ant installation jars under %ANT_INSTALL_DIR%/lib.

Now I have all my Java IDE's (IDEA, Eclipse, JBuilder) in sync.

R-e-s-p-e-c-t

From this thread on slashdot:

It's all about the memory and bus architecture...
The sad uninformed people say (pinch airflow from nose so you sound geeky) "It's a 64 bit processor, you need a 64 bit OS to take advantage of it, period".

What they fail to realize is the 64 bit memory and bus architecture happen *below the HAL*. the OS doesn't even see it, let alone need to be 64 bit to take advantage of it. I politely let them flap their gums and went out and bought one anyway, then proved them wrong.


Computationally = intel, tho that gap is narrowing
IO = AMD64 or opteron.


I don't care if you are running windows 95, amd64 will be faster for IO bound stuff, than any 32 bit architecture is capable of even getting close to.
If you are crunching spreadsheets, word processing or videogaming, *generally*, intel is better, tho that gap is getting smaller. It will likely disappear when 64 bit OS's get apps caught up to them.
For DB, working with large files, shunting lots of streams around the mobo, AMD 64 *smokes* intel 32 right now, 32 bit apps notwithstanding.

There is simply no contest.

Wednesday, July 13

DHTML Forms

At last, the full set of HTML components is customizable by CSS.

This article http://www.gamingheadlines.co.uk/wod/formstyle/index.html tells you how to do it, with great examples given too.

Canvas talking

My friend Kamila is doing some fabulous research involving museums in London. I took part in one of her experiments and it was an extraordinary self-revelation exercise.
Armed with a voice recorder, I had to choose two painters exposing in the gallery, a couple of paintings from each, and talk for half an hour about the paintings whilst facing them.

I chose Rembrandt and Seurat, Rembrandt being one of my favorites, Seurat because I wanted to have contrasting artists. The experiment was incredible, as I have never verbalized art before. I was also amazed (and so was Kamila) with how much I had to say (note: not necessarily amazed with how good what I had to say was!).
It will definitely be something I will be doing often, obviously without the recorder and without the need to talk it out loud.
It made me see paintings I took for granted in a totally different way.

Saturday, July 9

A plan for Africa

My plan for Africa simply relies in education. The situation in the African continent will only improve with the education of its people.
My idea is to spend (Live8?) money on scholarships, grants, and stipends aplenty so that 100s or 1000s of young people from many African countries access good schools and universities abroad.
Sure some would remain abroad, but many others would return and do/give something back to their home nation.
I think the hope of the continent lies in those who return, educated, new sounds in their ears, new visuals populating their dreams, their minds flourishing with new ideas.

Friday, July 8

London 7/7

No more, no less:

Londoners react to explosions not with fear and terror but with resolution and bravery. The eyes of the world are on London today. The world will see a display of stiff upper lips and unity. If there’s one thing that Londoners can do well, it’s this: they cope.

Update: The very powerful speech by Mayor Ken Livingstone is available online. Read it here, or see/hear it here. It is really a very inspired, sincere, and highly emotional moment from a man who has done some great work for this great city.

Wednesday, July 6

LondonTown 2012!

Yup, LondonTown got the Olympics! It's been crazy out in Trafalgar Sq!

I gotta tell you I've been choosing my cities pretty well:
-In 2001 I was living in China when Beijing won their 2008 bid. What a party that was!
-Now I'm back in London and London won.

Ok, you know exactly where I'm getting at: 2016 is up for grabs now.


Metropolis of the world, where should I move to and help win the next Olympics bid?

Monday, June 20

Cold Blood

This monday's memory exercise is an excerpt from Truman Capote's In Cold Blood, something I've been carrying with me for some time now.

There is a race of man that don't fit in
A race that can't stay still
So they break the hearts of kith and kin
And they roam the world at will

They range the fields and they rove the floods
They climb the mountain's crest
Theirs is the curse of the Gipsy blood
And they don't know how to rest

If they just went straight they might go far
They are strong and brave and true
But they are always tired of the things that are
And they want the strange and new

Friday, June 17

Import or not important?

I am now positively convinced any Java source code example should explicitly reference imports at package level.

Consider the JSF code snippet below extracted from here.

package com.mycompany.expense.ui;

import javax.faces.event.ActionListener;

public class ReportHandler implements ActionListener {
  ...
  public void processAction(ActionEvent e) throws AbortProcessingException {
    ...
  }
}

Even a seasoned Java developer (ahem) could accidentally import java.awt.event.ActionEvent (by force of habit, maybe?) instead of javax.faces.event.ActionEvent. Having done that, it's 'good luck, sucker!' trying to find the silly mistake from the cryptic JSF exception stacktrace.

And why is there an explicit import of javax.faces.event.ActionListener but not one of javax.faces.event.ActionEvent?

[Update]:
Cryptic (or absent)
JSF errors revisited.

Monday, June 13

The Lily

Been thinking that my memory must be clogged with tech blurb from the books, blogs, and programming languages I deal with daily. As a way to kind of balance that (yeah, in my head this makes sense), I will try to memorize something non-techie every now and then.
This week's candidate is a short poem by
William Blake (I'm aiming low to begin with)

The modest rose puts forth a thorn
The humble sheep a threatening horn
While the lily white shall in love delight
Nor a thorn, nor a threat, stain her beauty bright

Friday, June 10

My way

My world, as of half-way through 2005


What about yours?