The best kittens, technology, and video games blog in the world.

Wednesday, May 31, 2006

The will to fight God.

I've watched so much cool stuff in the last few days.
So let's start, in rough order of coolness.

  • Full Metal Panic Fumoffu (2003). Take Full Metal Panic, get rid of the plot, and replace it with overdone commedy. Plenty of stuff like battle teddy bears helping one yakuza gang beat another, weapons of mass destruction in a Japanese high school, and full scale battles to get a peek at girls at onsen. I think it's much better than the original series.
  • Amadeus (1984, #79 on imdb top list, 8 Oscars). Don't get fooled by the title, it is not a Mozart's biography ;-). Well, at least not any more than Ed Wood is a biography of Ed Wood. Actually I've seen the movie just after Ed Wood, and the similarities between Mozart and Ed were truly astounding. Anyway, the movie is about a Salieri, who at the same time is Mozart's greatest admirer and one that wants to murder him. Really awesome character development (F. Murray Abraham got a Best Actor in a Leading Role Oscar for the role of Salieri). Movies like that are one of the reasons why you should follow the imdb top list's advice.
  • Scrapped Princess (2003). I am the last dragon, who was hidden in a fold of space to aid you...when you gained the will to fight God. Really cool anime series about a girl that is destined to destroy the world. Loads of swordfights and explosions, cute girls with magical powers, stuff like that. And the plot is really cool. I haven't finished it yet, so I don't know how high should it be an the coolness scale.

Monday, May 29, 2006


I just got back from the Netherlands, visiting kim and the other guys there.

The answers to the most obvious questions, in order of the obviousness: yes, actually they do, no, no, yes, yes, yes, no, yes, plenty, yes, no, the latter, sometime soon I hope :-D

Of course you may have a different idea what's obvious and what's not, well especially the fourth question is kinda silly in my case. Oh, whatever :-D

PS. I would almost forgot about this one (probably due to the shock). The Dutch eat French fries with mayo. And it's usually plenty of mayo, some 5x more than the amount of ketchup people in other countries usually use. The funny thing - French fries with mayo are actually quite tasty.

Friday, May 26, 2006

Baby pandas are not very happy

So my application to Google Summer of Code got rejected. It wasn't quite unexpected, as there are 10x more candidates than available positions and it was totally silly to write only a single application (when the average seemed to be more like 5-10) after realizing the deadline is coming in just a few hours ^_^.

Anyway, some impressions:

  • Baby pandas still think that RbGame would be the best things to happen since Ruby on Rails.
  • Baby pandas are really curious what other projects got accepted instead. It has been quite a few days, and still the only information about them is list of titles. Baby pandas think all accepted application should be published in full. Anyway, some of the projects sound pretty cool, other less so, but it's hard to tell for sure simply looking at the title.
  • Baby pandas think taw is too lazy to code RbGame now, but they've been wrong about it a couple of times in the past. Oh well. :-)

jrpg level editor works

The level editor (on the right) is able to load, edit and save maps in the new format supported by jrpg (on the left), so now the world and the story can become much more interesting. The snowy patch visible on both screens has been added from the level editor. The tiles in the editors are still square, I'll port the tile-rounding code later. For now the editor is still only able to edit the tile data. All NPCs, enemies, quests, events, decorations, portals etc. have to be edited from the map_setup_<XXX> functions in So each map is described in 3 places:

  • As entry in World object's map_db hash table
  • In file
  • In map_setup_foo function
Here are some examples:

# In the world constructor:
self.map_db["angel sanctuary"] = {
  "tiles": self.load_map(""),
  "setup": lambda: self.map_setup_angel_sanctuary(),

# Setup method for the angel sanctuary:
  def map_setup_angel_sanctuary(self):
    def angel_quest():
      if mhc.quest_is_done("reward for level 3"):
        ui.change_text([U"I am guardian angel of software development.",
                        U"I'm impressed that you finished all quests in jrpg.",
                        U"Please send your savefile to its developer,",
                        U"and he is sure to add some new areas ^_^"])
        ui.change_text([U"I am guardian angel of software development.",
                        U"If you actually finish all quests in jrpg,",
                        U"send the savefile to its developer,",
                        U"and he is sure to add some new areas."])

# This is how file looks like:
New jrpg code is slightly slower than the old one, but the different is not that big (at least on my hardware); it's also more or less debugged. The biggest problem and the reason I'm not releasing it yet is that the code assumed things will respawn every time they get out of the players' view. So you just had to walk around the mushroom forest and you'd find all requred mushrooms. In the new code they respawn only after you leave the map, so you'd have to return from the forest to the Elven town every time you want new mushrooms. That would be rather boring. I'll add some sort of respawn code or something and then release the improved jrpg on the jrpg website.

Thursday, May 25, 2006

Scrollable maps in jrpg

jrpg refactoring continues. The original world became scrollable, instead of jumping every screen. Of course as the original map was not supposed to be scrollable, it looks kinda silly.

Individual maps are loaded from files, so it can in principle work with the level editor.

The code still needs some work before it can be released.

jrpg level editor

I've made an alpha level editor for jrpg. That's my first program that uses wxWidgets. They have been quite pleasant to work with, in spite of horrible C-isms (that is - trying to do emulate closures with function pointers, magic ids etc.) and CamelCase naming (FooBar methods, instead of foo_bar the way God meant men to program).

As you can see, there are no rounded tiles yet ;-)

I'll keep you posted if jrpg finally gets a new bigger world or other usability improvements.

Tuesday, May 23, 2006


Making jrpg "more usable" has long been on my todo list. Recently I've read some articles about usability. Especially useful was one of the articles, which listed many usability heuristics for games. Let's see how well does jrpg do:

  • Controls should be customizable and default to industry standard settings: No customizability, but they're standard enough.
  • Controls should be intuitive and mapped in a natural way: I thinks it's doing fine here.
  • Minimize control options: jrpg has very simple controls
  • The interface should be as non-intrusive as possible: Doing OK
  • For PC games, consider hiding the main computer interface during game play: This is true for PC games (like those played with mouse + keyboard). But as jrpg is not a PC game, but a pseudo-console retro, and played without a mouse, it doesn't really apply.
  • A player should always be able to identify their score/status in the game: The score/status is always there, but not the information about the current quest.
  • Follow the trends set by the gaming community to shorten the learning curve: jrpg is a retro game, it ignores the current trends by design. But it's not doing anything particularly bad here.
  • Interfaces should be consistent in control, color, typography, and dialog design: Close enough
  • Minimize the menu layers of an interface: done perfectly
  • Use sound to provide meaningful feedback: Not done at all. Adding a slayed a demon/got hit by a demon sounds would be like a nice option.
  • Do not expect the user to read a manual: Most people did fine without it, but some seem to have problems. Quick help screen is a step in the right direction. A training mode for teaching how to fight would also be nice. I guess the hiragana demons in the forest are a good place to add the help messages.
  • Provide means for error prevention and recovery through the use of warning messages: Not applicable
  • Players should be able to save games in different states: I'm not certain about that. Save games contain information not only about the game state, but also about game's knowledge about player's kanji skills. Save/load before bosses would make the game lose this knowledge. So I think it's impossible to do it without a major redesign.
  • Art should speak to its function: I don't really know what is meant by it.
  • Mechanics should feel natural and have correct weight and momentum: A lot of work in jrpg has been done to make the movement natural. You'd be surprised how non-trivial the issue turned out. And it seemed so trivial at first.
  • Feedback should be given immediately to display user control: Doing fine.
  • Get the player involved quickly and easily: This point could be improved a lot. It takes jrpg way too much time to learn about the player's kanji skills.
  • There should be a clear overriding goal of the game presented early: Like - learn all kanji ? Fine enough.
  • There should be variable difficulty level: jrpg autodetects player's skills and if it's possible to make the game easier or harder by fighting demons in different locations.
  • There should be multiple goals on each level: Like multiple treasure chests on each dungeon level ? I don't think it's really applicable.
  • A good game should be easy to learn and hard to master: So true.
  • The game should have an unexpected outcome: Not applicable.
  • Artificial intelligence should be reasonable yet unpredictable: Not applicable.
  • Game play should be balanced so that there is no definite way to win: Well, you could always simply learn all kanji ...
  • Play should be fair: jrpg is trying to be fair, by accepting different spellings, all correct pronunciations etc.
  • The game should give hints, but not too many: Not really applicable, unless you count the silly quests.
  • The game should give rewards: The crystal ball is a step in the right direction but it's way too mean.
  • Pace the game to apply pressure to, but not frustrate the player: Difficulty is automatically adjusted to the player's skills. But I think the difficulty in the dungeon is adjusted to an overly difficult level.
  • Provide an interesting and absorbing tutorial: The kana part kinda has such a function, but it's not doing too well.
  • Allow players to build content: Like, with a level editor ? I'd like to make one for myself, but it'd be rather hard architecturally.
  • Make the game replayable: Unless you learn 2000 kanji in one go, it's pretty much replayable.
  • Create a great storyline: It probably won't happen.
  • There must not be any single optimal winning strategy: Not applicable
  • Should use visual and audio effects to arouse interest: It's a retro game after all, and I don't have any artists to work for me ;-)
  • Include a lot of interactive props for the player to interact with: I'm not sure if it's applicable or not.
  • Teach skills early that you expect the players to use later: doing OK
  • Design for multiple paths through the game: It would be nice. I'll have to check it with the guardian angel of software development.
  • One reward of playing should be the acquisition of skill: That's kinda the point of jrpg.
  • Build as though the world is going on whether your character is there or not: That's way too ambitious for jrpg.
  • If the game cannot be modeless, it should feel modeless to the player: jrpg is not modeless, but tries to be close enough. Most keys work the same way in all modes, even silly ones (save game on quick help screen etc.).
