- General (18)
- Food (1)
- Cooking (1)
- Ruby (6)
- Rails (2)
- Svn (2)
- Linux (9)
- Git (1)
- Firefox (8)
- Porn (1)
- Freyja (1)
- Witchhammer (6)
- Music (1)
- Merb (3)
- Poetry (0)
- Bolverk (3)
- Sinatra (1)
- Discogs (1)
- Centos (1)
- Python (1)
- Whinging (2)
- Travel (2)
- Scheme (7)
- Lisp (8)
- Sicp (1)
- Rot13 (1)
- Czech (2)
- Metal (3)
- Passenger (1)
- Fun (5)
- Fractals (2)
- Plt (2)
- Clojure (1)
- Continuations (1)
- Presentation (1)
Travel update #1
I had planned to post these more often, but hey, I guess I've been busy with non-computery stuff for the first time in far too long.
At the moment I am in Thailand, in Krabi Town specifically, a small-ish city in the south. It's near Phuket (which I did not like, for the record).
I've been on the road for about a month now and have loved (nearly) every minute of it. The first few days were a little rough as it was at that point I truly realised I was alone in a very foreign place.
At this point, I've seen most of the country. There are still some spots in central Thailand that I'd like to check out, but that will have to happen another time. I think my favourite place so far has been Chiang Mai, the proverbial "capital of the North". It's an ancient city with a laid-back atmosphere. Tomorrow night I am catching the overnight train up to Bangkok, where I will spend a few more nights.
On the 29th of December, I am flying directly to Munich, Germany. From there I will try and see as much of Eastern Europe as possibly can in 20 days (without rushing too much, of course). My only guideline is that I will need to be in Amsterdam on the 18th of January. At this point I will be meeting my younger sister, Grace, with whom I will travel through some of Western Europe (The Netherlands, Belgium, France, Switzerland).
At this point, I am feeling glad that I decided to travel alone. This type of radical decision really helps you come out your shell. I've met a lot of really cool people from all over the world and experienced Thai culture in a way that a lot of package travellers would never get to see.
Until next time!
Time for an adventure (Angkor WHAT?!)
A few weeks ago, I booked a one-way ticket to Bangkok. I have a netbook, a backpack, malaria tablets, new shoes, and some books on LISP.
I am departing from Melbourne at 2:55pm on December 1st, 2009.
The plan (well, if I had one, this would be it) is to spend a few weeks in Thailand, and then transplant myself into Cambodia. After visiting all of the Wats (temples) and soaking in the atmosphere, I'll travel into Laos and lay back for a few weeks. I've heard there is a cool "river-tubing" activity near Vang Vieng, which sounds fun.
Next is the hustle-bustle of Vietnam! I've heard excellent things about this country, and really look forward to checking it out. My sister says she will fly over and meet me in Hanoi, which would be ultra badass!
After that, depending on my financial, physical and emotional state, I may well just keep going and catch a flight to somewhere in China. But who knows? By then I might be in Africa or South America...
I'll still be online regularly (where possible), so hopefully I can document some of my travels as I go. Wish me luck! :)
Running Linux processes as Daemons
Running an arbitrary process, such as a Python script, on your Linux box as a daemon is really quite simple if you have the right tools.
In my case, I had a simple Python socket server that needed to run permanently. Simply running it in the background (Ctrl-z) is no good as it would die the moment I logged off!
Enter daemon, a really handy tool for solving this exact problem.
Installation is easy. On Debian-based distros, you can just install it directly form aptitude. On CentOS, which uses yum, I had to install it from source. But I ran into no problems there.
Once installed, getting things running was easy:
$ daemon -r --name=myserver python /full/path/to/myserver.py
The "r" flag tells daemon to respawn itself if the service is killed. I've given it a name so I can refer to it later. And the rest of the line is the actual command I want to run.
To test if the process is still running, you can look in ps or pgrep, but the best way to do it is to simply ask daemon personally:
$ daemon -v --name=myserver --running
The "v" flag is for verbosity (of coarse). The "running" flag tell daemon that I want to know if the process specified by "name" is still running. The output you receive is simple to interpret, e.g: "myserver is running with PID: 23324".
To finally kill the process at some point in the future, you can issue the following command:
$ daemon -v --name=myserver --stop
And this one should be rather self-explanatory by now. :)
I've only grazed the surface here. Just check out the man page for an idea of how much more you can do with this. Good luck, muchachos!
Let me do it, Python!
Python is great. It's nearly at the top of my list of "most usable" programming languages.
But one thing annoys me. It's even been explained in detail, and it still annoys me!
Basically, the join() method is defined on the string class and not on the list/tuple class. Now, I admit, it's not really that big of a deal. It's hardly going to make me drop Python into the abyss of "tried, but shitty" languages.
When I was first learning Python, I knew that joining a list/array of strings on a specific delimiter would be part of the standard library. Here is what I tried:
["Balls", "to", "the", "walls"].join(", ")
But, no! Python makes me do this:
", ".join(["Balls", "to", "the", "walls"])
Eww! It's both backwards and ugly! Let me do it by way, Python! In Ruby, I could just duckpunch the hell out of the class and implement my own method. But thats another story...
The thing that bothers me the most is that you actually have to pass a list into the method. If the join method must be on string, then I should atleast be able to pass in an arbitrary number of arguments, like so:
", ".join("Balls", "to", "the", "walls")
I mean, Python does support optional arguments, after all. And if I have a list I want to join, I could just apply the list as arguments:
# Doesn't work... args = ["Balls", "to", "the", "walls"] ", ".join(*args)
One other thing that (slightly) bothers me is that it also forces me to pass in a list of string objects. Being dynamically-typed and very-high-level, I would have expected Python to forcfully stringify any non-string members of the supplied list.
", ".join(["Balls", 2, "the", "Walls"]) => ERROR!
C'mon, Python. You already give me the option of writing questionable code by allowing me to access private instance methods externally (Note: I've never done this).
ImageMagick and RMagick on Centos 5.3
Installing ImageMagick + RMagick seems to be a common source of problems. Here is my eventual solution.
I must admit, I'm not a huge fan of yum. And this latest experience has not helped my disposition. There is an ImageMagick(-devel) package in the repository, but it's very old now requires an earlier version of RMagick. I also found that it didn't work with the FileColumn Rails plugin ("Invalid image" error).
I recommend, for CentOS 5.x atleast, that you build ImageMagick from source.
0) Install all the dependencies (yum should be fine for these):
1) Grab ImageMagick and unpack it
$ wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz $ tar xvzf ImageMagick.tar.gz $ cd ImageMagick-x.x.x
2) Compile and install ImageMagick. Note, these are the flags I used for my own server. Use --help to see a full list of the options.
$ ./configure --prefix=/usr --disable-static --with-modules --without-magick-plus-plus --with-quantum-depth=8 $ make $ sudo make install
3) Play the waiting game. Or you can have a sword fight with an employee. :)
4) Install the latest version of the RMagick gem
$ sudo gem install rmagick
5) For good measure, open up IRB and see if it's installed correctly.
$ irb > require 'RMagick' > true
Good luck in your adventures, people.
Arguments for pair programming
A while ago I found myself in the position where I needed to convince my managers that Pair Programming was a worthwhile business investment. I was recommending the traditional approach, consisting of a "driver" and an "observer", who optionally switch roles at semi-constant intervals.
I was conscious enough to know that getting the actual benefits across clearly was important as the whole concept could easily be misconstrued to mean something along the lines of: "Hey! I want to sporadically wrap all of the production staff into neat little bundles of two".
Below are my no-bullshit reasons why, from my own experience, pair programming/designing/writing works well. Now, I should mention that your own mileage may vary. I've had occasions where peoples ego's (perhaps including my own) have got in the way -- but that's a whole different issue! Anyway:
- When working in two, people spend less time looking at forums, news and otherwise useless crap.
- Increases the Bus-Factor. That is, the number of people that need to be hit by buses before a substantial amount of domain knowledge is forever lost.
- If stuck on a problem, sometimes the best way to solve it is simply to ask someone to listen to you explain it (the answer becomes clear when you dictate the issue). This is a well-known phenomenon.
- When seeing each other work, staff can really gain an insight into how they spend their days and why they are an important asset.
- Staff can expand their skillset by observing each others experience and knowhow.
- Two minds are better than one when it comes to complex problem-solving.
- Bonding is always a plus.
Perhaps this list will help another cronie in convincing their managers of "pairings" effectiveness? Good luck.
A Ruby wrapper for the Discogs.com API
I recently noticed that Discogs.com, a huge discographies database, had released their API in the public domain. I think this is a really nice offering, especially considering effective use of the Ebay API can cost in excess of $50,000 per year...
Unfortunately, I couldn't really think of anything useful to do with the information. So instead I've spent the last few weeks writing a 100% Ruby wrapper for version 1.0 of the API. It abstracts all of the tedious work of handling requests/responses, parsing the XML, etc. This way, if someone else has a good idea (or I have one in the future), most of the work will already be done!
Anyway, enough of that. The specifics:
The library currently supports everything in version 1.0 of the API as documented (sort of) on the Discogs website. Namely:
- Searching (all of the above
I've setup the library as a gem so installation is as easy as:
$ gem sources -a http://gems.github.com $ sudo gem install buntine-discogs
Here is a small taste of what you can do:
require 'rubygems' require 'discogs' wrapper = Discogs::Wrapper.new("my_api_key") artist = wrapper.get_artist("Master's Hammer") release = wrapper.get_release("611973") # Supply an ID. artist.name # => Master's Hammer artist.releases.title # => Finished artist.releases.year # => 1989 artist.releases.extraartists # => [ "Arakain", "Debustrol" ] release.title # => "Ritual" release.labels.name # => "Osmose Productions" release.formats.descriptions # => "LP" release.styles # => [ "Black Metal", "Death Metal" ] release.tracklist.title # => "Pad modly"
Finding out more
I have setup the repository at github. Please let me know of any bugs/problems you find. I'm open to suggestions for improvement, also. Fork me!
On the wiki at github, I have setup a bunch of examples and some documentation for each resource.
Witchhammer 1.5 is out
I've just finished an upgrade to Witchhammer, my Firefox extension for finding information on the http://www.metal-archives.com database.
I've made the following changes:
- Added song search
- Implemented loading dialogue
- Cleaned up JS namespace pollution
- General code cleanup and refactor
Any feedback you may have would be greatly appreciated! :)
Programming Bolverk; a simple example
Since Bolverk has gone live, I've had a few friends mention to me that "[It] sounds like a cool idea, but I have no idea where to start". Because of this, I've decided a small example of how one might go about programming her is in order.
I will demonstrate how to read in two binary numbers, determine their sum, and then print that value to the standard output.
0: Write the machine instructions
Below is an example of how you could write the solution (along with notes in parentheses).
2143 (LOAD register 1 with the decimal value 67) 220D (LOAD register 2 with the decimal value 13) 5123 (ADD register 1 and register 2 and store the result in register 3) 33A1 (STORE the contents of register 3 into the memory cell A1) D1A1 (PRINT the contents of memory cell A1 as a decimal number -- 80) C000 (HALT the program)
1. Load the instructions into main memory.
Click the "Write / Load Program" link and wait for the thickbox dialog to load up. Once ready, copy the following into the textarea:
2143 220D 5123 33A1 D1A1 C000
The "Starting cell" select can be left as is. Now click "Insert". You will notice that the program has been loaded into main memory. The populated cells will appear purple.
Note, you can manually change any single memory cell by double clicking it, changing the hexadecimal value, and then clicking out of the cell.
2. Initialise the program.
Click on the first cell of your program. You will notice the "Initialize Program" button will be enabled. Click it.
You will notice that the first two cells of your program code will be highlighted. This, as the legend shows, is the next instruction the machine will execute.
3. Run the program.
This is the easy part. You simply have to click the "Machine Cycle" button for each machine instruction in your program. At each instruction, you will see how the processor is being affected.
Try it! By the time the program ends, you should have the decimal number "80" printed to Standard Output.
Introducing Bolverk: 8-bit Microprocessor Emulator
Over the past few weeks, I have been developing a fun little application in an attempt to broaden my knowledge of the way a processor works at a low level.
What I've come up with is a Web-based, 8-bit Microprocessor Emulator with it's own Machine Language implementation. It contains 2kb of memory and is programmable in Hexadecimal.
I tried to keep the process enjoyable and did not worry myself too much with the finicky details that would undoubtedly plague engineers implementing a "real" machine. I questioned myself so many times that, after a while, I began to simply ignore my inner, logical self and simply kept hacking away. So even though writing a program to perform 8-bit floating point arithmatic in a machine language implemented using an interpreted and dynamic language is, quite obviously, far beyond ridiculous, I still reached my goal of... well, I don't know... total schizophrenia?
The true usefulness of such an application lies in it's effectiveness as an educational tool. Recently, I was watching some of the excellent Richard Buckland lectures from the UNSW Comp. Sci. course and I noticed that they were actually using something quite similar. The emulator they were using was only 4-bit and contained just 16 bytes of memory, but the concept was almost identical. What a confidence boost!!
Any feedback, bug reports, comments -- please send me an email!