So the useful ideas for UI improvements found in just a few minutes are:
  • Add input customizability
  • Display current quest
  • Add optional sounds to the battle
  • Add a quick help screen (done, visible on the screenshot)
  • Add a training mode for battle
  • A difficulty dispatcher.
  • Make the crystal ball less mean.
  • Take a look at difficulty.
  • Finally make a level editor.
  • Make the world bigger and more interesting.
It's quite surprising how many heuristics were applicable to jrpg, especially since they aren't specific to its genre.

Sunday, May 21, 2006

Firefox extensions

(The extensions visible on the screenshot are: Googlepedia, Customize Google, Gmail Notifier, Google Calendar Notifier, StumbleUpon, VideoDownloader, Colorful Tabs, and maybe some more if you look close enough)

The best browser

Out of the box, the best web browser ever is Opera. Firefox in default settings is slow, eats too much memory, and lacks half of Opera's functionality. Everything else (Konqueror, Safari, and that weird Microsoft thing that people sometimes confuse with a web browser) isn't even close.

That could kinda end this blog entry, but Opera lacks one small feature that Firefox has - the extensions. Firefox with enough extensions can be better than even Opera. Well, at least if you have enough RAM. So as I've just installed a new system, I had to configure Firefox. Here's an overview of the extensions I installed, I hope you'll find some of them useful too :-D

The big things

Before proceeding any further I had to fix the memory leak feature. Sorry, but I only have 256MB RAM and I sometimes use other programs besides Firefox. The fix is to go to about:config and change browser.sessionhistory.max_total_viewers from -1 to 0.

As I didn't remember names of everything I wanted , I went to Firefox website and browsed extensions in order of their popularity. The most important one is of course SessionSaver. With this great extension Firefox can finally do what Opera could do since forever, that is - stop forgetting which websites were open in case of a crash or closing the browser. I hope they integrate it with Firefox 2.

UI tweaks

Then, a few things that are small on their own, but together they really improve the web browsing experience.
  • Download Statusbar. The place for the progress bars and of the downloads and their context menus is not in a separate windows per download (the yuckiest thing ever) or in a separate window/tab. It's in the status bar. You won't know how great it is until you try it. It's my pick for "what should go into Firefox 2", just after they get SessionSaver integrated.
  • Adblock and Adblock Filterset.G Updater. There are too many ads on the Internet. Let's just block some.
  • Colorful Tabs. They tab handles are colored, so it's easier for the the human visual system to localize the right one when switching tabs.
  • Fission. A progress bar integrated with the address bar. It makes downloading slow websites slightly less annoying. I've heard they took it from Safari.
  • Restart Firefox. Firefox needs to be restarted when one changes any extensions. This one adds a Restart Firefox option to the File menu.
  • VideoDownloader. Can download embeded video files, like on YouTube or Google Video. It's not used very often, but it would be nice to have it integrated.

Website integration

In addition to the general extensions, I use some website-specific extensions.

  • CustomizeGoogle. Does all kinds of cool things to Google. Enable Google Suggest, disable ads (or leave them only on Froogle), add search links to Wikipedia, Yahoo, LiveJournal etc., use anonymous cookies, filter out spam from the results. It really improves your googling experience.
  • TinyUrl creator. Can create TinyUrls from right-click menu. Very useful.
  • Googlepedia. Display side by side Google results and Wikipedia article on a subject. They're synchronized, so clicking on links in Wikipedia part will update Google part. I haven't played much with it, but it looks cool. Check the screenshot above. It seems to work fine with CustomizeGoogle.
  • Gmail Notifier. It tells you when you have new mail on Gmail. Extremely convenient.
  • Google Calendar Notifier. Similar to Gmail Notifier.
  • rikaichan - for people who read Japanese websites, but sometime miss a word or two. Translates words and kanji on the spot. This is really a must-install extension if you learn Japanese. Not of much use otherwise.
  • StumbleUpon. Want to find cool websites ? Let yourself be clustered. It's the best thing that happened to web browsing since Firefox.
  • and Complete. Integrates with social bookmarking service I've noticed that there were two such extensions on the list, and I don't know yet which one I want to use.

Other extensions

A few things that didn't fit in either category:
  • ChatZilla. A really nice IRC client. I don't think it beats irssi or xchat yet, but can be easily installed on virtually every machine.
  • View Source Chart. I haven't used it yet, I've just noticed it on the list. Makes a nice chart with website's DOM structure. Potentially useful for JavaScript debugging.
I hope you've found something for you on this list.

Or did I miss some cool extensions ? Go on and tell me about them :-D

PS. It's also a good idea to change dom.max_script_run_time from 5 to something like 30 in about:config, to avoid spurious script too slow warnings on Gmail and other Javascript-heavy websites.

Ubuntu instalation

I was really fed up with Gentoo, so I grabbed Ubuntu betas (Dapper Drake 6.06 Beta 2).

The first cool thing - installer is integrated with a LiveCD. That is - you boot into a LiveCD (like a Knoppix), with all the things (like FireFox) you'd expect from one, but also with an "Install" link on the desktop. That's the best installer ever - if you get bored looking at the progress bar you can read some web comics or something :-). I'm actually writing this blog entry from inside the installer, just clicking Save Draft a bit more often.

Live report from the instalation

  • Warning "there may be some bugs left, please backup everything". Yeah, as if anyone ever did.
  • Language selection.
  • Timezone selection from a world map. It has language-based defaults so it got Warsaw time seeing that the selected language is Polish.
  • Keyboard selection. Finally, everything is in Dvorak :-). There was something about keyboard layouts on the boot screen (Fsomething - Keyboard layouts), but as BIOS doesn't grok my USB keyboard I couldn't use it. The whole system (including FireFox) switched to the new layout.
  • Real name, username, password, computer name selection. Remember that Ubuntu has no root account by default, it uses sudo for root things.
  • Partition program. I selected the "by hand" option, as that's the part where magic can really screw someone up. The "by hand" option is a really cute partitioning wizard.
  • Instalation. Reading web comics was not such a bright idea after all. 256MB (with no swap at this point) is not enough for comfortable FireFox + installer.
  • Reboot.

After reboot

I'm going to spare you description of the hacks I had to do because of BIOS having problems with disks bigger than about 137GB, as it only took 5 minutes and wasn't Ubuntu-related or particularly interesting. Or does someone maybe know how to update BIOSes ?

Anyway, after the reboot Ubuntu told me that 357 packages have updated versions and asked me whether I'd like to update. Information on what changed in each packag was available in a nice GUI wizard. So, I just told it to go on, and it updated 357 packages (it took about an hour, screenshot taken during the update).

So, I have a working system. Now the next actions are:
  • Install all necessary FireFox extensions. That's going to be some fine bloggable material.
  • Install more packages, like Eclipse and xchat and AmaroK. It should be much easier than in Gentoo, unless one of the programs has not been packaged for any Debian-based distro.
  • Install the proprietary 3D drivers. Yucky.
  • Configure everything that needs to be configured. Probably not too much work.
  • Decide whether GNOME (Ubuntu default) is better than KDE (what I used so far). If not, it's just a few clicks to switch it. The first impression is good - it doesn't seem to suck as much as it used to. Like, the terminal actually supports tabs. Another bloggable stuff coming :-D

Saturday, May 20, 2006

Predicting coolness

One of the coolest thing about the Internet is that it tries to predict what you're going to like. Nothing has tried that before. With newspapers or TV they tried to make you like certain things, usually products of those that paid for advertisements or the political views shared by the redactors. Don't even mention the "ratings" one could find in the newspapers, they were completely laughable.

But the Internet can be different.

First order prediction

What's the simplest way to predict whether you're going to like something or not ? Well, one could ask a lot of people what do they think about it, and simply guess that your opinion is going to fall somewhere in the middle.

That's what IMDB is doing. It is very good at suggesting what kind of movies are you going to like. Of course only if you have taste similar to the IMDB average. If not, you need to add a correction factor, like - well, I don't really like Spielberg, so I'm going to subtract 0.8 from each of his movies' score.

What if the system could do such corrections for you ?

Second order prediction

The next style of prediction, and the one that is considered the way nowadays, is predicting based on similarity of preferences. So you have to rate a few things first, then you get clustered with users that have similar preferences to yours, and the system estimates your further preferences based on theirs. Unless you're really unusual it's going to be better than the first order prediction. Or unless you provided too little data, but a well designed system should just fall back to the first order prediction in such case.

A very primitive version of second order prediction is something that the best p2p program ever (AudioGalaxy) had - the "if you like songs by A, you should also check B, C, and D". It worked perfectly. Most Internet bookstores seem to have a similar feature too, but it doesn't work that well. I guess music taste is simpler to predict than book taste.

A full-fledged second order prediction is present in StumbleUpon and

StumbleUpon tries to find you some cool websites by clustering you with other users. It's a browser plugin (I use it with FireFox), so if you want a random website you click Stumble!, and then you can click a "I like it" or "I don't like it" button to get clustered better. Before you get any pages you have to select topics you're interested in, so it has something to start from. I think that's the best thing to happen to the web browsing since FireFox. (and I think there are a few other projects like it) tries to predict your music preferences by clustering you with other users. It's integrated with a music player (I use it with AmaroK). Unfortunately it's not integrated with a P2P program, so it can't simply stream you new music and ask whether you like it, but it has some sort of personalized radio, a suggest feature, "neighbourhood" (people with similar taste) and other goodies.

There are probably many more than that. I predict you're going to like them. The prediction used first order method, because almost everybody does like them.

Third order prediction

Is clustering the last word or are we heading towards a new kind of coolness prediction ? Will IMDB add user clustering ? Will "smarter" methods like Bayesian networks find their use ? Will we be using mobile phones in grocery stores to cluster our food preferences ? How will it all affect anonymity and privacy ? In any case, I predict it's going to be the next big thing.

Friday, May 19, 2006

Tawbot UI - first public screenshots

That's actually the second attempt at making a Tawbot UI. The first one totally sucked, this one is much nicer.

The GUI is made with Ruby on Rails, with some AJAX. It uses Sqlite as a database backend, but this can easily be changed.

The workflow:

  1. Using collection constructors (or by editing collections by hand) prepare collections of articles.
  2. Enter the collection screen, and using a nice dialog decide what do you want to do with the articles. Saving the actions for later use would be a good idea, but it's not implemented yet.
  3. Press Go.
The collections are saved in the database, so you can prepare them on one day and do the actions on another. Step 2 and 3 will need some AJAX for usability.

The GUI should be very portable, it only requires Ruby on Rails and Sqlite (and the later can easily be replaced by any other database).

And here are the promissed screenshots. Some code:

Collection management view:

Collection details view (the one where the actual actions are performed) will get a major redesign soon, so no screenshot yet. :-D

I'll keep you posted on any new developments.

Beating a dead Gentoo

You thought I'm done with Gentoo bashing ? You thought wrong. Unfortunately they delayed a new Ubuntu release till June, so expect a few more posts about Gentoo before I can finally get away from it.

So first, automerging configuration changes broke at least 2 packages - apache and dictd. Both are kinda funny - Gentoo version of Apache is the only version ever made in which one cannot reload the configuration without stopping Apache first. Well, the Gentoo guys got a bright idea that instead of using regular configuration files, it's better to have configuration in /etc/conf.d/apache2, and pass that to the Apache server when it starts. Of course those files, unlike the regular Apache configuration, won't get reloaded on /etc/init.d/apache2 reload. Oh yeah, and they decided to break the configuration files on automerging and not even save a backup of the files before the automerge. That's one of the candidates for the biggest Gentoo annoyance, and the competition here is very tought.

And it broke dictd. Well, it got an idea that it should switch from Unicode to C. A short information for the dictd package maintainers - dictd does not work at all unless it's run in UTF-8 locale. The damn error message in /var/log/messages even tell me to switch to UTF-8 locale because dictd doesn't work in locale C. And does the unicode USE flag mean anything ? Not much apparently.

Let's forget the configuration mess for a moment. I wanted to check out high level languages for JVM. To my surprise, jRuby, Jython and Groovy were all available in portage. Wow, I thought, I doubt even Debian has them all, now Gentoo finally has a chance to shine. And guess what ? Not a single of them was installable. I even emerge sync'ed, but it didn't help any.


java.lang.UnsupportedClassVersionError: org/apache/bsf/BSFManager (Unsupported major.minor version 49.0)


>>> Compiling source in /var/tmp/portage/jython-2.1-r6/work/jython-2.1 ...
org/python/util/ cannot access org.gnu.readline.ReadlineLibrary
bad class file: /usr/share/libreadline-java/lib/libreadline-java.jar(org/gnu/readline/ReadlineLibrary.class)
class file has wrong version 49.0, should be 48.0
Please remove or make sure it appears in the correct subdirectory of the classpath.

and a similar one for Groovy.

Just one last thing. Among the broken packages are pam-login and shadow. Should I uninstall them both and break the system in hope that the new versions compile correctly (and I don't have to login in the meantime) ?

# emerge -av pam-login shadow

These are the packages that would be merged, in order:

Calculating dependencies... done!
[blocks B ] sys-apps/pam-login (is blocking sys-apps/shadow-4.0.15-r1)
[blocks B ] >=sys-apps/shadow-4.0.14-r2 (is blocking sys-apps/pam-login-4.0.14)
[ebuild U ] sys-apps/shadow-4.0.15-r1 [4.0.7-r4] USE="nls pam -nousuid -skey" 1,264 kB
[ebuild U ] sys-apps/pam-login-4.0.14 [3.17] USE="nls -livecd -skey%" 1,217 kB

Ed or Wood

In the last few days, I've seen a few IMDB top 100 movies.

In order of coolness:

  • Ed Wood (1994, actually #188 on the list, not in top 100). A must-see for all the fans of Ed Wood (of Plan 9 from Outer Space fame). A totally over the top commedy about one of our favourite movie directors. Sorta beating a dead horse feeling with regards to how the movie treats Ed Wood, but hey - he directed Plan 9, so who else deserves it more ?
  • Apocalypse Now (1970, #38). Based on Conrad's Heart Of Darkness, but taking place in Vietnam and much more psychodelic. All the brutality and absurdities of the Vietnam war, an interesting story and well developed characters. Definitely a must-see, unfortunately it's hard to tell much meaningful stuff about this kind of movies, they're just too weird.
  • Goodfellas (1990, #23). This one was kinda cool. It was based on facts, so they couldn't add too many over the top scenes of the kind that one sees in most of the mafia movies (especially in the Tarantino stuff), but it was still pretty extreme at times. This mixture of realism, and occasional overplaying made it one of the best mafia movies I've seen. The characters actually have some personality, not like everyone being "just another gangsta" like in many other movies. Oh, and the action is pretty cool. Definitely a nice movie to see.
  • Lawrence of Arabia (1962, #28). A long (over 200 minutes) movie about the war. The plot is ok and the main character is interesting, unfortunately the movie is excessively long for no good reason. Oh, and the secondary characters are rather boring. I say it's overrated.
  • Schindler's List (1993, #6). Did it really have to be 195 minutes long? Most of the time it was "just another Holocaust movie", y'know the one where there are evil Nazis doing all kinds of bad stuff to the innocent Jews, with little attempt of character development or social analysis of the war or such kind of the things. The idea is to completely dehumanize the Germans, because if they've shown otherwise "normal" guys taking part in the genocide, it could make some of the Americans uneasy about My Lai or Abu Ghraib or whoever the American Army have been murdering recently, and that would be bad for ticket sales. Oh, and they simply had to put the few completely unnecessary scenes to make it look like the Polish were ok with the killing. Oskar Schindler and Amon Göth are the only characters in the movie with any kind of character development, and they're both rather flat. I have no idea how did it get 8.8 on IMDB, I wouldn't rate it any higher than 7.0.

Thursday, May 18, 2006

Cold Heat

As seen on ThinkGeek, Slashdot and LiveJournal ... I've got myself a Cold Heat soldering iron ^_^. It's supposed to heat itself to the right temperature in 3 seconds, and cool down to room temperature in 3 seconds, and it has some protection against soldering accidents - it won't heat itself up unless two halves of the soldering tip are bridged by some conductor.

Maybe I should resurrect my TTL CPU. It was kinda fun, trying to build a CPU from basic logic gates, unfortunately it was pretty hard without the right hardware. A decent soldering iron it certainly going to help.

If you want to buy such a toy - in Germany or Poland try Conrad Electronics (shipping from ThinkGeek costs more than the item). In Poland Conrad Electronics also sells them on Allegro. In the U.S. I guess it's ThinkGeek.

Tuesday, May 16, 2006

OCaml programming best practice

(The panda doesn't feel well, because of programming too much OCaml. But trust me on this, you do not want to see a panda that had to code C++)

OCaml is a very big and complex language, like C++, and many parts ofit kinda stick out, are experiments that didn't go well, or exist only for backward compatibility.

If you want to code OCaml, you might find these hints useful.

  • "Exceptions" in OCaml won't give you a backtrace. This is easily one of the top 3 worst things about OCaml. So even in situations when you'd use an exception in Ruby/Python/Java/etc., think whether you can do something else in OCaml.

    • For handling "can't happen" situations use something like failwith (sprintf "Internal error: function foo(%d, %s, %s) expects a non-empty list" a b (foo_to_string c)). Because you won't get a backtrace, you should include as much information as possible.

  • OCaml's standard library is one of its weakest parts. Always use extensions to the std library. If you are concerned about people introducing unnecessary dependencies, simply copy sources of it to your repository with an appropriate copyright notice.

  • As we know from Perl/Ruby/Python/every other modern language, the three most common data structures you ever use are strings, hash tables and resizable arrays. You can get OCaml support all of them reasonably well, but it doesn't by default.

    • sprintf is one of the most useful OCaml functions. And do open Printf in all your OCaml files, it will save you a lot of typing and functions from Printf module have names that don't collide with anything. If you need to print something for debugging, define converters of all your types, like foo_to_string foo = sprintf "%s %d %s" foo.a foo.b foo.c

    • DynArray (resizable arrays) is one of the most useful OCaml data types ever. No more idiocy like building list ref and reversing it.

    • OCaml Hashtbl is weird and confusing. It is used for 1->1 hashes and 1->N hashes (and ('a,unit) hash tables are used as sets) and it's easy to get something wrong (was Hashtbl.add meant to add another element to 1->N hash or was it simply setting a value that didn't exist before ...). Besides, calling Hashtbl.blah is extremely verbose and it's impossible to include them in your namespace due to collisions. So it's very good idea to make types ('a,'b) ht = HT of ('a,'b) Hashtbl.t for 1->1 hash tables, ('a,'b) mht = MHT of ('a,'b) Hashtbl.t for 1->N hash tables and 'a set = SET of ('a,unit) Hashtbl.t. Then define functions like like ht_set, ht_get, mht_add, mht_get_all, ht_iter, mht_iter_all, set_add, set_mem etc. in a module that you include from all your files (I usually call it And definitely define functions like ht_keys, ht_values, ht_iter_keys etc. I have no idea how could they have forgetten them in the std library.

  • Do not use tuples bigger than 2 (in special cases 3) elements, or long-living tuples. Use records instead. Records can be easily extended, can be made mulable, and you won't have to remember which field of the tuple meant what. This also applies to Python ;-)

  • Encapsulate all common folds and tail recursions. It's very easy to make a mistake with them and the code looks ugly. On the other hand high-level functions like map, iter, filter, collect, join etc. don't clutter your code. Never use the same recursion/folding pattern twice. Extract the pattern. I think it's a good idea to separate the pattern from the application code for single-use patterns too. Some examples: collect : ('a'->'b option) -> 'a list -> 'b list, mht_iter_all : ('a' -> 'b list -> unit) -> ('a,'b) mht -> unit.

  • ocamldep is pretty helpful for writing Makefiles. Simply do ocamldep * >>.deps from time to time and include .deps from your Makefile.

Monday, May 15, 2006

A very secret quest

Do you know about this very secret quest in live, when after you watch the last movie from the IMDB best 100 movies (or the IMDB worst 100 movies, but I'll try the former quest) you get an instant level-up ? ^_^

Well, but more about it some other day. I've just seen a movie that isn't on either of these lists and I think it's the best movie I've seen since, like, TNG 4x25 (don't ask, you're either getting it already or you just won't get it ^_^). The movie is Michael Moore's Bowling for Columbine and it's at the same time absolutely hillarious (I almost fell down of my chair during the bank scene, just 2 minutes into the movie) and quite insightful. Fahrenheit 9/11 wasn't bad, but it doesn't even come close to the Bowling.

Now I can't tell you much about the movie without spoiling too much. But here's one that I just couldn't skip. The dog you're seeing here, some redneck hunters dressed it in a hunter wear and gave it a loaded gun. Then the dog used the gun to kill one of the rednecks. I'm sure the dog knew what it was doing. Like, a great service to the mankind, by getting some of the dumb genes out of the gene pool. Dog, the humanity thanks you. ^_^

Gentoo upgrade

(A cute image from CuteOverload for about as much particular reason as the last time)

So it spite of all the ranting about Gentoo being essentially impossible to upgrate, I tried to upgrade it. By going over the list of the packages and selecting those that were upgradable by hand, but I did it. Well, sort of ^_^.

And now I'll tell you what happened during the upgrade. First I rsynced the portage tree and svn-up'ed an "overlay" (equivalent of an extra repository in Debian) with Eclipse. That is, I did an equivalent of apt-get update.
Now every time I run emerge it tells me something about a parse error in one of the Eclipse ebuilds, but it doesn't seem to have any ill effects so let's skip that.

As full upgrade is impossible, I did some emerge magic, like emerge -about -seven -options -pasted -from -#gentoo -on -freenode that was supposed to tell me what can I upgrade. Of course it didn't work. It thinks that my version of mod_php is bad and I need to uninstall my mod_php and install a different mod_php if I want to keep using Gentoo. I still don't get it how mod_php is related to portage but anyway.

On the other hand emerge --pretend --update --newuse world did work, well kinda. It showed a list of packages that weren't 100% new, and I could hand pick from this list the ones that I wanted upgraded. About 200 package upgrades ones, two days and 3 emerge crashes (can't compile this or that) later, the system was it a kinda more up-to-date state. I even felt like maybe I was overreacting a little the last time. Then I rebooted ...

Now something came that I've never seen in Debian, even with all the unstable and experimental packages. The upgrades broke the configuration files ! lo interface was down, /etc/init.d/net.lo start gave a parse error, oh and half of the thing did not work because lo was down. I kinda remembered that I'm supposed to run etc-update after each upgrade. etc-update "automerged trivial changes" to about 20 configuration files and gave me a list of 49 others that I was supposed to merge by hand ! Well, /etc/init.d/net.lo was on the list so I just told it to use the new version from the package. Now lo works and I have only 48 broken config files on the system.

Was it over ? Not at all. svn was down because of library issues. Oh yeah, I'm supposed to reinstall all packages that use library X after I upgrade library X (like I ranted before about Perl and Python). Upgrading svn fixed it.

Now the funny thing, Gentoo has an automatic fixer. One just have to say revdep-rebuild, and it goes through the system, finds all executables with broken library dependencies, and reinstalls their packages. Now, it found that KDE ioslave for SVN is broken. However, it could not reistall KDE because the old version was not in portage any more, and I couldn't upgrade to the the new KDE because of some unrelated broken dependency on libfaad2. So I'll have to live with broken SVN ioslave in KDE. But I'm not complaining, compared to other problems I've had with Gentoo a broken ioslave is like a flu added to a cancer.

Summary for users of Debian and other sane systems - Gentoo is like Windows 98, you're not supposed to upgrade it, it is far easier to backup your /home, format your hard drive and reinstall it from scratch. Or switch back to Debian, what I plan to do as soon as possible.

Nighttime cycling season

The nighttime cycling season is now officially open.
Especially as the network is down again and I'm writing it as 3:45 am from the university ;-)

Here's a photo of a fountain at Dudo platz, near where I live.
It's rather lousy, but that's about how much one can get from a mobile phone camera. Maybe I'll get a real one if my application to Google Summer of Code gets accepted ;-)

For now, nighttime cyclists of all countries, unite ^_^

Sunday, May 14, 2006

gcc partial redundancy elimination

Compilers are usually a pretty boring subject, but this is really sweet. Take a look at the following snippet and try to guess what will the generated asm code look like (for your convenience, the interesting parts marked with different colors):

#include <stdio.h>

int foo(int i) {
 if(i > 0)
 else if (i == 0)
Now look at the actual generated code (colored parts correspond to the colors in C code):

     .file   "puts_pre.c"
     .section        .rodata.str1.1,"aMS",@progbits,1
     .string "positive"
     .string "zero"
     .string "negative"
     .p2align 4,,15
.globl foo
     .type   foo, @function
     pushl   %ebp
     movl    %esp, %ebp
     subl    $8, %esp
     cmpl    $0, 8(%ebp)
     jle     .L17
     movl    $.LC0, (%esp)
     call    puts
     movl    %ebp, %esp
     popl    %ebp
     .p2align 4,,7
     jne     .L19
     movl    $.LC1, (%esp)
     jmp     .L21
     .p2align 4,,7
     movl    $.LC2, (%esp)
     jmp     .L21
     .size   foo, .-foo
     .section        .note.GNU-stack,"",@progbits
     .ident  "GCC: (GNU) 3.3.6 (Gentoo 3.3.6, ssp-3.3.6-1.0, pie-8.7.8)"
LOL ZOMG, call to puts has been taken out of the if ^_^

Friday, May 12, 2006

apt-get upgrade

(this is pretty rantish, don't read if you're easily offended. I added the hamster pic from CuteOverload for no particular reason ^_^)

I've seen quite a few Linuces in my life. Most of the time I used Debian (unstable or later testing) or something based on Debian (kUbuntu). However, needing new Eclipse/Firefox/(million other things that weren't in anything Debian-based at that time) and having kinda broken my Ubuntu by mixing it with too many packages from Debian unstable, I decided to give Gentoo a try.

The good things

The most important one - Gentoo packages stuff much faster than Debian. Usually it has more and more recent packages than Debian, but there are a few exceptions (like dictd dictionaries).

Also, Gentoo has nice online documentation, Gentooers on IRC are usually more friendly and clueful than the average.

Lack of global packager lock is nice - I can install a small package in the middle of major system upgrade. In Debian, I had to wait for the upgrade to finish.

The not-so-good things

Initial install wasn't that bad. Sure it took about ten times longer than with other distros, but that's ok.

There are many quirks that are annoying but passable, like:

  • extremely minimalistic default USE flags. Right now I have 131 USE flags set. I'm not kidding you, here's the full list: 3dnow 3dnowext 7zip X a52 aac accessibility alsa apache2 asf avi bash-completion berkdb blas browserplugin bzip2 cairo canna cdparanoia chasen cjk crypt curl dba divx4linux doc dv dvd dvdread emacs encode esd examples exif fam fame fastcgi fftw firefox flac glitz gnutls gs gsl guile haskell imagemagick immqt-bc ipv6 ithreads jack java javascript jbig jce joystick jpeg jpeg2k kde kerberos krb4 latex ldap matroska mmap mmx mmxext mono mozdevelop mozilla mozsvg mp3 mpeg mplayer musicbrainz mysql network nls nodrm nptl nsplugin nvidia odbc offensive ogg opengl pdf perl php png postgres python quicktime rar real rtc ruby samba sasl sdl slang spell sql sqlite sqlite3 sse ssl subtitles subversion svg symlink tcltk tetex theora threads tiff truetype unicode usb utf8 visualization vorbis win32codecs wmf xanim xine xml xml2 xprint xvid zlib. Why the heck 90% of them are needed totally loses me. If someone doesn't want png support, they should be the ones to have to explicitly say it. It completely breaks the "Zero Config" principle.
  • Upgrading Perl (or Python etc.) means one has to reemerge all Perl libs by hand, or they won't be available in the new version. So emerge perl can break various installed programs. I think there is a message about that somewhere in the emerge output, but when more than one package is being upgraded at the same time, it will be lost in the flood of compiler messages.
  • Lack of testing-like distribution. It's either x86 (kinda like Debian stable) or ~x86 (kinda like the original Debian unstable, before they got testing). So either I have to put up with very old packages or accept a high possibility of random breakages. Many ebuilds from ~x86 did not build on my system.
  • Upgrades are really slow. Compiling is about 100 times slower than installing a binary package.

The bad thing

Gentoo doesn't have apt-get upgrade.

Gentoo does have emerge --av --update --newuse world, but it's not even close. It's about as far behind apt-get upgrade as Turbo Pascal is behind Ruby.

Now, the Gentooers (and Turbo Pascal users) deserve some explanation, as they probably don't believe me the difference is so big. So here it is.

apt-get upgrade checks all the packages in the system. Then, it checks those packages that can be upgraded without either breaking/uninstalling anything or installing anything fancy (other than trivial package rearrangment). Then it downloads and installs the upgrades. In the end, you have an upgraded system, and the packages that couldn't upgrade automatically are simply left in their original state. You can even add apt-get upgrade to the crontab. Every once in a while you spend about 30 seconds dealing with the packages apt doesn't upgrade automatically (which of course don't block the rest of the upgrade).

Let's compare it with emerge --av --update --newuse world. It checks all the packages in the system. Then it checks those packages that can be upgraded. So far so good. Now, if anything looks out of order - it tells you that it won't upgrade anything and thet you can go to hell. It cannot upgrade X, you have to uninstall them and install the new X. Because everything is being compiled on install, compilation can fail and it often does with ~x86. It can break your system (see above about Perl libraries). It takes forever, using a lot of CPU cycles. I don't think even one person has it added to crontab. Most Gentooers seem to have awfully out-of-date systems in spite of Gentoo packages often being more up-to-date than Debian's.

Now, excuse my rant and go back using your favourite distribution, whatever it is. I was simply annoyed by emerge and had to write something to calm down. ^_^

Wednesday, May 10, 2006

Sofutowea kaihatsu no shugotenshi, tasukete


After a few days long break due to ISP problems, new release of jrpg is out.

The main improvements:

  • Mistakes you make are saved to mistakes-<date>.txt file, for later review.
  • A long standing nuisance has been fixed. On the JLPT lists, 四 on level 4 has only pronunciation し, and on higher levels it has pronunciations し and よん (because less common pronunciations are not appropriate for beginners). jrpg used to follow JLPT closely and have two separate demons - JLPT 4 四(し) and JLPT 3 四(し or よん). As now JLPT level has only a minor influence on order fo the demons, the demons had been merged, and now 四 accepts either し or よん, always. Some 20 similar cases have been fixed too.
  • Crystall ball in the castle (on the screenshot) can give you some statistics on how well you're doing. If people find it useful, I might extend it in the future (all the statistics are there, they just don't get displayed yet).
  • The guardian angel of software development (if you can find her) ^_^.

Oh, and jprg has 212 downloads by today. ^_^

Tuesday, May 09, 2006

Google Summer of Code

I accidentally learned on May 8th that it was the last day of Google Summer of Code submissions. I was kinda considering applying before, but I didn't really know whether I felt like doing that. Well, deadlines have this weird property of making me want to do something (do you have the same feeling sometimes ? ^_^), so I got to a computer and wrote an application.

At first I thought I'd write at least 3 applications (that would be a much safer "strategy"), but when I was thinking what kind of stuff can I do, one idea (RbGame) felt to me so awesome that it made all my other ideas look boring and uncool. So I felt like, I don't really want to do X (even if X felt cool just a few hours ago), as RbGame is so much cooler than X, and if RbGame gets rejected and some less interesting idea gets accepted I'll be feeling bad all summer working on something that's not as cool as it could be ^_^.

Well, at least it's cooler than all other ideas that seem at least somewhat relevance to the Google Summer of Code. I do have a few that are even nicer than RbGame, maybe I'll write about them sometime later ^_^.

So, as according to the probability theory RbGame won't get selected (there's going to be probably be so many applications, that even such awesome ones ^_^ as RbGame can get rejected)

Very short descriptiom - RbGame would let me port jrpg to Ruby, and because Ruby is so much better than Python, it would let me make it the best Japanese learning game ever made. (well, it is much better than KiCL and Slime Forest already, but anyway ^_^). So, like, people would play for 5 minutes and they would be able to speak Japanese. Well, maybe not that good but close.

Oh, and it would make baby pandas happy.
And here's the longer description, directly from the application.

Longer description

Ruby is without doubt the best of the currently available very
high level languages, being much more expressive and elegant than
either Perl or Python (and I'm saying that in spite of quite a lot
of Perl/Python experience).

However due to significant headstart the other languages had,
important libraries and utilities for Perl and Python often
have no equivalents for Ruby, or the Ruby equivalents aren't
as well developed. A lot of focused effort will be
required to mitigate the issue.

One of the areas where Ruby significantly lags behind
Python is game development. Python's PyGame library
is well-integrated with the language, provides very
convenient high-level interface, and has been used
to develop hundreds of great Open Source games.

On the other hand, the closest Ruby equivalent - Ruby/SDL
is just a thin wrapper for a C library, which doesn't provide
convenience comparable to PyGame and has been used
by few games or other applications.

RbGame's goal is to develop convenient high-level SDL-based
library for Ruby that can directly compete with PyGame.

The codebase is probably going to be based on Ruby/SDL.
The design is going to be based on PyGame's but taking
advantage of all Ruby features (closures, symbols, OO
metaprogramming etc.)

I expect RbGame to significantly increase Ruby's adoption
in the Open Source game development community in the next 1-2 years,
and possibly have a positive influence on Ruby's adoption
in other areas.

Howto make your hair evil, or the Coffein Shampoo

Shopping for a new shampoo I've found something truly evil - a shampoo that contains caffeine.

Ingredients: Aqua, Sodium Laureth Sulfate, Laureth-2, Disodium Laureth Sulfosuccinate, Sodium Lauroyl Glutamate, Sodium Chloride, Caffeine, Panthenol, Parfum, PEG-120 Methyl Glucose Dioleate, Hydrolized Wheat Protein, Citric Acid, Sodium Citrate, PEG-40 Hydrogenated Castor Oil, Menthol Potassium Sorbate, Polyquaternium-7, Disodium EDTA, Sodium Benzoate, Niacinamide, Zinc PCA, Limonene, Tocopherol, Phenoxyethanol, Methylparaben, Propylparaben, Butylparaben, Ethylparaben, Sodium Hydroxide, CI 60730, CI 42090.

I'll keep you posted if anything funny happens to my hair. Now I'm just looking for Manga Blue hair colorizer ^_^.

Friday, May 05, 2006

Baby pandas, or how to fight evil with cuteness

First, take a look at the baby pandas. Do we all agree that they're very cute ? Ok, so as we do, let's get to the point: Why do people still use C/C++ ? Now, sure sometimes you already have a chunk of code in C/C++ or need some extra performance or whatever. But I think most of the time people use it just because it takes too much effort to switch to something else, even if at conscious level they "know" the other language would be better for them. It's just that in the small thing they're doing right now it's faster and easier to stick with the old methods. How do I know it ? Well, I've been using Perl for most of the scripting, even though I know that Ruby has all the nifty things that Perl does not. I've Perlscripted things so many times that I can write Perl one-liners (equivalent to 100 lines of Java) without even looking or being aware of what I'm typing. ^_^ With Ruby I still have to think what I'm typing. But that won't last any more - from today I'm not going to code anything in Perl if it can be done in Ruby (that is - unless I'm modifying some Perl program like tawbot). The first effect of it is the following code:

ruby -le '{|line|line} .scan(%r[http://www.\\?epDate=\d+-\d+-\d+])} .flatten .uniq .each{|url| system %Q[wget "#{url}"]}' <index.html
It mirrors whole archive of a certain webcomics. Now it Perl it would be:
perl -nle 'print $& for(m[http://www.\\?epDate=\d+-\d+-\d+])' <index.html | sort | uniq | perl -nle 'system qq[wget "$_"]'
It's a bit nicer in Ruby, not having to use external programs sort and uniq and without some of the Perl's line noise. So back to the baby pandas - Ruby is cute, baby pandas are cute, if you're still using C++ instead of some cute language you're hurting baby Pandas. You don't want to hurt baby Pandas, do you ?

Thursday, May 04, 2006

I've seen the rings.

Today I went to the Romanian-Bulgarian night at the MPI.

The programme: some PowerPoint presentations, and traditional dances, both of which I found rather boring. Then some guy who played traditional Romanian instrument and was really cool. Then the food (pretty good) and a Romanian commedy Filantropica (imdb 8.7).

However the coolest thing was the telescope ^_^. There's one on the roof of the MPI building, and Andrei Lintu gave a short show, not really related to either Romania or Bulgaria. So I've seen the Saturn's rings, finally. They're really cool. ^_^

Wednesday, May 03, 2006

Variant types in OCaml suck

So, here's the first of the promised long, boring, technical rants. My MSc thesis is a compiler for shaders written in the RenderMan Shading Language for SaarCOR hardware. Writing a compiler is a pretty straightforward task - gather some tests, write a hardware emulator, then a parser, a middle end, a code generator, then play with the components until they produce something satisfactory. Not much of a blogable material. The first issue however, choice of the programming language, was a bit interesting. The options I considered were:

  • Java + possibly some high-level JVM-targeted scripting language
  • OCaml, used very conservatively
  • OCaml, used with all the fancy stuff like variant types
  • Other functional language, like Common Lisp or Scheme
  • Some real high-level language like Ruby, Perl or Python
OCaml's (and SML's) static typing is usually way too annoying. The reason I decided to try OCaml anyway were all the fancy things that it has and the older MLs didn't, the stuff which supposedly makes coding much easier, like objects, variant types, camlp4 and so on. That was kinda the last chance I was giving it, not quite satisfied with OCaml, but not yet willing to abandon it. And the way the fancy features are implemented really sucks. Today, let's talk about suckiness of the variant types. Imagine there are two types, flt_temp = `FLT_TEMP of int (floating point temporaries), and vec_temp = `VEC_TEMP of int (vector temporaries). There is also a type any_temp = [flt_temp|vec_temp] for temporaries of either kind. So in contexts where only float temporaries are allowed (like division), flt_temp is used, in contexts where only vector temporaries are allowed (like dot products) - vec_temp, and in contexts where any temporary is ok (like function argument) - any_temp. So far so good, and a dumb wrappers like F of flt_temp|V of vec_temp wasn't needed to implement any_temp.
let any_temp_to_string : [<any_temp] -> string
= function
|`FLT_TEMP(x) -> sprintf "t%d:float" x
|`VEC_TEMP(x) -> sprintf "t%d:vector" x
Notice the <. It means that any subtype of any_temp can be argument of this function. So it's possible to run any_temp_to_string on any_temp, flt_temp or vec_temp values, what's a really nice improvement compared to the old MLs. However at this point you may be a little bit confused - why is < needed ? Isn't a value of type flt_temp/vec_temp also any_temp ? Now that's where we get to the suckiness part, because it's not and it needs an explicit typecast. Unfortunately the typecast often needs to be repeated many times, because OCaml will report a type error without even looking at our annotations: For example, one might have thought that the following would work:
let extract_used_temps : any_comp -> any_temp list = function
|`DIVISION(a, b) -> [a; b]
|`DOT_PRODUCT(a, b) -> [a; b]
But it won't. The "correct" rewrite is (extremely ugly and verbose):
let extract_used_temps : any_comp -> any_temp list = function
|`DIVISION(a, b) -> [(a :> any_temp); (b :> any_temp)]
|`DOT_PRODUCT(a, b) -> [(a :> any_temp); (b :> any_temp)]
A related issue is that polymorphic functions of type 'a->whatever get instantiated to any_temp->whatever, not [<any_temp]->whatever. So Hashtbl.find ht_of_any_temps some_flt_temp is going to fail unless we use (some_flt_temp :> any_temp). The "let's screw the type system" function Obj.magic (identity function of type 'a->'b) every here and there limits the typecast bloat a bit, but I've found that it helps in maybe 10% of cases, and of course then, if you make a typo, you end up with random segfaults (not even a nice runtime exception like in a dynamically typed language). In the 90% of cases there isn't really a way to use Obj.magic, mostly because it's applied too late, only after OCaml finds what it thinks is a type error. Now some statistics - the compiler itself at the moment has 4239 lines, and that includes 175 uses of :> and 32 uses of Obj.magic. It's so ugly :-/ So in the end the type system is mostly something to fight with, not something that helps, just like it was so often the case in plain OCaml/SML. So for the next project, I'll try something with fewer types. And I'll probably give up on OCaml. Oh, and I also had some problems with OCaml's object system, maybe I'll blog about it sometime later. ^_^

Hello, Kittens ^_^

This is going to be my new
blog. I suspect it will be full of long, boring, technical rants.

But that's not a good way to start a blog. I'm going to start with something nice and sweet, like ... kittens ^_^ (image from Cute Overload)

Oh, and here's a rant that convinced me to start this blog: Stevey's Why you should write blogs.