<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4288112407600774150</id><updated>2011-11-23T10:09:22.262+10:00</updated><category term='uname'/><category term='Syntaxhighlighting'/><category term='JPA'/><category term='Plugins'/><category term='ubuntu 11.04'/><category term='Algebraic Data Types'/><category term='DNS'/><category term='Vision'/><category term='Hibernate'/><category term='how to'/><category term='Instinct'/><category term='Windows'/><category term='Either'/><category term='sendmsg'/><category term='Firestarter'/><category term='Jaunty'/><category term='firefox'/><category term='Ghosting'/><category term='VPN'/><category term='No Machine'/><category term='TDD'/><category term='Mac'/><category term='Start'/><category term='functor'/><category term='Error'/><category term='Display Drivers'/><category term='Traits'/><category term='raid'/><category term='Ensime'/><category term='work'/><category term='Wireless Apple Keyboard Vista'/><category term='SB X-fi'/><category term='Plugin'/><category term='SSH'/><category term='Euler'/><category term='CSS'/><category term='Intellij'/><category term='Subversion'/><category term='security'/><category term='Gmail'/><category term='sbt'/><category term='Windows Media Center'/><category term='companion'/><category term='Fiesty'/><category term='NAT'/><category term='Vim'/><category term='NFS'/><category term='JDK'/><category term='Agile'/><category term='Edgy'/><category term='Eclipse'/><category term='semigroup'/><category term='Partial Implementation'/><category term='x1950 Pro'/><category term='Emacs'/><category term='VNC'/><category term='Ubuntu 8.10'/><category term='Exceptions'/><category term='OS'/><category term='Google Maps'/><category term='Vista'/><category term='VPNC'/><category term='Subversion  1.5'/><category term='web start'/><category term='lessons'/><category term='File System'/><category term='cache'/><category term='Bigpond'/><category term='Samba'/><category term='VirtualBox'/><category term='JNLP'/><category term='Tutorial'/><category term='vol_id'/><category term='Firewall'/><category term='lshw'/><category term='IDE'/><category term='Pondskum'/><category term='Router'/><category term='/etc/exports'/><category term='1680x1050'/><category term='Version'/><category term='Scala'/><category term='degraded'/><category term='Veitch Lister Consulting'/><category term='opensource'/><category term='BDD'/><category term='Ubuntu 8.0.4'/><category term='GridGain'/><category term='Resolution'/><category term='Spring 2.5.2'/><category term='functional concepts'/><category term='Internet Usage'/><category term='Remote Clients'/><category term='hashCode'/><category term='DVD'/><category term='Deploy'/><category term='Pair Programming'/><category term='Problem'/><category term='Parted'/><category term='Wacky'/><category term='anongid'/><category term='boot'/><category term='Lift'/><category term='Share'/><category term='JRE'/><category term='anonuid'/><category term='Play from HDD'/><category term='Broken'/><category term='Java'/><category term='Apple Keyboard'/><category term='Abstract Data Types. Pattern Matching'/><category term='share folder'/><category term='Welcome'/><category term='Function Keys'/><category term='tests'/><category term='jobs'/><category term='Googlecode'/><category term='Install'/><category term='lsb_release'/><category term='Maven'/><category term='Linux'/><category term='ATI'/><category term='Subclipse'/><category term='Update'/><category term='Ubuntu'/><category term='Grid'/><category term='Karmic'/><category term='iptables'/><category term='Enum'/><category term='SVN'/><category term='Ubuntu 9.0.4'/><category term='Sparse Checkout'/><category term='equals'/><title type='text'>Babylon Candle</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>55</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4126798142290415173</id><published>2011-11-22T14:47:00.020+10:00</published><updated>2011-11-23T10:09:22.430+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Firewall'/><category scheme='http://www.blogger.com/atom/ns#' term='iptables'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu 11.04'/><title type='text'>Firewall configuration with iptables</title><content type='html'>Recently I had the seemingly "daunting" task of adding firewall rules through the iptables command. Here are some of my findings.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Basic Commands&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To list your current firewall configuration use:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1387262.js?file=list_iptable_rules.sh"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;If you have no rules in your iptables you should see something like this:&lt;/div&gt;&lt;script src="https://gist.github.com/1387244.js?file=firewall_with_no_rules.txt"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;To add a rule to a chain use:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387262.js?file=add_iptable_rule.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To delete a rule on a chain use:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387262.js?file=delete_iptable_rule.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Make sure your firewall INPUT chain policy is set to ACCEPT not DROP.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Add some basic rules to the INPUT chain:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387262.js?file=common_iptable_rules.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The above rules allow  SSH, DNS, HTTP and HTTPS traffic. It also logs any requests that have not been satisfied by any of the rules to your syslog. We have also blocked all other traffic and ports. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;List your  iptable rules with:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1387262.js?file=list_iptable_rules.sh"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Your iptables should look similar to this:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1387244.js?file=firewall_with_rules.txt"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For some reason if I leave out the first rule, none of the others work. I presume this has to do with connections coming in on known ports but negotiating on to other ports once a connection is established.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The DROP policy for the INPUT chain drops all traffic to ports other than those specified in your rules. If there's no rule, it's not getting through.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also of note is that rules are evaluated top-down with the first matching rule executed. Thus if you have a rule that drops traffic for a certain port followed by one that allows traffic for the same port, all traffic will be dropped.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Given the above, if you need to insert a rule at a particular line do so with the following:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1387262.js?file=insert_rule_into_iptable.sh"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Make sure you verify that all the programs you need are allowed through the firewall. If needed you can change the policy of the INPUT chain back to an ACCEPT policy like so: &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387262.js?file=roll_back_iptable_drop.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing to note is that if you are some way locked out of your system due to the above rules, a simple reboot will remove all entries.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Save and Restoring Rules&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As iptable rules are not saved and restored by default you  need to it manually.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1.  Save your current changes:&lt;/div&gt;&lt;script src="https://gist.github.com/1387300.js?file=save_iptables_through_sh.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2. Create the file /etc/network/if-pre-up.d/iptablesload This will be run just before your network interfaces are brought up. Add the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387262.js?file=iptablesload.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;make it executable with:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387300.js?file=add_execute_rights_to_load.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3. Create the file /etc/network/if-post-down.d/iptablessave. This will be run just after your network interfaces are brought down. Add the following:&lt;/div&gt;&lt;script src="https://gist.github.com/1387262.js?file=iptablessave.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;make it executable with:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387300.js?file=add_execute_rights_to_save.sh"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now when you restart your machine your iptables will be saved and restored. You can have a look at the rules that are persisted by looking at the /etc/iptables.rules file:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1387300.js?file=view_exported_iptables.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Your /etc/iptable.rules file should look something like this:&lt;/div&gt;&lt;script src="https://gist.github.com/1387244.js?file=sample_iptables.rules.txt"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Comments/suggestions are welcome. :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Links: &lt;a href="https://help.ubuntu.com/community/IptablesHowTo"&gt;1&lt;/a&gt; &lt;a href="http://www.sshguard.net/docs/setup/firewall/netfilter-iptables/"&gt;2&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4126798142290415173?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4126798142290415173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4126798142290415173' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4126798142290415173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4126798142290415173'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2011/11/firewall-configuration-with-iptables.html' title='Firewall configuration with iptables'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5227770131967324221</id><published>2011-04-06T16:39:00.009+10:00</published><updated>2011-04-06T18:26:50.504+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='sbt'/><category scheme='http://www.blogger.com/atom/ns#' term='Ensime'/><category scheme='http://www.blogger.com/atom/ns#' term='Emacs'/><title type='text'>Ensime with Emacs</title><content type='html'>I've been toying with the idea of looking for an alternative to Intellij for Scala development for a while now. I tried to use &lt;a href="https://github.com/aemoncannon/ensime"&gt;Ensime&lt;/a&gt; with Emacs a few months ago and never got it going for one reason or another. More recently, I've got Ensime and Emacs working together and thought I'd blog about it for anyone else who had trouble getting everything to work together.&lt;br /&gt;&lt;br /&gt;Here are the minimum requrements as stated on the &lt;a href="http://aemon.com/file_dump/ensime_manual.html"&gt;Ensime user manual&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;1.Unix(y) or Windows OS&lt;/li&gt;&lt;br /&gt;2.JVM Version 6&lt;/li&gt;&lt;br /&gt;3.Scala 2.8.1 compatible source and libraries&lt;/li&gt;&lt;br /&gt;4.Emacs 22 or later (23 is recommended)&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;H2&gt;Configuring Emacs for Scala&lt;/H2&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. Ensure you have a working installation of scala 2.8.1final.&lt;br /&gt;&lt;br /&gt;2. Install emacs. On Ubuntu you can do this with&lt;br /&gt;&lt;br /&gt;&lt;B&gt;sudo apt-get install emacs&lt;/B&gt;&lt;br /&gt;&lt;br /&gt;and on the Mac you can:&lt;br /&gt;&lt;br /&gt;&lt;B&gt;brew install emacs&lt;/B&gt;&lt;br /&gt;&lt;br /&gt;Ensure you have at least version 22 or later.&lt;br /&gt;&lt;br /&gt;3. Go to your scala_installation_dir/misc/scala-tool-support/emacs/ directory. Copy all .el, .elc files and the Makefile into a location where you want to store these files.&lt;br /&gt;&lt;br /&gt;Eg. ~/scalaemacs&lt;br /&gt;&lt;br /&gt;4. Copy the contrib/dot-ctags file to your ~/.ctags file&lt;br /&gt;&lt;br /&gt;5. Using a command shell, cd to the above directory and run "make" to convert the .el files to .elc files.&lt;br /&gt;&lt;br /&gt;6. Add the following to your ~/.emacs file:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/905263.js?file=gistfile4.sls"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;eg.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/905263.js?file=gistfile3.sls"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;You may need to create this file if it does not exist.&lt;br /&gt;&lt;br /&gt;7. Open a .scala file in emacs to verify syntax highlighting works and other basic scala functionality works.&lt;br /&gt;&lt;br /&gt;&lt;H2&gt;Installing Ensime&lt;/H2&gt;&lt;br /&gt;&lt;br /&gt;1. Ensime can be downloaded from &lt;a href="https://github.com/aemoncannon/ensime/downloads"&gt;here&lt;/a&gt;. Download the latest version. The current version is -&gt; ensime_2.8.1-0.5.0.tar.gz&lt;br /&gt;&lt;br /&gt;2. Extract the archive downloaded to a know location. This will be your ENSIME_ROOT.&lt;br /&gt;&lt;br /&gt;Eg. ~/opt/ensime&lt;br /&gt;&lt;br /&gt;3. Verify that the ENSIME_ROOT/bin/server.sh file has execute permissions.&lt;br /&gt;&lt;br /&gt;4. Add the following to your ~/.emacs file substituting ENSIME_ROOT for where you extracted the archive:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/905263.js?file=gistfile1.sls"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Your complete .emacs files should look something like:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/905263.js?file=gistfile2.sls"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;H2&gt;Creating a Project with SBT&lt;/H2&gt;&lt;br /&gt;&lt;br /&gt;You need to create an Ensime project for each project you want to use with Ensime. The project details are written to a .ensime file in your project root. Ensime currently has support for SBT, Maven and Ivy. If you don't have a build system you can also generate a .ensime file through the wizard or by hand.&lt;br /&gt;&lt;br /&gt;The following is how to create a project for an existing SBT project:&lt;br /&gt;&lt;br /&gt;1. Launch emacs&lt;br /&gt;2. Type M-x to open the mini-buffer and then type: &lt;b&gt;ensime-generate-ensime-config-gen&lt;/b&gt;. &lt;br /&gt;A note on the Meta key (or M-) combinations: On linux M-x is Alt+x, while on the Mac it's Esc+x. Play around until you find which meta key is used on your flavour of OS.&lt;br /&gt;3. Specify the root of your project. &lt;br /&gt;4. If your project is an SBT project, it automatically detects most settings and you should see a message like:&lt;br /&gt;"Your project seems to be of type 'sbt', continue with this assumption? (yes or no)". Choose yes.&lt;br /&gt;5. Enter all the other information requested.&lt;br /&gt;6. At the end you will see something like "Your project config has been written to /xyz/.ensime. Use 'M-x ensime' to launch ENSIME." Your ensime file has been written and you are ready to use ensime.&lt;br /&gt;7. Type M-x and in the mini-buffer type: &lt;b&gt;ensime&lt;/b&gt; to launch the Ensime server for your project. Reconfirm the location of your project.&lt;br /&gt;8. That's it! :)&lt;br /&gt;&lt;br /&gt;&lt;H2&gt;Neat Features&lt;/H2&gt;&lt;br /&gt;&lt;br /&gt;1. Type inspection - will dive into details of the type at the cursor&lt;br /&gt;2. Automatic member completion (eg. typing "blah". followed by the Tab key will give you a list of the methods on String.&lt;br /&gt;3. Navigation between sources&lt;br /&gt;4. Refactoring (Renaming, Optimizing imports etc)&lt;br /&gt;5. Source formatting&lt;br /&gt;6. SBT support&lt;br /&gt;7. Dropping files into the Scala REPL&lt;br /&gt;8. Debugging (I haven't had much luck getting this to work)&lt;br /&gt;&lt;br /&gt;For a full list have a look at the online &lt;a href="http://aemon.com/file_dump/ensime_manual.html"&gt;Ensime user manual&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://github.com/ssanj/Blog/raw/master/ensimeWithEmacs/EnsimeAutoComplete.png" width="640" height="480"/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5227770131967324221?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5227770131967324221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5227770131967324221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5227770131967324221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5227770131967324221'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2011/04/ensime-with-emacs.html' title='Ensime with Emacs'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6636300637852809599</id><published>2011-02-16T12:24:00.024+10:00</published><updated>2011-02-17T09:40:52.211+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='functor'/><category scheme='http://www.blogger.com/atom/ns#' term='functional concepts'/><title type='text'>Functor</title><content type='html'>&lt;h2&gt;What is a Functor?&lt;/h2&gt;&lt;br /&gt;Chances are you've already used a Functor. You probably use it everyday irrespective of the language you use.&lt;br /&gt;Paraphrasing &lt;a href="http://www.haskell.org/haskellwiki/Typeclassopedia"&gt;Typeclassopedia&lt;/a&gt;: "A Functor represent a container of some sort with the ability to apply a function uniformly to every element of that container".&lt;br /&gt;&lt;br /&gt;Say we had a List of words and we wanted to find out the lengths of each of those words. We would use a List[String], find the length of each String and get a List[Int] in return.&lt;br /&gt;&lt;br /&gt;In scala we could do something like:&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=MappingOverList.scala"&gt;&lt;/script&gt;&lt;br /&gt;We applied the length function to each element of the List "container". What has also happened is that a List[String] has been converted to a List[Int]. We started with a List of words and we end up with a List of word-lengths.&lt;br /&gt;&lt;br /&gt;Functors operate on type constructors - which are types that need additional types parameters to be constructed. List[T], Map[K, V], Option[T] and Either[L,R] etc are all type constructors as they need one or more types to be constructed.&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830563.js?file=ListTypeConstructor.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;A functor can be defined as:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=FunctorTrait.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Assuming the F type constructor was List, the above trait could be implemented as:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=ListFunctor.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;All Functor implementations traverse over the type supplied and apply the function f, to each element within that type. In the case of List, f is applied to each element of the List.&lt;br /&gt;&lt;br /&gt;We could use the ListFunctor as:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=UsingListFunctor.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;This gives us the same results as before, but we've abstracted over the List type constructor and we can covert from List[A] -&gt; List[B] where A and B are any types.&lt;br /&gt;&lt;br /&gt;Import points to note are:&lt;br /&gt;&lt;br /&gt;1. The container remains the same (F or in the above case List)&lt;br /&gt;2. The supplied function f, works on the value contained within the container.&lt;br /&gt;&lt;br /&gt;As per &lt;a href="http://www.haskell.org/haskellwiki/Typeclassopedia"&gt;Typeclassopedia&lt;/a&gt;: "fmap applies a function to each element of the container without altering the structure of the container"&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Some Examples&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Let's create our own type constructor to hold a single value. Let's call it Holder:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=Holder.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Now let's define a Functor for Holder:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=HolderFunctor.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Here's how we use it:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=UsingHolderFunctor.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;We converted a Holder[Int] -&gt; Holder[String] by mapping across the value in the Holder.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Functor Laws&lt;/h2&gt;&lt;br /&gt;There are 2 Functor laws:&lt;br /&gt;&lt;br /&gt;1. mapping with identity over every item in a container has no effect&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=FunctorLaw1.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;2. mapping a composition of two functions over any item in a container is the same as mapping the first function and then mapping the second.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=FunctorLaw2.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Let's see if HolderFunctor obeys these 2 laws:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=HolderFunctorObeyingLaws.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Looks like it does obey both laws. :)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Why use Functors?&lt;/h2&gt;&lt;br /&gt;So here's the real question: Why use Functors? By defining Functors for each container you are interested in, you could define a single function that fmaps across any container containing any type:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=OneFmapToRuleThemAll.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Let's try and call it with Holder:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=FailedHolderWithFmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Let's create an implicit Functor[Holder]:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=HolderPassesfmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Let's try and use it with Functor[List]:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=ListFailsWithfmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Let's create an implicit Functor[List]:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=ListPassesWithfmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;What if we want to use it with Option? We simply create an implicit Functor[Option]:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=OptionImplicitForfmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;We can now call fmap with Option:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=OptionPassesWithfmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Verifying the laws for Functor[Option]:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=OptionFunctorObeysLaws.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;We could further simplify fmap as:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/830536.js?file=Shorterfmap.scala"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Functor has allowed us to define a single fmap function to map across any container for any value type! :)&lt;br /&gt;&lt;br /&gt;Here's a listing of the snippets:&lt;br /&gt;&lt;script src="https://gist.github.com/830474.js?file=Functor.scala"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6636300637852809599?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6636300637852809599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6636300637852809599' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6636300637852809599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6636300637852809599'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2011/02/functor.html' title='Functor'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-1035392402630537959</id><published>2011-02-02T08:47:00.003+10:00</published><updated>2011-02-02T08:57:00.774+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='raid'/><category scheme='http://www.blogger.com/atom/ns#' term='degraded'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='boot'/><title type='text'>Linux RAID Failed on Boot</title><content type='html'>After upgrading from Ubuntu 10.04 to 10.10 I noticed that my machine refused to startup on most occasions. After a few reboots it eventually decided to startup. I am running a raid0 setup which includes the boot partition.&lt;br /&gt;&lt;br /&gt;I got an error stating that "one or more raid devices were degraded". &lt;br /&gt;&lt;br /&gt;The solution turned out to be a simple one. It turned out that one of the HDDs in the raid array took a longer time to spin up than the others. This difference only became apparent in Ubutun 10.10.&lt;br /&gt;&lt;br /&gt;The fix is to add a rootdelay parameter to your /etc/default/grub file and update grub.&lt;br /&gt;&lt;br /&gt;Edit your /etc/default/grub file and update the following line to include a rootdelay:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;GRUB_CMDLINE_LINUX_DEFAULT="rootdelay=90" &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You might need to increase your root delay if it still occurs after the above fix.&lt;br /&gt;&lt;br /&gt;Update grub with&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo update-grub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and you should be all good! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-1035392402630537959?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/1035392402630537959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=1035392402630537959' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1035392402630537959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1035392402630537959'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2011/02/linux-raid-failed-on-boot.html' title='Linux RAID Failed on Boot'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5585085753894192707</id><published>2010-12-16T22:07:00.036+10:00</published><updated>2011-01-06T09:09:21.336+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lessons'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='jobs'/><title type='text'>Lessons learned</title><content type='html'>&lt;div style="text-align: justify;"&gt;I have worked at a number of companies over the last few years. All of them start off looking good but most fall into the "I wish I hadn't wasted x years/months of my life here". "How did this happen again?" I've wondered. I naturally missed the early warning signs which I should have heeded. I've chosen to document some of the most frequent occurring warning signs and lessons learned in the hope of reminding myself to steer clear of certain Companies. I also hope that my lessons will aid you in not repeating them.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Ask better interview questions&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Most developers never ask a prospective employer any useful questions. We might ask about technology. We might ask about the problem being solved. We negotiate salary. Rarely have I heard a developer ask more than that. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;The interview is the best place to weed out jobs that are going to suck later. Just like in Kanban a problem is a lot easier to fix at the source of the problem rather than further down the process chain.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Here are some practical questions to ask:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;1. Ask questions about the methodology. What happens when there are changes? What happens when new requirements are added? How are stories estimated? Who estimates them? How many stories were not implemented in the last couple of iterations?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;2. Ask about the development process. This would include TDD, pair programming, integration testing, build systems,  CI, the process by which artifacts are moved to production.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;3. The technical interviewer is likely to be one of the more skilled members of the team. Find out about any technical books he is reading, opensource contributions, any new languages and frameworks he is using/learning and any conferences he has attended in the last few years. Is he constantly improving?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;4. Find out how the position you are applying for became available. Are lots of people leaving the Company?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;5. Ask about some of the technical challenges they currently face. Then ask about some solutions they have in place.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;6. Ask about some improvements they have made between the last few iterations.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;7. Ask them what the biggest hurdle to productivity is at the moment.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Don't be afraid not to accept a job, if you feel that the answers to some of the above are sketchy. It's easier to walk away now.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;During one job interview, the technical teamlead mentioned things like: "40 developers have worked on the codebase in the last 4 years - and it shows", "I'm struggling to get the number of unit tests into double digits" and "the project is 4 years late but we will deliver it in 2 months". And both the teamlead and the team manager were only hired 2 months ago. Their predecessors had left the building. Needless to say I turned down this "amazing" offer much to the surprise of the hiring team.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Scrutinize the leader&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;The leaders of a company set the tone for everyone else. Who is a "leader"? It could be the CEO, the founder or even your manager. Have a good look at these people. They determine the ethos and care-factor of everyone around you.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;An example is where I was interviewed by a CEO of a small IT Services' Company.  He referred to his technical resources as "Nerds" and went on to say that he didn't know anything about Computers. He was also proud to say "We are not Google. We don't want to be anything like Google" and "We build Software. We are not building Rocket ships to the moon!". I should have run to the door and never looked back. Instead I proved to myself over the next few months that I should have indeed made that sprint when I could.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Here's what I should have learned from the above interview:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;1. When CEO stated that he didn't know anything about Computers, he admitted that he knew nothing about the industry in which his Company was operating! Why was he running an IT company?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;2. By calling people who understood his business "Nerds" he was happy to distance himself from the actual employees doing the work that made his Company money. He was also happy to be derogatory to a potential new hire and thought nothing of it.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;3. He obviously didn't understand the complexities of Software. He assumed developing Software was easy. No big deal. Anyone who has worked in Software for more than 2 minutes knows different. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;It's hard to escape from this kind of cluelessness. The CEO's attitude directly affects higher management. He continues to hire clueless people to run his project teams and they in turn hire clueless people to manage you and your team! Talk about a vicious cycle. When it all goes to pot (and it will) the "Nerds" aka you and I, get the blame. Needless to say the project I was on was in dire straits. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Standup for yourself&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;We've all worked at a Company where they want you to "hit the ground running".  A friend of mine joined the Company I was working at. He was tasked with taking over the work of an experienced programmer who have been working on some secret squirrel project for the last few months. "Don't waste your time writing any tests" he had been told. He was a contractor. The Company had mishandled his contract and he had rightly found greener pastures. My friend was tasked with delivering the contractor's work in 3 days. He didn't have his computer set up. He had just walked in the door and he was already on a suicide mission. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;My friend rightly said "No. I can't do it. I don't have the domain knowledge to get this done in 3 days". Pretty obvious and he didn't even have a working machine! He was met with resistance from the project manager. "Why not try?". But my friend rightly stuck to his guns and said "No. I can't do it. Get someone more experienced with the System to do it". After quite a lot of deliberating the project manager reluctantly agreed to shelve the changes and give it to someone else. "Wow!" I thought. It was refreshing to see someone standup for themselves. I myself might have "tried". I would have tried to get everything working as fast as possible. I would have had to cut corners. I would have worked late. Most heinously, I would have reinforced the fact that giving developers unachievable, impossible tasks was okay. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;At another workplace I was repeatedly asked to work the whole weekend. The request came at 4pm on a Friday arvo just as I was leaving the building. I gave a polite "Sorry! Had you only told me earlier.  I have plans" and walked off. The next week, the same thing happens. Around 4pm the same question. The same answer. It really didn't stop them asking and it didn't stop me giving them a flat "No".  Had I been asked earlier I would have at least considered working the weekend.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;It's all about respect. Obviously someone thinks it's fine to ask employees to sacrifice their entire weekend at the very last moment - for cash. Like people can be bought and used at will. This also goes to show the great planning around this project.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Rarely have I seen any developers standing up for themselves. We need to do it more and not accept the unrealistic expectations and pressure put on us. We need to be more professional. The more we do this, the better it is for us as a group of professionals. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Keep away from unethical people&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Some Companies are happy to take large sums of their Customers' money and return utter crap in return. Testing is overlooked, shortcuts are taken. Everything is held together by ribbons. At one Company I worked at they were using their Customer as "first-level testing". Hilarious! This too after charging them a lot of money for the privilege of using their crappy excuse for a product.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;If a Company doesn't care about its Customers who give them loads of money, the chances of them caring about you, a lowly developer, are pretty close to zero. You are just someone else to be exploited. They think getting paid for delivering rubbish Software is okay. No moral issues there. Your cheese has been moved.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Use short contracts/probation to your advantage&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Contractors are always after long contracts. Permies are always trying to signup for a lifetime at a Company. I think this is all backwards. When contracting I would prefer a weekly contract. Let me tell you why. If the company I'm working at turns out to be a stinking hellhole (and some of them do) the fact that I am only a week-away from getting outa there fills me with hope. Imagine walking into a nightmare workplace and being stuck there for 6 months! Worse - a year! Oh the horror! No amount of money is worth working at some Companies. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;One Company I worked at seemed quite normal when I started but a few days into it, it turned out that employees of the Company thought that swearing at each other across the room, daily, was an acceptable way to behave. There were 3 developers always going at it. They were called "The Triangle of Anger". Oh dear! Also it turned out that  the management hated the developers and the developers hated the management. With this blood-feud going on I was put on a "mission critical project" by myself and was managed by 5 people - each telling me something different to do! People were leaving the Company left-right-and-centre. There were talks about firing everyone and outsourcing it to another Company. Morale was pretty high as you can imagine! Oh the fun! :)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;The same goes for probationary periods for permies. For the first time ever I refused to sign my post-probationary documents. If you find a Company less than optimal to work for during your probation, it's quite likely it's only going to get worse once you sign up fulltime. Here's why: Once you are post-probation, you usually have to give the Company 4 weeks' notice. Try finding another job where they are willing to wait 4 weeks until you finish up at your Company. It's really quite hard. Most jobs need to be filled in under a month. Most of them in 2 weeks. This is just the way Companies seem to work in Brisbane. They only look for developers at the very moment that they need them. Not a (few) month(s) before. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;If you are not sure about a Company, start looking for work a  month before your probation runs out. That way you usually only need to give a weeks' notice before you head off.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Beware of Amatures&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;We are all Amatures in one way or another. What I mean by that is that we all have things we don't know. There are always people who know more about something than we do. The features of who I consider to be an "Amature" are given below:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. Refuses to write tests because "there is no time".&lt;/div&gt;&lt;div&gt;2. Hasn't learned a single new API or language or framework or tool since 2004.&lt;/div&gt;&lt;div&gt;3. Is literally scared to upgrade libraries as it may "break something".  "I can't move to Junit4, as the world will implode".&lt;/div&gt;&lt;div&gt;4. Doesn't understand generics. "I like a List that can hold anything. It's more flexible."&lt;/div&gt;&lt;div&gt;5. Prefers XML over annotations because they are more "readable".&lt;/div&gt;&lt;div&gt;6. Thinks that writing Class names into a database table is "all good".&lt;/div&gt;&lt;div&gt;7. Writes 1000 line classes and says "It's good because all the code I need is in one place".&lt;/div&gt;&lt;div&gt;8. Hates TDD because "There is no way you can write tests before you write code".&lt;/div&gt;&lt;div&gt;9. Hates pair programming because it is a "waste of time".&lt;/div&gt;&lt;div&gt;10. Thinks writing hard-to-understand-idiotic-code is macho.&lt;/div&gt;&lt;div&gt;11. Doesn't know the difference between a Unit test and an Integration test.&lt;/div&gt;&lt;div&gt;12. Thinks test isolation is "optional".&lt;/div&gt;&lt;div&gt;13. Doesn't know how to use their IDE.&lt;/div&gt;&lt;div&gt;14. Thinks there is nothing wrong with a 6-hour build.&lt;/div&gt;&lt;div&gt;15. Is afraid of using mocks as "they are too hard to understand".&lt;/div&gt;&lt;div&gt;16. Refuses to use code style such as checkstyle on the source.&lt;/div&gt;&lt;div&gt;17. Refuses to run tests before checking in their code and thereby breaking the build.&lt;/div&gt;&lt;div&gt;18. Thinks that taking 5 days to write 600 lines of mock code to test a Class is fine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I don't have a problem with people who have the qualities listed above. I  do have a problem with people who have the qualities above and who refuse to change. What this means is that  it is now 10x harder for you to do a good job as you have constantly fight these "Amatures". They will waste your time and drag you down. Unless you can make a change for the better with these guys there is absolutely no reason to keep working in that same team. Leave while you still can!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;The myth of Agile&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;I'm totally over every single Company I work for claiming to be "Agile". It's just another buzz word to them. "Oh yes! We are Agile! We have x week iterations". What they mean by Agile is:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;1. The Software is evaluated at fixed time frame. Usually 2 weeks to a month. (So far so good)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;2. The business gets to change their mind every single day. No re-evaluation of the story cards is done.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;3. The developers are never consulted for estimation of the story cards or an architect-type is consulted to give estimates for each card (fairly useful since he doesn't implement a single card!)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;4. The business expects all their updated changes at the end of the iteration. No excuses! We are "Agile".&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;5. Testing is optional.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;6. There is no acceptance criteria on the story cards - which is good since nothing is accepted!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Most of the time there are no story cards. Just vague requirements that change on a daily basis. When retrospectives are done, all the ideas are just written down and improvements never get implemented. Each retro turns into ground hog day with most people just falling asleep. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Iteration opens follow a similar path with too much work assigned in each iteration as they did the iterations before. The lights are on but nobody's home. &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;Some have requirements' documents that they've been working on for 6 months! Waterfall anyone? But no. They are "Agile". They know what they are doing. As the projects start to fail they blame the developers and the "Agile" process.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"&gt;This is such a scam that I am going to ask people real questions about their processes to figure out whether they actually know anything about being "Agile". Don't be fooled by Companies being "Agile". Most aren't. If you are not sure ask them some pointed questions.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Foster good habits&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;We are all creatures of habit. If you get used to not writing tests then you start to think that not testing your code is fine. If you get used to working in a waterfall methodology, you see nothing wrong with long feedback times and reams of documentation. If get used to tip-toeing around broken builds/tests/deployments then you will think automation is too hard. In everything you do try and do the best job you can.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some habits to foster:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1.  Always write tests for the code you are producing - preferably TDD. If there are no tests - write the tests first then start on your work.&lt;/div&gt;&lt;div&gt;2. If the build is not automated then automate it. It will save the team hours of pain immediately.&lt;/div&gt;&lt;div&gt;3. If there aren't story cards/requirements - do not start work. Write the story cards and acceptance criteria and then estimate it. If you can't do it, get someone with the knowledge to do it. Then start work.&lt;/div&gt;&lt;div&gt;4. If you see quicksand code (code that sucks you in and threatens your life) refactor it! It will not only make the code cleaner but it will increase your understanding of the system. See 1.&lt;/div&gt;&lt;div&gt;5. Don't write an integration test for a piece of code that can be tested thoroughly at the unit level.&lt;/div&gt;&lt;div&gt;6. Run code coverage on any code you write - even if the rest of the team isn't.&lt;/div&gt;&lt;div&gt;7. Run checkstyle or a similar tool to ensure consistent formatting.&lt;/div&gt;&lt;div&gt;8. Write many cohesive small classes. Do this specially if all the other classes are 1000s of lines long.&lt;/div&gt;&lt;div&gt;9. Say "NO" to unrealistic deadlines, features and requests.&lt;/div&gt;&lt;div&gt;10. Where possible try to introduce better processes where you see better alternatives.&lt;/div&gt;&lt;div&gt;11. Check in often - more than a couple of times a day.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Even if the organization you are in is not working in  a professional way, that's no excuse for you not to. &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;As developers we need to have a baseline environment before we start writing code. If this baseline does not exist then our first priority should be to establish this baseline - with approval of course. We should not start work no matter how much of a hurry the Customer is in, if this baseline environment does not exist. This is the bare minimum we need to do a professional job. An example would be having a stable development environment, version control, automating the build, having a CI server,  etc. First things first.&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Know when to leave&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I think we all know whether a Company is good to work at, in under a week. Sometimes you want to give the Company a chance to make improvements. "We are not perfect" they might say. Fair enough. But set a deadline for when some of the improvements should happen by. Most of the time none of the changes proposed are implemented. This might be your signal to leave.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Sometimes it's an external event that signals you to leave. It could be the way the Company treats a certain employee. It could be the way they treat their Customer. It could be the way they treat you. You might notice quite a few people resigning every week (they might know something you don't). It might just be that you have nothing left to learn in the Company and everyday you stay there you lose a little more skill - a little more enthusiasm.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;In a Company I worked at a number of years ago, I specifically mentioned that I didn't want to do any form of teamleadership. I wanted to be a developer and that was it. Everyone nodded at the time. Just after my probation had ended, I was thrust into a teamlead position I did not want. There was no choice about it! The eventual result was that I resigned at the end of that project. I didn't want to work for Company where people didn't understand boundaries or English.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;At a more recent job, a group of us were coming up with changes to make the broken development processes better. We wanted to ensure the project made it over the line and the customer got a decent product. The outcome was a disciplinary email from the then manager warning each of use to "Stop wasting time" and to "get back to work". He didn't care if the project made or not. All he cared about was how it looked. Us coming up with heaps of changes meant that he looked bad and he had to put a stop to that. The unfortunate thing was that this "shutup and work" attitude was supported by upper management. The last thing I wanted to do was work at a Company where progress was not valued and where voices where drowned out by clarion call of authority. I resigned the next day.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I hope some of the above anecdotes have resonated with you. I am really shocked at how immature the Software industry really is. Imagine telling a builder that you need a building 3 months early. Or imagine changing your mind about whether you want a one or two story house mid way.  It's not going to happen is it?&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;We get these kinds of change requests all the time in Software and we are happy to do it. We need to have better boundaries! &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'll start this experiment with me..... let's see how many jobs I get to keep after that! :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5585085753894192707?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5585085753894192707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5585085753894192707' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5585085753894192707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5585085753894192707'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2010/12/lessons-learned.html' title='Lessons learned'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4617653893827299226</id><published>2010-09-29T20:17:00.012+10:00</published><updated>2010-09-29T21:37:06.280+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Lift'/><category scheme='http://www.blogger.com/atom/ns#' term='sbt'/><title type='text'>Hello World Lift</title><content type='html'>Recently I've been trying to get into &lt;a href="http://liftweb.net/"&gt;Lift&lt;/a&gt;. While there's a lot of information out there there's nothing that really lets a beginner start with the basics.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This post basically gives you the bare minimum configuration and dependencies to get a simple Lift application running.  This example just writes some text to the main web page of your application - The ubiquitous "Hello World". &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;If you find any errors or inaccuracies please let me know as I'm still figuring this stuff out&lt;/i&gt;!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The source for this project can be found &lt;a href="http://github.com/ssanj/HelloWorldLift"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm using &lt;a href="http://code.google.com/p/simple-build-tool/"&gt;SBT&lt;/a&gt; for building this project. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The basic structure of this Lift project is as follows:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The SBT properties and SBT project can be found in:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;project &gt; build.properties&lt;/div&gt;&lt;div&gt;project &gt; build &gt; LiftProject.scala&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The scala source can be found in:&lt;/div&gt;&lt;div&gt;&lt;div&gt;src &gt; main  &gt; scala &gt; bootstrap &gt; liftweb (contains a bootstrap class)&lt;/div&gt;&lt;/div&gt;&lt;div&gt;src &gt; main &gt; scala &gt; au &gt; com &gt; testlift &gt; snippet (contains snippet code)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Properties are defined in:&lt;/div&gt;&lt;div&gt;src &gt; main  &gt; resources &gt; props &gt; default.props (an empty file for now)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The web application structure can be found in:&lt;/div&gt;&lt;div&gt;src &gt; main &gt; webapp (contains html pages that call snippets)&lt;/div&gt;&lt;div&gt;src &gt; main &gt; webapp &gt; WEB-INF&lt;/div&gt;&lt;div&gt;src &gt; main &gt; webapp &gt; templates-hidden (contains templates for your snippets)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With the structure out of the way, lets focus on the LiftProject file for SBT:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre name="code" class="brush: scala"&gt;&lt;br /&gt;import sbt._&lt;br /&gt;&lt;br /&gt;class LiftProject(info: ProjectInfo) extends DefaultWebProject(info) {&lt;br /&gt;val liftVersion = "2.1-RC2"&lt;br /&gt;&lt;br /&gt;override def libraryDependencies = Set(&lt;br /&gt;"net.liftweb" %% "lift-webkit" % liftVersion % "compile-&gt;default",&lt;br /&gt;"net.liftweb" %% "lift-common" % liftVersion % "compile-&gt;default",&lt;br /&gt;"net.liftweb" %% "lift-mapper" % liftVersion % "compile-&gt;default",&lt;br /&gt;"org.mortbay.jetty" % "jetty" % "6.1.22" % "test-&gt;default"&lt;br /&gt;) ++ super.libraryDependencies&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The above basically defines the minimum dependencies to get this example running. I've left out database drivers and any other dependencies we don't need. We need jetty because we are going to use it to run the example through SBT. I'm using Lift 2.1-RC2 which supports Scala 2.8.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My build.properies file defines basic project attributes:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre name="code" class="brush: bash"&gt;&lt;br /&gt;#Project properties&lt;br /&gt;#Thu Sep 16 20:04:08 EST 2010&lt;br /&gt;project.organization=blah&lt;br /&gt;project.name=HelloWorldLift&lt;br /&gt;sbt.version=0.7.4&lt;br /&gt;project.version=1.0&lt;br /&gt;build.scala.versions=2.8.0&lt;br /&gt;project.initialize=false&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you can see we are building against Scala 2.8. That's it for project setup.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Lift looks for a boostrap class in the bootstrap.liftweb.Boot class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Boot.scala has the following contents:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre name="code" class="brush: scala"&gt;&lt;br /&gt;package bootstrap.liftweb&lt;br /&gt;&lt;br /&gt;import net.liftweb.http.LiftRules&lt;br /&gt;import net.liftweb.sitemap.{SiteMap, Menu}&lt;br /&gt;&lt;br /&gt;class Boot {&lt;br /&gt;&lt;br /&gt;def boot {&lt;br /&gt;LiftRules.addToPackages("au.com.testlift")&lt;br /&gt;LiftRules.setSiteMap(SiteMap(Menu("Home") / "index"))&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Basically what this code is doing is:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. Notifying Lift that the classes it needs can be found in the au.com.testlift package. Snippets can be found in au.com.testlift.snippet package.&lt;/div&gt;&lt;div&gt;2. Setting up a Sitemap or Menu with a single entry named "Home" which maps to /index url. You need to setup a Menu entry on the SiteMap for each page you wish to expose through Lift.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's it for boot setup.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We create a HelloWorld class in the au.com.testlift.snippet package with the following contents:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;package au.com.testlift.snippet&lt;br /&gt;&lt;br /&gt;class HelloWorld {&lt;br /&gt;def howdy = &amp;lt;span&amp;gt;World!! The current date is: {new java.util.Date}&amp;lt;/span&amp;gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you can see this snippet is pretty straightforward. The howdy method simply returns a scala.xml.NodeSeq when called. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The main webpage that drives this functionality is the index.html page which can be found under src &gt; main &gt; webapp. Its contents is as follows:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;lift:surround with="default" at="content"&amp;gt;&lt;br /&gt;&amp;lt;h1&amp;gt;Hello World Snippet&amp;lt;/h1&amp;gt;&lt;br /&gt;Hello &amp;lt;lift:HelloWorld.howdy /&amp;gt;&lt;br /&gt;&amp;lt;/lift:surround&amp;gt;&lt;br /&gt;&lt;/pre&gt;Basically what the above block says is to get the value of the howdy method on the au.com.testlit.snippet.HelloWorld class and replace the  &amp;lt;lift:HelloWorld.howdy&amp;gt; tag with what it returns. The &amp;lt;life:surround&amp;gt; defines that the &amp;lt;lift:HelloWorld.howdy&amp;gt; tag  should be embedded (or surrounded with) the contents of the default.html file at a bind position named "content". The default.html file can be found under src &gt; main &gt; webapp &gt; templates-hidden.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;The contents of the default.html file are as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" xmlns:lift='http://liftweb.net'&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;meta http-equiv="content-type" content="text/html; charset=UTF-8" /&amp;gt;&lt;br /&gt;    &amp;lt;meta name="description" content="" /&amp;gt;&lt;br /&gt;    &amp;lt;meta name="keywords" content="" /&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Hello World&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;lift:bind name="content" /&amp;gt;&lt;br /&gt;    &amp;lt;lift:Menu.builder /&amp;gt;    &lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And that's all the main components to get this example running.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Issue the following commands to SBT:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;update&lt;/div&gt;&lt;div&gt;jetty-run&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If all goes well you should see something like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;&lt;br /&gt;[info] jetty-6.1.22&lt;br /&gt;[info] NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet&lt;br /&gt;[info] Started SelectChannelConnector@0.0.0.0:8080&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After all the dependencies have been downloaded and the project compiled, jetty should launch on port 8080. You can verify that everything works by hitting &lt;a href="http://localhost:8080/index"&gt;http://localhost:8080/index&lt;/a&gt; or &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The way I think this works is as follows:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. The user issues the /index call to the application. This maps to the src &gt; main &gt; webapp &gt; index.html file.&lt;/div&gt;&lt;div&gt;2. When index.html is launched it invokes HelloWorld.howdy to get the contents of its inner &amp;lt;lift:HelloWorld.howdy&amp;gt; tag.&lt;/div&gt;&lt;div&gt;3. It then embeds that result in the src &gt; main &gt; webapp &gt; templates-hidden &gt; default.html template at the "content" bind point. It further adds the single Menu entry "Home" at the &amp;lt;lift:Menu.builder&amp;gt; tag &lt;/div&gt;&lt;div&gt;4. The fully resolved page is sent back to the user.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Further information on Lift can be found &lt;a href="http://www.assembla.com/wiki/show/liftweb"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4617653893827299226?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4617653893827299226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4617653893827299226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4617653893827299226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4617653893827299226'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2010/09/hello-world-lift.html' title='Hello World Lift'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6742028299081978866</id><published>2010-07-20T12:46:00.028+10:00</published><updated>2010-07-20T17:53:54.272+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='semigroup'/><category scheme='http://www.blogger.com/atom/ns#' term='functional concepts'/><title type='text'>Semigroup</title><content type='html'>I recently came across something called a  "Semigroup" while browsing &lt;a href="http://github.com/nkpart/scalaz"&gt;scalaz&lt;/a&gt; code. I was actually looking for an example of a Monoid, but found that the scalaz implementation used Semigroup in the implementation of Monoids.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;What is a Semigroup?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A Semigroup is an abstraction of a  binary operation where the operands and the result are of the same type.&lt;br /&gt;&lt;br /&gt;A functional definition of a Semigroup in scala could be:&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;def op[T](t1:T, t2:T) : T&lt;/pre&gt;&lt;br /&gt;The abstraction has to adhere to  2 rules to be considered a Semigroup. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;u&gt;Semigroup Rules&lt;/u&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The result of the binary operation should be of the same type as that of the two operands.&lt;/li&gt;&lt;li&gt;The binary operation should be associative.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Rule 1&lt;/b&gt;, defines a "closed set", or a closure - which is an operation on elements of a set, that always yield another element of the same set. An example set would be natural numbers. If the operation to abstract was addition, we would get op(1,2) = 3 -&gt; 1+2 = 3, where both 1,2 and 3 are all members of the same set (natural numbers). &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Rule 2&lt;/b&gt;, defines that if we had a sequence of the same operation, the associativity of the operations would be not change the final result. For example taking the operation as multiplication, we would get op(2, op(4, 5)) = op(op(2,4), 5) -&gt; 2*(4*5) = (2*4)*5&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The division operation is not a natural number Semigroup, because the result of dividing through 2 natural numbers may be a real number. Eg. 5/2 -&gt; 2.5. This breaks rule 1, since 2.5 is not a member of the natural number set.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The division operation is also not a real number Semigroup because it is not an associative operation and hence breaks rule 2.  Given op(op(27.0,3.0), 2.0) != op(27.0, op(3.0,2.0) -&gt; (27.0/3.0)/2.0 != 27.0/(3.0/2.0)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Some Examples&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an implementation of the plus operator:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre name="code" class="brush: scala"&gt;&lt;br /&gt;trait Semigroup[T] {&lt;br /&gt;def op(t1:T, t2:T) : T&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def plus = new Semigroup[Int] { def op(t1:Int, t2:Int) = t1 + t2 }&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Scalaz defines a Semigroup as the following trait:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="brush: scala"&gt;&lt;br /&gt;trait Semigroup[S] {&lt;br /&gt; def append(s1: S, s2: =&gt; S): S&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;and some example implementations from scalaz:&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="brush: scala"&gt;&lt;br /&gt;trait Semigroups {&lt;br /&gt;def semigroup[S](f: (S, =&gt; S) =&gt; S) = new Semigroup[S] {&lt;br /&gt;  def append(s1: S, s2: =&gt; S) = f(s1, s2)&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;implicit def IntSemigroup: Semigroup[Int] = semigroup(_ + _)&lt;br /&gt;implicit def StringSemigroup: Semigroup[String] = semigroup(_ + _)&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Why use Semigroups?&lt;/b&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When using any Semigroup implementation, we know that the 2 rules apply: closure and associativity. This gives us knowledge on how to use the API correctly. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example since we know that Semigroups are associative, we don't have to wonder about what will happen if the associativity of a statement changes. We also know by closure that the types returned are within the same domain as the operands.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Semigroups can also be used to implement other concepts such as Monoids and thus having a Semigroup implementation helps you create further functional concepts.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Any feedback is much appreciated.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6742028299081978866?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6742028299081978866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6742028299081978866' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6742028299081978866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6742028299081978866'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2010/07/semigroup.html' title='Semigroup'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-8938756706329308326</id><published>2010-07-20T12:19:00.008+10:00</published><updated>2011-02-16T17:14:52.440+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='functional concepts'/><title type='text'>Functional Concepts</title><content type='html'>&lt;div style="text-align: justify;"&gt;One of the biggest hurdles I've come across while learning scala, are all the new functional concepts used - most of which I know nothing about! I've also found it rather to hard to find any succinct information on these concepts, except for Haskell code and mathematical equations. While these are great for those who know Haskell and/or are proficient in mathematics it may not be the easiest thing for a simple programmer (such as myself) to understand.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I believe that in order to become a good functional programmer one needs to understand basic functional concepts and how they are implemented.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;In the following months I hope to investigate the following concepts:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;&lt;a href="http://babyloncandle.blogspot.com/2010/07/semigroup.html"&gt;Semigroup&lt;/a&gt;&lt;/li&gt;&lt;li style="text-align: justify;"&gt;&lt;a href="http://babyloncandle.blogspot.com/2011/02/functor.html"&gt;Functor&lt;/a&gt;&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Monoid&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Monad&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Arrows&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Groups&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Continuations&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Isomorphic&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Monomorphic&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Referential Transparency&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Functional Composition&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Higher-order Functions&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Higher Kinds&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Type Classes&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-8938756706329308326?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/8938756706329308326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=8938756706329308326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8938756706329308326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8938756706329308326'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2010/07/functional-concepts.html' title='Functional Concepts'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4273956944212822295</id><published>2010-03-02T10:50:00.014+10:00</published><updated>2010-03-02T12:07:05.859+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Exceptions'/><category scheme='http://www.blogger.com/atom/ns#' term='Either'/><title type='text'>Scala's Alternatives to Exceptions</title><content type='html'>I recently posed a series of questions about Scala's alternatives to Exception @ the &lt;a href="http://www.meetup.com/Brisbane-Functional-Programming-Group-BFG/"&gt;BFPG&lt;/a&gt;. The slides can be found &lt;a href="http://files.meetup.com/1443989/Scala%27s%20Alternatives%20to%20Exceptions.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is some of the feedback I received on the solutions provided:&lt;br /&gt;&lt;br /&gt;By &lt;a href="http://kristian-domagala.blogspot.com/"&gt;Kristian Domagala&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;It looks like Sanjiv raised some interesting questions at the end of his slides. As I wasn't at the meeting, I don't know to what extent the questions were answered, but I thought I would chime in with my 2 cents.&lt;br /&gt;&lt;br /&gt;I've found the Either type to be useful for error conditions that can be resolved either through code (eg, using a fallback), or by re-directing back to the user to address. Often this means the Left and Right types are mapped to the same type, and the Either type is merged into a single value (ie, Either[A,A] =&gt; A). In the examples you present, you're essentially doing that all together at the end with the fold function.&lt;br /&gt;&lt;br /&gt;In terms of chaining exceptions, in Scala terms, this can be handled using flatMap function on the right-projection of Either, assuming you use a common type on the left. Sometimes you will need to map the left types to a common type, but I've found it's usually a String or something representing an exception message, and little additional effort is required.&lt;br /&gt;&lt;br /&gt;Going to the particular examples in the slides, I note that the PersistentOutcome type is very similar to Either; ie, Either[String, Unit]. In fact, you could remove the need for pattern matching on the type by aliasing it to Either and re-using the functions defined there:&lt;br /&gt;&lt;br /&gt;type PersistentOutcome = Either[String, Unit]&lt;br /&gt;&lt;br /&gt;Alternatively, you could achieve the same thing using an implicit def, so that the pattern matching is done in one place and whenever you see a PersistentOutcome, you can treat it as an Either[String, Unit]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;implicit def poToStringUnit(po:PersistentOutcome):Either[String,Unit] = po match {  &lt;br /&gt;case Failure(x) =&gt; Left(x)  &lt;br /&gt;case Success =&gt; Right(())  &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt; note that you've started to go down the latter path in the reloaded example. The above gives you something you can re-use anywhere.  &lt;br /&gt;  &lt;br /&gt;Once you've got Either[String,Unit], it's only one left-map away from becoming Either[Exception,Unit]:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;def stringUnitToExUnit(e:Either[String,Unit]):Either[Exception,Unit] =   &lt;br /&gt;e.left.map(new Exception(_))  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Now we're dealing with more consistent types throughout the execution (Either[Exception,_]), and the addSpends function can be reduced to:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;def addSpends(date:Sdate, f:(DailySpend) =&gt; Unit):Either[Exception, Unit] =&lt;br /&gt;    Either.joinRight(&lt;br /&gt;      (spender &lt; date).right.flatMap(&lt;br /&gt;        ds =&gt; { f(ds); spender &gt; ds }&lt;br /&gt;      ).right.map(stringUnitToExUnit)&lt;br /&gt;    )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;To see that I'm not cheating, here's my working&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;  def addSpends(date:Sdate, f:(DailySpend) =&gt; Unit):Either[Exception, Unit] = {&lt;br /&gt;    val eds:Either[Exception,DailySpend] = spender &lt; date&lt;br /&gt;    val epo:Either[Exception,PersistentOutcome] = &lt;br /&gt;        eds.right.flatMap(ds =&gt; {f(ds); spender &gt; ds})&lt;br /&gt;    val esu:Either[Exception,Either[String,Unit]] = epo&lt;br /&gt;    val eeu:Either[Exception,Either[Exception,Unit]] = &lt;br /&gt;        esu.right.map(stringUnitToExUnit)&lt;br /&gt;    val eu:Either[Exception,Unit] = Either.joinRight(eeu)&lt;br /&gt;    eu&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Going to the main function, I notice that you're folding twice on the same type (Either[Exception,Unit]). You can get rid of the first fold, and with a little bit of point-free style come down to:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;def main(args: Array[String]) {&lt;br /&gt;  import Function.const  &lt;br /&gt;  addSpends(yesterday, addItems1).right.flatMap(  &lt;br /&gt;  const(addSpends(today, addItems2))).fold(  &lt;br /&gt;  printError, const(printAllSpends))  &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once again, the long-hand:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;def main(args: Array[String]) {&lt;br /&gt;  val eu1:Either[Exception,Unit] = addSpends(yesterday, addItems1)  &lt;br /&gt;  val eu2:Either[Exception,Unit] =  &lt;br /&gt;  eu1.right.flatMap(_ =&gt; addSpends(today, addItems2))  &lt;br /&gt;  val u:Unit = eu2.fold(e =&gt; printError(e), _ =&gt; printAllSpends)  &lt;br /&gt;  u  &lt;br /&gt;}  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;I hope this gives some food for thought and I haven't misinterpreted what you are trying to achieve!&lt;br /&gt;&lt;br /&gt;Going to your chaining solution:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;val spender = new Spender with LedgeredMemoryPersister&lt;br /&gt;type Result = Either[Exception, Unit]&lt;br /&gt;&lt;br /&gt;  def main(args: Array[String]) {&lt;br /&gt;    failFast(List(()=&gt; addSpends(yesterday, addItems1),&lt;br /&gt;                  ()=&gt; addSpends(today, addItems2),&lt;br /&gt;                  ()=&gt; addSpends(SomeDay(18, February(), 2010), addItems2),&lt;br /&gt;                  ()=&gt; addSpends(SomeDay(19, February(), 2010), addItems1),&lt;br /&gt;                  ()=&gt; addSpends(SomeDay(20, February(), 2010), addItems1))).&lt;br /&gt;            fold(ex =&gt; printError(ex), r =&gt; printAllSpends)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def failFast(funcs:List[Function0[Result]]) : Result = {&lt;br /&gt;    if (funcs.isEmpty) Right({})&lt;br /&gt;    else (funcs.head.apply()).fold(l =&gt; Left(l), r =&gt; failFast(funcs.tail))&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def addSpends(date:Sdate, f:(DailySpend) =&gt; Result) : Result = {&lt;br /&gt;    (spender &lt; date).fold(l =&gt; Left(l), ds =&gt; f(ds))&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; I think it is more complicated than it needs to be. Obviously, if you need to support a variable-length list of functions to execute, then you need something similar to what you wrote. Actually, probably what you want is more along the lines of:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;  val params = List((yesterday, addItems1), (today, addItems2). ...)&lt;br /&gt;  params.foldLeft(Right(())((r, p) =&gt; r.right.flatMap(addSpends(p)) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;But if you are just using it as a language feature, then there is something already there for you. First I will write out the long-hand version:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;addSpends(yesterday, addItems1).right.flatMap(  &lt;br /&gt;    r1 =&gt; addSpends(today, addItems2)).right.flatMap(  &lt;br /&gt;    r2 =&gt; addSpends(SomeDay(18, February(), 2010), addItems2)).right.flatMap(  &lt;br /&gt;    r3 =&gt; addSpends(SomeDay(19, February(), 2010), addItems1)).right.flatMap(  &lt;br /&gt;    r4 =&gt; addSpends(SomeDay(20, February(), 2010), addItems1)))).  &lt;br /&gt;        fold(ex =&gt; printError(ex), r5 =&gt; printAllSpends)  &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Using Scala's for comprehensions, this is equivalent to:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;def main(args: Array[String]) {&lt;br /&gt;   for (r1 &lt;- addSpends(yesterday, addItems1).right;           &lt;br /&gt;        r2 &lt;- addSpends(today, addItems2)).right;           &lt;br /&gt;        r3 &lt;- addSpends(SomeDay(18, February(), 2010), addItems2).right;           &lt;br /&gt;        r4 &lt;- addSpends(SomeDay(19, February(), 2010), addItems1).right;           &lt;br /&gt;        r5 &lt;- addSpends(SomeDay(20, February(), 2010), addItems1).right)       &lt;br /&gt;   yield ()).fold(ex =&gt; printError(ex), r =&gt; printAllSpends)  &lt;br /&gt;}  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;With an implicit conversion from Either to RightProjection, using '_' for the ignored success return values, moving the success case into the yield statement, and mapping the Left type to Unit, that comes down to:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;def main(args: Array[String]) {&lt;br /&gt;implicit def EtoRP[A,B](e:Either[A,B]) = e.right  &lt;br /&gt;Either.merge(  &lt;br /&gt;  for (_ &lt;- addSpends(yesterday, addItems1);             &lt;br /&gt;       _ &lt;- addSpends(today, addItems2);             &lt;br /&gt;       _ &lt;- addSpends(SomeDay(18, February(), 2010), addItems2);             &lt;br /&gt;       _ &lt;- addSpends(SomeDay(19, February(), 2010), addItems1);             &lt;br /&gt;       _ &lt;- addSpends(SomeDay(20, February(), 2010), addItems1))         &lt;br /&gt;  yield (printAllSpends)).left.map(printError))   &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;The Either[A,A] type I mentioned is what you need to use Either.merge. In the previous case, it is obtained by calling left.map to convert Either[Exception,Unit] to Either[Unit,Unit].&lt;br /&gt;&lt;br /&gt;Another thing to note is that the examples I've provided are a way to show how to better use Either; not necessarily the best way to solve your problem. I would strongly argue that you have way too much in the way of side-effects in the original code. By isolating the side-effects from the purely functional (read: referentially transparent) parts of the code, you could potentially end up with a much more elegant and (de)composable solution. Learning a language that forces you to deal with side-effects will greatly help with working out the isolation.&lt;br /&gt;&lt;br /&gt;Finally, I haven't run any of the above through a compiler, so don't be surprised if I've left something out/stuffed something up!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Given all the great solutions given by Kristian above I decided to go with the following:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java" &gt;&lt;br /&gt;type Result = Either[Exception, Unit]  &lt;br /&gt;def addSpends(date:Sdate, f:(DailySpend) =&gt; Result) : Result  &lt;br /&gt;  &lt;br /&gt;  ...  &lt;br /&gt;  &lt;br /&gt;  type AddByDate = Tuple2[Sdate, Function1[DailySpend, Result]]  &lt;br /&gt;  val params = List[AddByDate](  &lt;br /&gt;                    (SomeDay(16, February(), 2010), addItems1),  &lt;br /&gt;                    (SomeDay(17, February(), 2010), addItems2),  &lt;br /&gt;                    (SomeDay(18, February(), 2010), addItems2),  &lt;br /&gt;                    (SomeDay(19, February(), 2010), addItems1),  &lt;br /&gt;                    (SomeDay(20, February(), 2010), addItems1))  &lt;br /&gt;   params.foldLeft(Right():Result)((r, p) =&gt; r.right.flatMap(r1 =&gt; addSpends(p._1, p._2))).  &lt;br /&gt;           fold(ex =&gt; printError(ex), r =&gt; printAllSpends)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can the syntax be made cleaner I wonder?  Anyway, it's been a great learning experience! I've got so much to learn! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4273956944212822295?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4273956944212822295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4273956944212822295' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4273956944212822295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4273956944212822295'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2010/03/scalas-alternatives-to-exceptions.html' title='Scala&apos;s Alternatives to Exceptions'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5194569933044042160</id><published>2009-12-03T21:40:00.003+10:00</published><updated>2009-12-03T21:49:59.270+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Intellij'/><category scheme='http://www.blogger.com/atom/ns#' term='cache'/><category scheme='http://www.blogger.com/atom/ns#' term='tests'/><title type='text'>Intellij can't find test classes in a package</title><content type='html'>I came across a very annoying problem while using intellij 8.1.3 today. I could run all the tests from the source package until I introduced a compilation error. After fixing the compilation error, I could no long run all the tests from the source package. Intellij kept insisting that "there are no tests in package xyz" .. which of ofcourse there where.&lt;br /&gt;&lt;br /&gt;I had a quick look around the intellij configuration files (usually in your &lt;span style="font-weight:bold;"&gt;home_directory/.IntelliJIdea8x/system&lt;/span&gt; directory) and I came across 2 cache directories: &lt;br /&gt;&lt;br /&gt;1. caches&lt;br /&gt;2. compiler&lt;br /&gt;&lt;br /&gt;Both had cached files of the project I was working on. The cache files are of the format: &lt;span style="font-weight:bold;"&gt;project_name_unique_number&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I deleted the cached files of my project from each of the above directories and restarted intellij. This fixed the problem of not finding any tests! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5194569933044042160?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5194569933044042160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5194569933044042160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5194569933044042160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5194569933044042160'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/12/intellij-cant-find-test-classes-in.html' title='Intellij can&apos;t find test classes in a package'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-3824858738330562154</id><published>2009-12-01T21:51:00.006+10:00</published><updated>2009-12-01T22:39:05.579+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='companion'/><title type='text'>Companion Objects</title><content type='html'>Scala defines singleton objects with the "object" keyword. If a singleton object shares the same name as that of a class and is defined within the same file, the singleton object is called a "companion object" and the class is called a "companion class". Companionship offers full access to each other's private variables/members. This is similar to an inner class in Java, without the need for an enclosing instance of the outer class.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what can we do with this new found power of companion objects? Companion object can be used to create companion class instances through factory methods. You could for instance have the companion class extend a trait and make all its constructors private. Then using a factory method on the companion object, you could create an instance of the trait but abstract the companion class out of the equation. We could also provide additional constructors for a class outside the class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's take an example. Say we have a trait:&lt;/div&gt;&lt;pre name="code" class="java"&gt;sealed trait Vehicle {&lt;br /&gt;protected val vin:String&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;Say we also have an extension:&lt;/div&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;class Car(val vin:String,private val model:String) extends Vehicle&lt;br /&gt;&lt;/pre&gt;The vin is a protected value in the trait Vehicle and as such can only be accessed by subclasses and the model is private.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We can define a companion object of Car like so:&lt;/div&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;object Car {&lt;br /&gt;&lt;br /&gt;def apply(vin:String, model:String) = new Car(vin, model)&lt;br /&gt;def apply(vin:String) = new Car(vin, "Jaguar")&lt;br /&gt;def apply() = new Car("N/A", "Invisble Car")&lt;br /&gt;def print(car:Car) {println("My " + car.model + "'s vin is: " + car.vin) }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;By using the companion object we can instantiate Car with:&lt;/div&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Car() or Car("1234567") or Car("9876543", "Ford")&lt;br /&gt;&lt;/pre&gt;The companion object has given us extra constructors for the Car object for free....or so it seems. We have also rid ourselves of the "new" key word that you would normally need to create an instance of a class. Case classes are the exception and now Car behaves a little like a case class thanks to the companion object. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the print method we see that the companion object does access the protected value "vin" (although it does not extend Vehicle) and the private value "model". Thus we can define methods that need to access the private state of the companion class within the companion object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One Caveat to keep in mind is that the companions are explicitly linked by name and name alone. Attempting the following will fail although it may "feel" right:&lt;/div&gt;&lt;pre name="code" class="java"&gt;def print2(vehicle:Vehicle) {println("My vehicle's vin is: " + vehicle.vin) }&lt;br /&gt;&lt;/pre&gt;We get the following compilation error:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;error vin cannot be accessed from blog.this.Vehicle&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;/i&gt;The reason for this failure is that we are trying to access a value from the Vehicle trait and not the Car class. The companion object Car in this case only has access to the state of the companion class Car.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the full example:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package blog&lt;br /&gt;&lt;br /&gt;import Car._&lt;br /&gt;&lt;br /&gt;object Companionship {&lt;br /&gt;&lt;br /&gt;def main(args: Array[String]) {&lt;br /&gt;print(Car())&lt;br /&gt;print(Car("1234567"))&lt;br /&gt;print(Car("9876543", "Ford"))&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;sealed trait Vehicle {&lt;br /&gt;protected val vin:String&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Car(val vin:String,private val model:String) extends Vehicle&lt;br /&gt;&lt;br /&gt;object Car {&lt;br /&gt;&lt;br /&gt;def apply(vin:String, model:String) = new Car(vin, model)&lt;br /&gt;def apply(vin:String) = new Car(vin, "Jaguar")&lt;br /&gt;def apply() = new Car("N/A", "Invisble Car")&lt;br /&gt;def print(car:Car) {println("My " + car.model + "'s vin is: " + car.vin) }&lt;br /&gt;//def print2(vehicle:Vehicle) {println("My vehicle's vin is: " + vehicle.vin) }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-3824858738330562154?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/3824858738330562154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=3824858738330562154' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3824858738330562154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3824858738330562154'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/12/companion-objects.html' title='Companion Objects'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4340322186735848739</id><published>2009-11-07T18:42:00.004+10:00</published><updated>2009-11-07T18:55:25.500+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VPN'/><category scheme='http://www.blogger.com/atom/ns#' term='NAT'/><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='Karmic'/><category scheme='http://www.blogger.com/atom/ns#' term='VPNC'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Pop goes the VPN</title><content type='html'>Recently my vpn stopped working for no apparent reason. I could connect to the vpn using vpnc, but from there I couldn't ping any of the machines on the network. I had not changed any settings so it was quite puzzling. Friends' using Windows clients were able to connect with the same vpn parameters without any problems. It looked like a dns lookup problem.&lt;br /&gt;&lt;br /&gt;Running: &lt;span style="font-style:italic;"&gt;cat /etc/resolv.conf&lt;/span&gt; confirmed that the vpn dns was not being used.&lt;br /&gt;&lt;br /&gt;After googling around a bit I came across &lt;a href="http://prystash.blogspot.com/2009/09/vpnc-linux-vpnc-no-response-from-target.html"&gt;this&lt;/a&gt; site which gave me a clue on how to configure my dns look ups. I just had to add the following line to my vpnc config file:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;NAT Traversal Mode cisco-udp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now when I ran vpnc, and ran &lt;span style="font-style:italic;"&gt;cat /etc/resolv.conf&lt;/span&gt;, it confirmed that my vpn dns was used! :)&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The complete vpnc config file looks like this:&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;IPSec gateway xxx.xx.xxx.xxx&lt;br /&gt;IPSec ID your_id&lt;br /&gt;IPSec secret your_secret&lt;br /&gt;IKE Authmode psk&lt;br /&gt;NAT Traversal Mode cisco-udp&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4340322186735848739?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4340322186735848739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4340322186735848739' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4340322186735848739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4340322186735848739'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/11/pop-goes-vpn.html' title='Pop goes the VPN'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-3212304621448626319</id><published>2009-10-15T19:37:00.003+10:00</published><updated>2009-10-15T20:08:38.036+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Problem'/><category scheme='http://www.blogger.com/atom/ns#' term='Euler'/><title type='text'>Project Euler Problem 1</title><content type='html'>&lt;a href="http://dibblego.wordpress.com/"&gt;Tony&lt;/a&gt; mentioned &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; more than a few times back in the day when we used to work &lt;a href="http://www.workingmouse.com/"&gt;here&lt;/a&gt;. I completely forgot about Project Euler until recently when I restarted learning scala. I thought it would be a good way to further my learning of scala by solving (or trying to solve) some of the Euler problems. Below is my attempt at solving Problem 1.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Problem:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" background-color: rgb(255, 255, 255); font-family:'Trebuchet MS', sans-serif;"&gt;&lt;p&gt;&lt;i&gt;If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;Find the sum of all the multiples of 3 or 5 below 1000.&lt;/i&gt;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;This was my first solution [Sol1]:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;def getTotal(upper:Int) : Int = multiplesBelow(upper - 1)&lt;br /&gt;&lt;br /&gt; def multiplesBelow(start:Int) : Int = {&lt;br /&gt;   if (start &lt;= 0) return 0     &lt;br /&gt;   if (isMultiple(start)) start + multiplesBelow(start-1) else multiplesBelow(start - 1)   &lt;br /&gt; } &lt;br /&gt;&lt;br /&gt;def isMultiple(number:Int) : Boolean = (number != 0) &amp;&amp; ((number % 3 == 0) || (number % 5 == 0))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Although this solution will give you the expected answer with the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt; getTotal(1000)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sol1 is quite clumsy. After a quite scout around the net I found a ruby solution that used ranges and since scala also has ranges I came up with the following [Sol2]:&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;def getTotal2(upper:Int) : Int = (1 until upper).foldLeft(0)(((a,b) =&gt; if (b % 3 == 0 || b % 5 == 0) a+b else a))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I like Sol2 mainly because it is succinct and "simple". I also came up with a solution using map and fold [Sol3]:&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;def getTotal3(upper:Int) : Int = (1 until upper).map(a =&gt; if (a % 3 == 0 || a % 5 == 0) a else 0).foldLeft(0)(_ + _)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sol3 has an extra step of mapping the function across the values and then folding it. &lt;br /&gt;And there you have the solution to problem 1. I'm sure there are much neater solutions to problem than those above. Please feel free to comment if you have a better solution  and/or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-3212304621448626319?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/3212304621448626319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=3212304621448626319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3212304621448626319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3212304621448626319'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/10/project-euler-problem-1.html' title='Project Euler Problem 1'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5613282731185517573</id><published>2009-09-29T19:46:00.002+10:00</published><updated>2009-09-29T21:04:39.456+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Start'/><category scheme='http://www.blogger.com/atom/ns#' term='how to'/><title type='text'>The path less followed</title><content type='html'>A couple of months ago, I started my scala journey in earnest. You have probably heard of the many benefits of using scala, if not have a look &lt;a href="http://www.scala-lang.org/node/25"&gt;here&lt;/a&gt;. I'd like to give you some pointers on how to get started in scala and send you along your interesting journey of discovery.&lt;br /&gt;&lt;br /&gt;Your central source of scala is &lt;a href="http://www.scala-lang.org/"&gt;here&lt;/a&gt;. You can download the latest version of scala from &lt;a href="http://www.scala-lang.org/downloads"&gt;here&lt;/a&gt;. On linux simply download the &lt;b&gt;.tgz&lt;/b&gt;, extract it and add the bin directory to your path.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can verify your installation by invoking the following from a command prompt:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;scalac -version&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;which will output something similar to:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Scala compiler version 2.7.5.final -- Copyright 2002-2009, LAMP/EPFL&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;To launch the scala interpreter invoke the following:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;scala&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;This will give you a prompt like the following:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Welcome to Scala version 2.7.5.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_14).&lt;div&gt;Type in expressions to have them evaluated. Type :help for more information.&lt;br /&gt;&lt;br /&gt;scala&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;Greeting the world as per usual can be done as follows:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;println("Hello World")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will print out the String "Hello World" just beneath the println command. As with java, (System.)println prints out a line of text to the standard out.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We can define a simple method as follows:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def greeter(name : String) = println("Hello " +  name + "!")&lt;br /&gt;&lt;br /&gt;greeter: (String)Unit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The above means that greeter is the name of the method, which takes a String and returns Unit (or void in java).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It can be invoked as expected:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;greeter("Dolly")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;Which would give:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Hello Dolly!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;You can write any method you like in the interpreter and execute it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is good for small programs but not so great for larger ones.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's create our first scala class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First create a folder called &lt;b&gt;blog&lt;/b&gt;, which is essentially our package. Now create a file called &lt;b&gt;SimpleGreeter.scal&lt;/b&gt;a within the blog package with the following contents:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package blog&lt;br /&gt;&lt;br /&gt;object SimpleGreeter {&lt;br /&gt;&lt;br /&gt;def main(args : Array[String]) {&lt;br /&gt; if (args.length == 0) println("Usage: SimpleGreeter your_name")&lt;br /&gt; else  println("Hello " + args.mkString(" ")  + "!")&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is a simple "main" method with a snippet of code that either displays a greeting based on the arguments supplied or if no arguments are supplied shows the usage.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's very similar to java's main method definition:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def main(args : Array[String])&lt;br /&gt;&lt;br /&gt;public static void main(String[] args)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Go to your source directory and compile the scala class:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;scalac blog/SimpleGreeter.scala&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;If you have a look under your &lt;b&gt;blog&lt;/b&gt; package you should see the following classes:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;SimpleGreeter.class&lt;br /&gt;SimpleGreeter$.class&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can run the SimpleGreeter with:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;scala blog.SimpleGreeter my very long name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We then get the following:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Hello my very long name!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;If you call the greeter with no parameters:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;scala blog.SimpleGreeter&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;We get:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Usage: SimpleGreeter your_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;An interesting thing to note is that since scala runs on the &lt;b&gt;VM&lt;/b&gt;, we should be able to do this:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;java blog.SimpleGreeter my very long name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;If we run this we get the following error:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Exception in thread "main" java.lang.NoClassDefFoundError: scala/ScalaObject&lt;br /&gt; at java.lang.ClassLoader.defineClass1(Native Method)&lt;br /&gt; at java.lang.ClassLoader.defineClass(ClassLoader.java:621)&lt;br /&gt; at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)&lt;br /&gt; at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)&lt;br /&gt; at java.net.URLClassLoader.access$000(URLClassLoader.java:56)&lt;br /&gt; at java.net.URLClassLoader$1.run(URLClassLoader.java:195)&lt;br /&gt; at java.security.AccessController.doPrivileged(Native Method)&lt;br /&gt; at java.net.URLClassLoader.findClass(URLClassLoader.java:188)&lt;br /&gt; at java.lang.ClassLoader.loadClass(ClassLoader.java:307)&lt;br /&gt; at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)&lt;br /&gt; at java.lang.ClassLoader.loadClass(ClassLoader.java:252)&lt;br /&gt; at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)&lt;br /&gt; at blog.SimpleGreeter.main(SimpleGreeter.scala)&lt;br /&gt;Caused by: java.lang.ClassNotFoundException: scala.ScalaObject&lt;br /&gt; at java.net.URLClassLoader$1.run(URLClassLoader.java:200)&lt;br /&gt; at java.security.AccessController.doPrivileged(Native Method)&lt;br /&gt; at java.net.URLClassLoader.findClass(URLClassLoader.java:188)&lt;br /&gt; at java.lang.ClassLoader.loadClass(ClassLoader.java:307)&lt;br /&gt; at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)&lt;br /&gt; at java.lang.ClassLoader.loadClass(ClassLoader.java:252)&lt;br /&gt; at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)&lt;br /&gt; ... 13 more&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;What we need to do is include the &lt;b&gt;scala-library.ja&lt;/b&gt;r library that came with the scala installation into the classpath to make it work. The library is found in the &lt;b&gt;lib&lt;/b&gt; directory of the scala installation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trying this again:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;java -cp .:your_scala_lib_location/scala-library.jar blog.SimpleGreeter my very long name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;We get:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Hello my very long name!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;This is awesome, because once you compile your scala sources into classes, they are essentially java classes! :) Oh! How sweet it is! :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'll leave this introduction there for the moment. Some good resources for further study are:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Programming-Scala-Comprehensive-Step-step/dp/0981531601/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1254220205&amp;amp;sr=8-1"&gt;Programming in Scala&lt;/a&gt; by Martin Odersky et al&lt;/li&gt;&lt;li&gt;The &lt;a href="http://www.scala-lang.org/node/198"&gt;Scala&lt;/a&gt; website&lt;/li&gt;&lt;li&gt;Some tutorials can be found &lt;a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaTutorial.pdf"&gt;here&lt;/a&gt; and &lt;a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaByExample.pdf"&gt;here&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;The helpful folks on the  scala channel @ irc.freenode.net&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5613282731185517573?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5613282731185517573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5613282731185517573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5613282731185517573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5613282731185517573'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/09/path-less-followed.html' title='The path less followed'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-3755071895452558694</id><published>2009-08-25T20:51:00.003+10:00</published><updated>2009-08-25T21:01:29.510+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Samba'/><category scheme='http://www.blogger.com/atom/ns#' term='/etc/exports'/><category scheme='http://www.blogger.com/atom/ns#' term='NFS'/><category scheme='http://www.blogger.com/atom/ns#' term='Share'/><category scheme='http://www.blogger.com/atom/ns#' term='anongid'/><category scheme='http://www.blogger.com/atom/ns#' term='anonuid'/><title type='text'>NFS Users</title><content type='html'>I recently needed to share the same directory between Samba and NFS. The main problem was that Samba accounts were mapped to users and NFS was not. NFS accounts can also be mapped to users by adding the following to &lt;span style="font-weight: bold; font-style: italic;"&gt;/etc/exports&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;path_to_share   computer_name(rw,all_squash,anonuid=xxx,anongid=yyy)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;anonuid&lt;/span&gt; is the user id to map to and &lt;span style="font-weight: bold; font-style: italic;"&gt;anongid&lt;/span&gt; is the group id to map to when a client from the &lt;span style="font-weight: bold; font-style: italic;"&gt;computer_name&lt;/span&gt; connects to the share.&lt;br /&gt;&lt;br /&gt;You can find out the user id and group id of a user with&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;id user_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Use the value of &lt;span style="font-weight: bold; font-style: italic;"&gt;uid&lt;/span&gt; and &lt;span style="font-weight: bold; font-style: italic;"&gt;gid&lt;/span&gt; to be &lt;span style="font-weight: bold; font-style: italic;"&gt;anonuid&lt;/span&gt; and &lt;span style="font-weight: bold; font-style: italic;"&gt;anongid&lt;/span&gt; respectively.&lt;br /&gt;&lt;br /&gt;Now when a user from &lt;span style="font-weight: bold; font-style: italic;"&gt;computer_name&lt;/span&gt; connects to the share, he connects as user &lt;span style="font-weight: bold; font-style: italic;"&gt;uid&lt;/span&gt; and of group &lt;span style="font-weight: bold; font-style: italic;"&gt;gid&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-3755071895452558694?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/3755071895452558694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=3755071895452558694' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3755071895452558694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3755071895452558694'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/08/nfs-users.html' title='NFS Users'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-2685824045587108037</id><published>2009-08-25T20:20:00.006+10:00</published><updated>2009-08-25T20:44:55.026+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='File System'/><category scheme='http://www.blogger.com/atom/ns#' term='Parted'/><category scheme='http://www.blogger.com/atom/ns#' term='vol_id'/><title type='text'>Linux File System Info</title><content type='html'>A quick way to find the file system of a particular block device is to use&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo vol_id device&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo vol_id /dev/sda1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which would produce something like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;ID_FS_USAGE=filesystem&lt;br /&gt;ID_FS_TYPE=ext3&lt;br /&gt;ID_FS_VERSION=1.0&lt;br /&gt;ID_FS_UUID=......&lt;br /&gt;ID_FS_UUID_ENC=...&lt;br /&gt;ID_FS_LABEL=&lt;br /&gt;ID_FS_LABEL_ENC=&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can also use vol_id to generate a uuid for a device&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo vol_id --uuid device&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo vol_id --uuid /dev/sda1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you have parted installed &lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo apt-get install parted&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;you could also do a &lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo parted -l&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;to find out the file system of all block devices.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-2685824045587108037?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/2685824045587108037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=2685824045587108037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2685824045587108037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2685824045587108037'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/08/linux-file-system-info.html' title='Linux File System Info'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4357534008611088325</id><published>2009-08-25T20:10:00.006+10:00</published><updated>2009-08-25T20:18:15.963+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Broken'/><category scheme='http://www.blogger.com/atom/ns#' term='Subversion  1.5'/><category scheme='http://www.blogger.com/atom/ns#' term='Sparse Checkout'/><category scheme='http://www.blogger.com/atom/ns#' term='Update'/><title type='text'>Subversion Update Broken in 1.5</title><content type='html'>Of recent I have noticed that the good old&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;svn up dir_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;does not seem to work as it used to. I have had heaps of missing files which were quite visible in the repository on closer examination! After having a dig around the man pages, I came up with the following&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;svn up -r HEAD --depth infinity dir_name&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;which achieves what I want. Quite strange. A quick peek at the documentation for Subversion 1.5 states that &lt;span style="font-style: italic; font-weight: bold;"&gt;--depth infinity&lt;/span&gt; is default for &lt;a href="http://subversion.tigris.org/svn_1.5_releasenotes.html#sparse-checkouts"&gt;sparse checkouts&lt;/a&gt;. I don't know what changed. Have a go at the code above if you've come across similar problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4357534008611088325?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4357534008611088325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4357534008611088325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4357534008611088325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4357534008611088325'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/08/subversion-update-broken-in-15.html' title='Subversion Update Broken in 1.5'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4216515306238656951</id><published>2009-08-04T22:03:00.005+10:00</published><updated>2009-08-04T22:10:50.919+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='web start'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='JNLP'/><title type='text'>Running Webstart on Linux</title><content type='html'>A few people, (myself included) were confused about how to run &lt;a href="http://java.sun.com/javase/technologies/desktop/javawebstart/index.jsp"&gt;web start&lt;/a&gt; files, specially through the browser.&lt;br /&gt;&lt;br /&gt;When firefox prompts you for running jnlp files simply point it to your &lt;span style="font-style: italic;"&gt;java_installation_dir/bin/javaws&lt;/span&gt; executable. :) It's that easy! :)&lt;br /&gt;&lt;br /&gt;On the command line run:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;javaws jnlp_url&lt;br /&gt;&lt;br /&gt;eg.&lt;br /&gt;&lt;br /&gt;javaws http://java.sun.com/docs/books/tutorialJWS/uiswing/components/ex6//TreeDemo.jnlp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can test it out &lt;a href="http://java.sun.com/docs/books/tutorialJWS/uiswing/components/ex6//TreeDemo.jnlp"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4216515306238656951?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4216515306238656951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4216515306238656951' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4216515306238656951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4216515306238656951'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/08/running-webstart-on-linux.html' title='Running Webstart on Linux'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6860947813322808431</id><published>2009-08-04T21:39:00.005+10:00</published><updated>2009-08-04T22:02:07.086+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 9.0.4'/><title type='text'>Java6 plugginess</title><content type='html'>Installing a java plugin for Firefox has eluded me for a while. I had a look @ the usual posts but they seemed quite cumbersome. Imagine my surprise when I installed the firefox java plugin in a few easy steps!&lt;br /&gt;&lt;br /&gt;1. Install Java6 SE or JRE from &lt;a href="http://java.sun.com/javase/downloads/?intcmp=1281"&gt;here&lt;/a&gt;.&lt;br /&gt;2. Find your firefox installation. Mine was in&lt;span style="font-style: italic;"&gt; /usr/lib/firefox-3.0.12&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you want to find out where your installation is, type:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;grep 'LIBDIR' /usr/bin/firefox&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You should see something like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;LIBDIR=/usr/lib/firefox-3.0.12&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;LIBDIR&lt;/span&gt; variable has the location of the firefox installation.&lt;br /&gt;&lt;br /&gt;3. Find the location of &lt;span style="font-style: italic;"&gt;libnpjp2.so&lt;/span&gt; in your java installation.&lt;br /&gt;&lt;br /&gt;Mine was in &lt;span style="font-style: italic;"&gt;jdk_install_dir/jre/lib/amd64/libnpjp2.so&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;4. Change to the &lt;span style="font-style: italic;"&gt;/usr/lib/firefox-3.0.12/plugins&lt;/span&gt; directory.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;cd /usr/lib/firefox-3.0.12/plugins&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;5. Create a symlink to your &lt;span style="font-style: italic;"&gt;libnpjp2.so&lt;/span&gt; file.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;ln -s jdk_install_dir/jre/lib/amd64/libnpjp2.so libnpjp2.so&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Your plugins directory will now have a symlink named &lt;span style="font-style: italic;"&gt;libnpjp2.so&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;6. Open firefox and type:&lt;br /&gt;&lt;br /&gt;about:plugins&lt;br /&gt;&lt;br /&gt;You should see something like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;Java(TM) Plug-in 1.6.0_14&lt;br /&gt;&lt;br /&gt; File name: libnpjp2.so&lt;br /&gt; The next generation Java plug-in for Mozilla browsers.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can further test your java installation at the following sites:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://javatester.org/version.html"&gt;Java Tester&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.java.com/en/download/installed.jsp"&gt;Java Verification&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.java.com/en/download/help/testvm.xml"&gt;Dancing Duke&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That's it! :)&lt;br /&gt;&lt;br /&gt;References: &lt;a href="http://www.bluequartz.us/phpBB2/viewtopic.php?t=85453&amp;amp;sid=7f45ed6cde8a1b7fb2eab30110a81728"&gt;1&lt;/a&gt; and &lt;a href="http://kb.mozillazine.org/Firefox_:_FAQs_:_Install_Java"&gt;2&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6860947813322808431?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6860947813322808431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6860947813322808431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6860947813322808431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6860947813322808431'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/08/java6-plugginess.html' title='Java6 plugginess'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6745148321668470828</id><published>2009-07-28T22:01:00.010+10:00</published><updated>2009-07-30T21:07:09.093+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Error'/><category scheme='http://www.blogger.com/atom/ns#' term='NFS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>Common NFS Error</title><content type='html'>Recently while trying to connect to an NFS share I got a familiar error message:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;mount: wrong fs type, bad option, bad superblock on Machine:/path,&lt;br /&gt;     missing codepage or helper program, or other error&lt;br /&gt;     (for several filesystems (e.g. nfs, cifs) you might&lt;br /&gt;     need a /sbin/mount.helper program)&lt;br /&gt;     In some cases useful info is found in syslog - try&lt;br /&gt;     dmesg | tail  or so&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I checked the usual configuration files to verify that I had the necessary permissions:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;/etc/exports &lt;- client should be allowed here with necessary access rights (r,w,rw etc) &lt;br /&gt;&lt;br /&gt;/etc/hosts.allow &lt;br /&gt;&lt;br /&gt;/etc/hosts.deny &lt;- client should not be listed here. &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All the configuration files were valid. The solution to the problem was to install nfs-common:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo apt-get install nfs-common&lt;br /&gt;&lt;/pre&gt;The nfs share can be mounted with:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo mount server_name:/path/to/remote/share local_mount_dir&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;eg.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo mount Harry_Hardcore:/home/harry/share  /home/user/share&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Enjoy! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6745148321668470828?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6745148321668470828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6745148321668470828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6745148321668470828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6745148321668470828'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/07/common-nfs-error.html' title='Common NFS Error'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6332103700596210661</id><published>2009-07-28T21:45:00.005+10:00</published><updated>2010-05-29T15:34:42.718+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Function Keys'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple Keyboard'/><category scheme='http://www.blogger.com/atom/ns#' term='Jaunty'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 9.0.4'/><title type='text'>Apple Silver Keyboard on Ubuntu 9.0.4</title><content type='html'>This is becoming a habit. Whenever a new version of &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; comes out, the function keys on my apple keyboard stop working. Not only that, but, the fixes used previously to get them working, don't work any more! Arrrg! The &lt;a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/201711"&gt;bug&lt;/a&gt; still stands.&lt;br /&gt;&lt;br /&gt;After a little digging around I came across this &lt;a href="http://dancingpenguinsoflight.com/2009/01/fixing-the-function-keys-on-the-apple-keyboard-in-ubuntu/"&gt;article&lt;/a&gt; which provided the simple solution. Have a look at your  &lt;span style="font-style: italic;"&gt;/sys/module/hid_apple/parameters/fnmode&lt;/span&gt; file:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;cat  /sys/module/hid_apple/parameters/fnmode&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Chances are that its value is 1. We need to set this to &lt;span style="font-style: italic;"&gt;2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;We can do this by editing the /etc/rc.local file&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;sudo vim /etc/rc.local&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Add the following lines before the &lt;span style="font-style: italic;"&gt;exit 0&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;#Added to enable the apple function keys by default.&lt;br /&gt;echo 2 &gt;  /sys/module/hid_apple/parameters/fnmode&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;save, exit and reboot your system.&lt;br /&gt;&lt;br /&gt;Before you give the function keys a go, have another look at the  &lt;span style="font-style: italic;"&gt;/sys/module/hid_apple/parameters/fnmode&lt;/span&gt; file. It should have a value of &lt;span style="font-style: italic;"&gt;2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;After this I discovered that function keys F13-F19 did not work! Sigh. I created ~/.Xmodmap file with the following entries&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;keycode 191 = Insert&lt;br /&gt;keycode 192 = Print Sys_Req&lt;br /&gt;keycode 193 = Scroll_Lock&lt;br /&gt;keycode 194 = Pause Break&lt;br /&gt;keycode 195 = First_Virtual_Screen&lt;br /&gt;keycode 196 = Next_Virtual_Screen&lt;br /&gt;keycode 197 = Last_Virtual_Screen&lt;br /&gt;&lt;br /&gt;clear Shift&lt;br /&gt;clear Lock&lt;br /&gt;clear Control&lt;br /&gt;clear Mod1&lt;br /&gt;clear Mod2&lt;br /&gt;clear Mod3&lt;br /&gt;clear Mod4&lt;br /&gt;clear Mod5&lt;br /&gt;add Shift = Shift_L Shift_R&lt;br /&gt;add Lock = Caps_Lock&lt;br /&gt;add Control = Control_L Control_R&lt;br /&gt;add Mod1 = 0 Alt_L 0x007D&lt;br /&gt;add Mod2 = Num_Lock&lt;br /&gt;add Mod4 = Super_L Super_R&lt;br /&gt;add Mod5 = Mode_switch ISO_Level3_Shift ISO_Level3_Shift ISO_Level3_Shift&lt;br /&gt;&lt;br /&gt;keycode 0x7D = equal&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This file will be referenced the next time you log in and all should be sweet in the world! :)&lt;br /&gt;&lt;br /&gt;And that it should be it.... until the next Ubuntu release!&lt;br /&gt;&lt;br /&gt;Also have a look &lt;a href="https://help.ubuntu.com/community/AppleKeyboard"&gt;here&lt;/a&gt; for alternative solutions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6332103700596210661?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6332103700596210661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6332103700596210661' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6332103700596210661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6332103700596210661'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/07/apple-silver-keyboard-on-ubuntu-904.html' title='Apple Silver Keyboard on Ubuntu 9.0.4'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-8211737305364603136</id><published>2009-06-25T14:45:00.005+10:00</published><updated>2009-06-25T15:04:16.103+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Firestarter'/><category scheme='http://www.blogger.com/atom/ns#' term='sendmsg'/><category scheme='http://www.blogger.com/atom/ns#' term='VPNC'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>VPNC with Firestarter</title><content type='html'>I had been using vpnc to connect to work for a while now. I was using Ubuntu 8.0.4 and recently upgraded to 8.10. Suddenly my vpnc would not work. I couldn't ping any of the target computers without getting this error:&lt;br /&gt;&lt;pre name="code" class="java"&gt;sendmsg: Operation not permitted&lt;br /&gt;&lt;/pre&gt;After googling around I found the answer &lt;a href="http://ubuntuforums.org/showthread.php?t=695072"&gt;here&lt;/a&gt; and &lt;a href="http://www.lamnk.com/blog/vpn/using-firestarter-with-cisco-vpn-client/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Basically what you need to do is:&lt;br /&gt;&lt;br /&gt;1. Make the &lt;span style="font-weight: bold;"&gt;/etc/firestarter/user-pre&lt;/span&gt; file editable with &lt;span style="font-weight: bold;"&gt;chmod 600&lt;/span&gt; or equivalent.&lt;br /&gt;2. Edit  the &lt;span style="font-weight: bold;"&gt;user-pre&lt;/span&gt; file as &lt;span style="font-weight: bold;"&gt;sudo&lt;/span&gt; and add the following replacing xxx.xxx.xx.xxx with the ip of your gateway:&lt;br /&gt;&lt;pre name="code" class="java"&gt;iptables -A INPUT -j ACCEPT -s xxx.xxx.xx.xxx -p esp&lt;br /&gt;iptables -A INPUT -j ACCEPT -s xxx.xxx.xx.xxx -p udp -m multiport --sports isakmp,10000&lt;br /&gt;iptables -A INPUT -j ACCEPT -i tun+&lt;br /&gt;iptables -A OUTPUT -j ACCEPT -d xxx.xxx.xx.xxx -p esp&lt;br /&gt;iptables -A OUTPUT -j ACCEPT -d xxx.xxx.xx.xxx -p udp -m multiport --dports isakmp,10000&lt;br /&gt;iptables -A OUTPUT -j ACCEPT -o tun+&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;3. Save and exit&lt;br /&gt;4. Restart &lt;span style="font-weight: bold;"&gt;firestarter&lt;/span&gt; with &lt;span style="font-weight: bold;"&gt;sudo ./etc/init.d/firestarter restart&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;That should make it all work again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-8211737305364603136?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/8211737305364603136/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=8211737305364603136' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8211737305364603136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8211737305364603136'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/06/vpnc-with-firestarter.html' title='VPNC with Firestarter'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-2185139985559086445</id><published>2009-06-12T09:59:00.004+10:00</published><updated>2009-06-12T10:08:04.320+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Internet Usage'/><category scheme='http://www.blogger.com/atom/ns#' term='Pondskum'/><category scheme='http://www.blogger.com/atom/ns#' term='Bigpond'/><category scheme='http://www.blogger.com/atom/ns#' term='opensource'/><category scheme='http://www.blogger.com/atom/ns#' term='Googlecode'/><title type='text'>Pondskum Lives!</title><content type='html'>After recently having moved to &lt;a href="http://www.bigpond.com/"&gt;Bigpond&lt;/a&gt; (no thanks to IINET not getting their sh*t together) I wanted to install a linux widget that displayed my current Internet usage. It's easy enough to log into Bigpond but it's cumbersome and involves multiple clicks when all you want to know is your usage.&lt;br /&gt;&lt;br /&gt;With &lt;a href="http://code.google.com/p/pondskum/"&gt;Pondskum&lt;/a&gt;, I've created a small opensource Java API that logs into your Bigpond account and screen-scrapes (yukk!) data and gives it back to you in a bean. If only Bigpond had a webservice that provided usage information!&lt;br /&gt;&lt;br /&gt;I've created 2 guis from the API. One command-line which gives you basic usage information like totals etc and a Swing version that gives you a day-by-day usage table for the current billing month.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://pondskum.googlecode.com/svn/wiki/images/pondskum-1.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 600px; height: 400px;" src="http://pondskum.googlecode.com/svn/wiki/images/pondskum-1.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This will work until the Bigpond site is redesigned. Have a look if you need an easy way to find out your Internet usage data.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-2185139985559086445?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/2185139985559086445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=2185139985559086445' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2185139985559086445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2185139985559086445'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/06/pondskum-lives.html' title='Pondskum Lives!'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4777540750435932841</id><published>2009-04-29T10:41:00.014+10:00</published><updated>2009-05-07T21:58:24.679+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Deploy'/><category scheme='http://www.blogger.com/atom/ns#' term='Subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='Googlecode'/><title type='text'>Deploying Maven Artifacts to Googlecode</title><content type='html'>Recently I need to deploy a snapshot of one of my &lt;a href="http://code.google.com/p/pinthura/"&gt;opensource&lt;/a&gt; projects, into a &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt; repository so it could be used by another project. Having a quick look around it seemed that I needed to setup a Maven repository such as &lt;a href="http://archiva.apache.org/"&gt;Archiva&lt;/a&gt; or deploy to a site such as &lt;a href="https://maven2-repository.dev.java.net/"&gt;java.net&lt;/a&gt;. Neither prospect appealed to me very much.&lt;br /&gt;&lt;br /&gt;I had a look at &lt;a href="http://adams.id.au/blog/"&gt;Tom&lt;/a&gt;'s &lt;a href="http://code.google.com/p/instinct/"&gt;instinct&lt;/a&gt; project and noticed that he was using &lt;a href="http://code.google.com/"&gt;googlecode&lt;/a&gt; to host his artifacts. Now that's more like it! I came across &lt;a href="http://adams.id.au/blog/2008/08/deploying-a-maven-artefact-without-a-repository-using-ant/"&gt;this&lt;/a&gt; article that Tom had written on how to export artifacts from &lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt; into subversion. I didn't fancy using Ant as I wanted to go a purely maven route.&lt;br /&gt;&lt;br /&gt;Subsequently I came across &lt;a href="http://code.google.com/p/spring-maven-plugin/wiki/CreatingAMavenRepositoryInSubversion"&gt;this&lt;/a&gt; excellent blurb on how to deploy artifacts to a &lt;a href="http://www.webdav.org/"&gt;WebDAv&lt;/a&gt; server. The &lt;a href="http://code.google.com/u/ramon.nogueira/"&gt;author&lt;/a&gt; goes on to say that "&lt;i style="font-style: italic;"&gt;The trick to this one is to realize that when you share a Subversion repository over HTTP(S), it is actually implemented as a superset&lt;/i&gt;&lt;span style="font-style: italic;"&gt; of WebDAV&lt;/span&gt;". Who &lt;a href="http://subversion.tigris.org/webdav-usage.html"&gt;knew&lt;/a&gt;? That basically means you can use your subversion repository on googlecode as a WebDAv repository.&lt;br /&gt;&lt;br /&gt;Cool. I implemented his proposed solution and it all worked with minimal fussing around.&lt;br /&gt;&lt;br /&gt;So here are the steps I used to get this working:&lt;br /&gt;&lt;br /&gt;1. Update your project pom.xml with the following:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xhtml"&gt;&lt;br /&gt;&amp;lt;distributionManagement&amp;gt;&lt;br /&gt;      &amp;lt;repository&amp;gt;&lt;br /&gt;          &amp;lt;id&amp;gt;your-reposiotory-id&amp;lt;/id&amp;gt;&lt;br /&gt;          &amp;lt;name&amp;gt;your-reposiotory-name&amp;lt;/name&amp;gt;&lt;br /&gt;          &amp;lt;url&amp;gt;dav:https://your-googlecode-project/svn/maven/repository&amp;lt;/url&amp;gt;&lt;br /&gt;      &amp;lt;/repository&amp;gt;&lt;br /&gt;      &amp;lt;snapshotRepository&amp;gt;&lt;br /&gt;              &amp;lt;id&amp;gt;your-snapshot-repository-id&amp;lt;/id&amp;gt;&lt;br /&gt;              &amp;lt;url&amp;gt;dav:https://your-googlecode-project/svn/maven/repository-snapshot&amp;lt;/url&amp;gt;&lt;br /&gt;              &amp;lt;uniqueVersion&amp;gt;false&amp;lt;/uniqueVersion&amp;gt;&lt;br /&gt;      &amp;lt;/snapshotRepository&amp;gt;&lt;br /&gt;&amp;lt;/distributionManagement&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;build&amp;gt;&lt;br /&gt;      &amp;lt;extensions&amp;gt;&lt;br /&gt;              &amp;lt;extension&amp;gt;&lt;br /&gt;                      &amp;lt;groupId&amp;gt;org.apache.maven.wagon&amp;lt;/groupId&amp;gt;&lt;br /&gt;                      &amp;lt;artifactId&amp;gt;wagon-webdav&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                      &amp;lt;version&amp;gt;1.0-beta-2&amp;lt;/version&amp;gt;&lt;br /&gt;              &amp;lt;/extension&amp;gt;&lt;br /&gt;      &amp;lt;/extensions&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;2. Update your settings.xml with the following:&lt;br /&gt;&lt;pre name="code" class="xhtml"&gt;&lt;br /&gt;&amp;lt;servers&amp;gt;&lt;br /&gt;      &amp;lt;server&amp;gt;&lt;br /&gt;          &amp;lt;id&amp;gt;your-repository-id&amp;lt;/id&amp;gt;&lt;br /&gt;          &amp;lt;username&amp;gt;your-googlecode-username&amp;lt;/username&amp;gt;&lt;br /&gt;          &amp;lt;password&amp;gt;your-googlecode-password&amp;lt;/password&amp;gt;&lt;br /&gt;          &amp;lt;filePermissions&amp;gt;775&amp;lt;/filePermissions&amp;gt;&lt;br /&gt;          &amp;lt;directoryPermissions&amp;gt;775&amp;lt;/directoryPermissions&amp;gt;&lt;br /&gt;      &amp;lt;/server&amp;gt;&lt;br /&gt;  &amp;lt;/servers&amp;gt;&lt;br /&gt;&amp;lt;/settings&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The repository id from the pom and the server id from the settings.xml link up a repository with it's server properties. The wagon extension in the pom is needed to do the actual upload.&lt;br /&gt;&lt;br /&gt;Now to upload your artifact to your maven repository do a:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xhtml"&gt;&lt;br /&gt;mvn clean install deploy:deploy&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's about it if it all goes well. If you get an 401 http error or the like check the file and directory permissions under the server tag in your settings.xml.&lt;br /&gt;&lt;br /&gt;For a client to access your freshly created maven repository and artifacts, they need to add the following to an active profile in their settings.xml file:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xhtml"&gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;profiles&amp;gt;&lt;br /&gt;       &amp;lt;profile&amp;gt;&lt;br /&gt;           &amp;lt;id&amp;gt;active-profile-id&amp;lt;/id&amp;gt;&lt;br /&gt;           &amp;lt;repositories&amp;gt;&lt;br /&gt;               &amp;lt;repository&amp;gt;&lt;br /&gt;                   &amp;lt;id&amp;gt;snapshot-repository-id&amp;lt;/id&amp;gt;&lt;br /&gt;                   &amp;lt;url&amp;gt;http://your-googlecode-project/svn/maven/repository-snapshot&amp;lt;/url&amp;gt;&lt;br /&gt;               &amp;lt;/repository&amp;gt;&lt;br /&gt;               &amp;lt;repository&amp;gt;&lt;br /&gt;                   &amp;lt;id&amp;gt;release-repository-id&amp;lt;/id&amp;gt;&lt;br /&gt;                   &amp;lt;url&amp;gt;http://your-googlecode-project/svn/maven/repository&amp;lt;/url&amp;gt;&lt;br /&gt;               &amp;lt;/repository&amp;gt;&lt;br /&gt;           &amp;lt;/repositories&amp;gt;&lt;br /&gt;       &amp;lt;/profile&amp;gt;&lt;br /&gt;   &amp;lt;/profiles&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That should all work and now you can use your googlecode subversion as a maven repository! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4777540750435932841?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4777540750435932841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4777540750435932841' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4777540750435932841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4777540750435932841'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/04/deploying-maven-artifacts-to-googlecode.html' title='Deploying Maven Artifacts to Googlecode'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-283144165462401847</id><published>2009-04-28T21:10:00.007+10:00</published><updated>2009-04-28T21:28:23.145+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='No Machine'/><category scheme='http://www.blogger.com/atom/ns#' term='VNC'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 8.10'/><category scheme='http://www.blogger.com/atom/ns#' term='Remote Clients'/><title type='text'>No SSH - No No Machine</title><content type='html'>I've been using &lt;a href="http://www.nomachine.com/"&gt;No Machine&lt;/a&gt; to remote into machines for quite a while now and all I can say is that I'll never go back to VNC.&lt;br /&gt;&lt;br /&gt;I recently completely reinstalled my fileserver with &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; 8.10 and installed the no machine server in the recommended &lt;a href="http://www.nomachine.com/download-package.php?Prod_Id=722"&gt;way&lt;/a&gt;. I fired up the client and got a "connection refused on port 22". What thaa?&lt;br /&gt;&lt;br /&gt;It had been so long since I did a fresh installation of Ubuntu that I'd forgotten that Ubuntu ships with a SSH client but not the server. I found some useful info &lt;a href="http://www.cyberciti.biz/faq/ubuntu-linux-openssh-server-installation-and-configuration/"&gt;here&lt;/a&gt;. To get your system upto speed all you need to do is:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo apt-get install openssh-server openssh-client&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can test it with:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ssh your_user@localhost&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now your system can frolic in its No Machine goodness! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-283144165462401847?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/283144165462401847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=283144165462401847' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/283144165462401847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/283144165462401847'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/04/no-ssh-no-no-machine.html' title='No SSH - No No Machine'/><author><name>sanj sahayam</name><uri>http://www.blogger.com/profile/01161497777336386073</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6458441901554162997</id><published>2009-01-07T07:58:00.010+10:00</published><updated>2009-01-07T15:13:37.070+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Syntaxhighlighting'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><category scheme='http://www.blogger.com/atom/ns#' term='SVN'/><title type='text'>Syntax Highlighting Blogger Code</title><content type='html'>I finally decided to get some decent syntax highlighting going on blog posts. I hunted around and decided to use the rather cool &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;SyntaxHighlighter&lt;/a&gt;. I did run into a few problems though. I've document the steps I've used to get it working, below:&lt;br /&gt;&lt;br /&gt;1. Download the latest version of &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;SyntaxHighlighter &lt;/a&gt;&lt;br /&gt;2. Unrar the contents into a temporary directory.&lt;br /&gt;3. Host the exploded files on a web server somwhere or in subversion. (which has its own challenges. See below)&lt;br /&gt;4. Edit your blogger layout (Layout -&gt; Edit HTML)&lt;br /&gt;5. Add the following lines just above the end &amp;lt;/html&amp;gt; tag, changing http://pinthura.googlecode.com/svn/blogs to match your own path:&lt;br /&gt;&lt;br /&gt;&lt;textarea class="HTML" name="code"&gt;&lt;br /&gt;&amp;lt;link href="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" rel="stylesheet" type="text/css"&amp;gt;&amp;lt;/link&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shCore.js"/&amp;gt;  &lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shBrushCSharp.js"/&amp;gt;  &lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shBrushJava.js"/&amp;gt; &lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shBrushXml.js"/&amp;gt;  &lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shBrushCss.js"/&amp;gt;  &lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shBrushJScript.js"/&amp;gt;  &lt;br /&gt;&lt;br /&gt;&amp;lt;script language="javascript" src="http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/shBrushSql.js"/&amp;gt;&lt;p/&gt;&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The above adds support for the following:&lt;br /&gt;&lt;br /&gt;1. C#&lt;br /&gt;2. Java&lt;br /&gt;3. XML&lt;br /&gt;4. CSS&lt;br /&gt;5. Javascript&lt;br /&gt;6. SQL&lt;br /&gt;&lt;br /&gt;To add additional language support add the appropriate brush from the http://your_path_/dp.SyntaxHighlighter/Scripts/ directory.&lt;br /&gt;&lt;br /&gt;6. Add the following just before the &amp;lt;/body&amp;gt; tag:&lt;br /&gt;&lt;br /&gt;&lt;textarea class="HTML" name="code"&gt;&lt;br /&gt;&amp;lt;script language="javascript"&amp;gt;  &lt;br /&gt;&lt;br /&gt;window.onload = function () {&lt;br /&gt;&lt;br /&gt;  dp.SyntaxHighlighter.ClipboardSwf = 'http://pinthura.googlecode.com/svn/blogs/syntaxhighlighter/dp.SyntaxHighlighter/Scripts/clipboard.swf';   &lt;br /&gt;&lt;br /&gt;  dp.SyntaxHighlighter.BloggerMode();&lt;br /&gt;&lt;br /&gt;  dp.SyntaxHighlighter.HighlightAll(code);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7. To use highlight code use:&lt;br /&gt;&lt;br /&gt;&amp;lt;pre name="code" class="java" &amp;gt;&lt;br /&gt;//your java code here&lt;br /&gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&amp;lt;textarea name="code" class="java" &amp;gt;&lt;br /&gt;//your java code here&lt;br /&gt;&amp;lt;/textarea&amp;gt;&lt;br /&gt;&lt;br /&gt;If you are using a language other than java then check its alias &lt;a href="http://code.google.com/p/syntaxhighlighter/wiki/Languages"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Gotha's with SVN and CSS and HTML files&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One problem that had me stumped was that the CSS files could not be read from SVN although they were actually in SVN. The problem stems from using SVN as a HTML source directly and having the correct MIME types. CSS and HTML files by default are returned from http-accessed SVN as "text/plain" which is incorrect. For CSS files we need text/css and for html we need text/html. To achieve this do the following:&lt;br /&gt;&lt;br /&gt;Update your ~/.subversion/config file:&lt;br /&gt;1. Uncomment the line enable-auto-props = yes&lt;br /&gt;2. Add the following lines:&lt;br /&gt;*.html = svn:mime-type=text/html&lt;br /&gt;*.css = svn:mime-type=text/css&lt;br /&gt;&lt;br /&gt;Now if you import your files into SVN it will get returned with the correct mime types when access via the web.&lt;br /&gt;&lt;br /&gt;References&lt;br /&gt;&lt;br /&gt;1. &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;SyntaxHighlighter&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.kallisti.net.nz/blog/2006/08/setting-the-content-type-on-a-subversion-file/"&gt;Blog without an Important Name&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6458441901554162997?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6458441901554162997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6458441901554162997' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6458441901554162997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6458441901554162997'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/01/syntax-highlighting-blogger-code.html' title='Syntax Highlighting Blogger Code'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-1182917662897311506</id><published>2009-01-05T19:07:00.014+10:00</published><updated>2009-01-06T15:02:16.243+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>A Stab @ Reusing Test Code</title><content type='html'>&lt;div&gt;I've been looking a way to reuse test code for a while now. Who hasn't written some test code only to have to repeat it in another test class. This is specially the case when you use BDD and have separate test classes for each context.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;Refactoring tests does help but it doesn't seem to be the right solution. I've been experimenting with using Test Behaviour Handlers (TBH) to encapsulate the process of expecting, running and verifying code. It seems work quite well.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;The term TestBehaviourHandler, is one I've come up with, with my limited imagination! If there is another name for this "pattern" please let me know.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-size:130%;"&gt;What are the responsibilities of a TestBehaviourHandler?&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;div&gt;1. Encapulating all mocking (expectations, assertions, replaying, verifying etc)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;2. Ecapulating the method(s) under test. No data is returned. State is modified when methods return values. Assertions verify the returned values.&lt;br /&gt;&lt;br /&gt;3. (Optional) Since this models the Builder pattern, return the instance of the TBH from each method.&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-size:130%;"&gt;An Example&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;The &lt;a href="http://code.google.com/p/pinthura/"&gt;Pinthura&lt;/a&gt; project has a class called &lt;a href="http://code.google.com/p/pinthura/source/browse/branches/Release-0.2.0.0/core/src/main/java/com/googlecode/pinthura/util/RandomDataCreatorImpl.java?r=364"&gt;RandomDataCreatorImpl&lt;/a&gt; to generate random test data. We'll focus on the methods that generate random numeric data. Here's a snippet from the class:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public final class RandomDataCreatorImpl implements RandomDataCreator {&lt;br /&gt;&lt;br /&gt;private final MathBoundary mathBoundary;&lt;br /&gt;&lt;br /&gt;public RandomDataCreatorImpl(final MathBoundary mathBoundary) {&lt;br /&gt;this.mathBoundary = mathBoundary;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public int createNumber(final int value) {&lt;br /&gt;return (int) (mathBoundary.random() * value);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now we could write tests for this method of the form:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.googlecode.pinthura.boundary.java.lang.MathBoundary;&lt;br /&gt;import com.googlecode.pinthura.util.builder.RandomDataCreatorBuilder;&lt;br /&gt;import org.easymock.EasyMock;&lt;br /&gt;import org.easymock.IMocksControl;&lt;br /&gt;import static org.hamcrest.core.IsEqual.equalTo;&lt;br /&gt;import static org.junit.Assert.assertThat;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;public final class ARandomDataCreatorCreatingNumbersUnderTest {&lt;br /&gt;&lt;br /&gt;private final IMocksControl mockControl;&lt;br /&gt;private MathBoundary mockMathBoundary;&lt;br /&gt;private RandomDataCreator creator;&lt;br /&gt;&lt;br /&gt;public ARandomDataCreatorCreatingNumbersUnderTest() {&lt;br /&gt;mockControl = EasyMock.createControl();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Before&lt;br /&gt;public void setup() {&lt;br /&gt;mockMathBoundary = mockControl.createMock(MathBoundary.class);&lt;br /&gt;creator = new RandomDataCreatorBuilder().withMathBoundary(mockMathBoundary).build();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnZero() {&lt;br /&gt;expectNumber(0.001, 255, 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnAPositiveNumber() {&lt;br /&gt;expectNumber(0.98, 1000, 980);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnANegativeNumber() {&lt;br /&gt;expectNumber(0.5, -500, -250);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldNeverReturnTheSuppliedValue() {&lt;br /&gt;expectNumber(0.9999, 50, 49);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void expectNumber(final double randomValue, final int value, final int expectedVal) {&lt;br /&gt;EasyMock.expect(mockMathBoundary.random()).andReturn(randomValue);&lt;br /&gt;mockControl.replay();&lt;br /&gt;&lt;br /&gt;int number = creator.createNumber(value);&lt;br /&gt;assertThat(number, equalTo(expectedVal));&lt;br /&gt;&lt;br /&gt;mockControl.verify();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Suppose we now add a second method that generates random numbers between a range of supplied numbers:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public int createNumber(final int min, final int upperBoundary) {&lt;br /&gt;    int range = upperBoundary - min;&lt;br /&gt;    double randomValue = mathBoundary.random() * range;&lt;br /&gt;&lt;br /&gt;    if (min &amp;lt; 0) {&lt;br /&gt;        return (int) mathBoundary.floor(min + randomValue);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return (int) (min + randomValue);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A test case for this method might look like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.googlecode.pinthura.boundary.java.lang.MathBoundary;&lt;br /&gt;import com.googlecode.pinthura.util.builder.RandomDataCreatorBuilder;&lt;br /&gt;import org.easymock.EasyMock;&lt;br /&gt;import org.easymock.IMocksControl;&lt;br /&gt;import static org.hamcrest.core.IsEqual.equalTo;&lt;br /&gt;import static org.junit.Assert.assertThat;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;public final class ARandomDataCreatorCreatingBoundedNumbersUnderTest {&lt;br /&gt;&lt;br /&gt;private final IMocksControl mockControl;&lt;br /&gt;private MathBoundary mockMathBoundary;&lt;br /&gt;private RandomDataCreator creator;&lt;br /&gt;&lt;br /&gt;public ARandomDataCreatorCreatingBoundedNumbersUnderTest() {&lt;br /&gt;  mockControl = EasyMock.createControl();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Before&lt;br /&gt;public void setup() {&lt;br /&gt;  mockMathBoundary = mockControl.createMock(MathBoundary.class);&lt;br /&gt;  creator = new RandomDataCreatorBuilder().withMathBoundary(mockMathBoundary).build();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnABoundedNumber() {&lt;br /&gt;  expectBoundedNumber(0.5, 10, 20, 15);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnTheMinValue() {&lt;br /&gt;  expectBoundedNumber(0.0001, 300, 555, 300);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldNotReturnTheUpperBoundary() {&lt;br /&gt;  expectBoundedNumber(0.9999, 50, 100, 99);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void expectBoundedNumber(final double randomVal, final int minVal, final int upperBoundary, final int expectedVal) {&lt;br /&gt;  EasyMock.expect(mockMathBoundary.random()).andReturn(randomVal);&lt;br /&gt;  mockControl.replay();&lt;br /&gt;&lt;br /&gt;  int number = creator.createNumber(minVal, upperBoundary);&lt;br /&gt;  assertThat(number, equalTo(expectedVal));&lt;br /&gt;&lt;br /&gt;  mockControl.verify();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now this test is almost identical to the previous test.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We could refactor the tests into one test class. This would become messy rather quickly though with the number of methods increasing. Also there is another test case that tests for negative number ranges. This is to be added to a separate test class.&lt;br /&gt;&lt;br /&gt;Using the TBH for the above methods gives us:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.googlecode.pinthura.annotation.SuppressionReason;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;public final class ARandomDataCreatorCreatingNumbersUnderTest {&lt;br /&gt;&lt;br /&gt;@SuppressWarnings("InstanceVariableOfConcreteClass")&lt;br /&gt;@SuppressionReason(SuppressionReason.Reason.TEST_BEHAVIOUR_HANDLER)&lt;br /&gt;private ARandomDataCreatorCreatingNumbersTBH handler;&lt;br /&gt;&lt;br /&gt;@Before&lt;br /&gt;public void setup() {&lt;br /&gt;    handler = new ARandomDataCreatorCreatingNumbersTBH();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnZero() {&lt;br /&gt;    expectNumber(0.001, 255, 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnAPositiveNumber() {&lt;br /&gt;    expectNumber(0.98, 1000, 980);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnANegativeNumber() {&lt;br /&gt;    expectNumber(0.5, -500, -250);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldNeverReturnTheSuppliedValue() {&lt;br /&gt;    expectNumber(0.9999, 50, 49);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void expectNumber(final double randomValue, final int value, final int expectedVal) {&lt;br /&gt;    handler.expectRandomValue(randomValue).replay();&lt;br /&gt;    handler.createNumber(value).assertNumbersAreEqual(expectedVal).verify();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.googlecode.pinthura.annotation.SuppressionReason;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public final class ARandomDataCreatorCreatingBoundedNumbersUnderTest {&lt;br /&gt;&lt;br /&gt;@SuppressWarnings("InstanceVariableOfConcreteClass")&lt;br /&gt;@SuppressionReason(SuppressionReason.Reason.TEST_BEHAVIOUR_HANDLER)&lt;br /&gt;private ARandomDataCreatorCreatingNumbersTBH handler;&lt;br /&gt;&lt;br /&gt;@Before&lt;br /&gt;public void setup() {&lt;br /&gt;    handler = new ARandomDataCreatorCreatingNumbersTBH();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnABoundedNumber() {&lt;br /&gt;    expectBoundedNumber(0.5, 10, 20, 15);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldReturnTheMinValue() {&lt;br /&gt;    expectBoundedNumber(0.0001, 300, 555, 300);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;public void shouldNotReturnTheUpperBoundary() {&lt;br /&gt;    expectBoundedNumber(0.9999, 50, 100, 99);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void expectBoundedNumber(final double randomVal, final int minVal, final int upperBoundary, final int expectedVal) {&lt;br /&gt;    handler.expectRandomValue(randomVal).replay();&lt;br /&gt;    handler.createNumber(minVal, upperBoundary).assertNumbersAreEqual(expectedVal).verify();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The TestBehaviourHandler looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.googlecode.pinthura.annotation.SuppressionReason;&lt;br /&gt;import com.googlecode.pinthura.boundary.java.lang.MathBoundary;&lt;br /&gt;import com.googlecode.pinthura.util.builder.RandomDataCreatorBuilder;&lt;br /&gt;import org.easymock.EasyMock;&lt;br /&gt;import org.easymock.IMocksControl;&lt;br /&gt;import static org.hamcrest.core.IsEqual.equalTo;&lt;br /&gt;import static org.junit.Assert.assertThat;&lt;br /&gt;&lt;br /&gt;@SuppressWarnings({"MethodReturnOfConcreteClass"})&lt;br /&gt;@SuppressionReason(SuppressionReason.Reason.BUILDER_PATTERN)&lt;br /&gt;public final class ARandomDataCreatorCreatingNumbersTBH {&lt;br /&gt;&lt;br /&gt; private final IMocksControl mockControl;&lt;br /&gt; private MathBoundary mockMathBoundary;&lt;br /&gt; private RandomDataCreator creator;&lt;br /&gt; private int number;&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH() {&lt;br /&gt;     mockControl = EasyMock.createControl();&lt;br /&gt;     mockMathBoundary = mockControl.createMock(MathBoundary.class);&lt;br /&gt;     creator = new RandomDataCreatorBuilder().withMathBoundary(mockMathBoundary).build();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH replay() {&lt;br /&gt;     mockControl.replay();&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH createNumber(int value) {&lt;br /&gt;     number = creator.createNumber(value);&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH createNumber(int minVal, int upperBoundary) {&lt;br /&gt;     number = creator.createNumber(minVal, upperBoundary);&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH expectRandomValue(double randomVal) {&lt;br /&gt;     EasyMock.expect(mockMathBoundary.random()).andReturn(randomVal);&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH expectFlooredValue(double intermediateValue, double flooredValue) {&lt;br /&gt;     EasyMock.expect(mockMathBoundary.floor(intermediateValue)).andReturn(flooredValue);&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH verify() {&lt;br /&gt;     mockControl.verify();&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public ARandomDataCreatorCreatingNumbersTBH assertNumbersAreEqual(int expectedVal) {&lt;br /&gt;     assertThat(number, equalTo(expectedVal));&lt;br /&gt;     return this;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here are the tests for negative number ranges:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.googlecode.pinthura.annotation.SuppressionReason;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;public final class ARandomDataCreatorCreatingBoundedNegativeNumbersUnderTest {&lt;br /&gt;&lt;br /&gt;  @SuppressWarnings("InstanceVariableOfConcreteClass")&lt;br /&gt;  @SuppressionReason(SuppressionReason.Reason.TEST_BEHAVIOUR_HANDLER)&lt;br /&gt;  private ARandomDataCreatorCreatingNumbersTBH handler;&lt;br /&gt;&lt;br /&gt;  @Before&lt;br /&gt;  public void setup() {&lt;br /&gt;      handler = new ARandomDataCreatorCreatingNumbersTBH();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void shouldReturnTheMinValue() {&lt;br /&gt;      handler.expectRandomValue(0.001).expectFlooredValue(-9.995, -10).replay();&lt;br /&gt;      handler.createNumber(-10, -5).assertNumbersAreEqual(-10).verify();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void shouldNotReturnTheUpperBoundary() {&lt;br /&gt;      handler.expectRandomValue(0.999999).expectFlooredValue(-100.0001, -101).replay();&lt;br /&gt;      handler.createNumber(-200, -100).assertNumbersAreEqual(-101).verify();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void shouldReturnANumberBetweenNegativeAndPositveBounds() {&lt;br /&gt;      handler.expectRandomValue(0.4).expectFlooredValue(-1, -1).replay();&lt;br /&gt;      handler.createNumber(-5, 5).assertNumbersAreEqual(-1).verify();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The TestBehaviourHandler has been reused in the above test case as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;The Disadvantages&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. You have to write yet another class. (The TBH)&lt;br /&gt;2. You have to repeat the mocking code in each TBH.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;One improvement that has to be done is to move the mocking code into a common class allowing the user to supply additional test behaviour only. This would allow the user to focus only on the test behaviour and not the mocking/ setup  code.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;The Advantages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. Reuse of test code.&lt;br /&gt;2. Test cases are kept smaller.&lt;br /&gt;3. The tests are easier to read and maintain.&lt;br /&gt;&lt;br /&gt;I'll keep using this "pattern" and see how it can be improved. Any comments and/or suggestions are welcome.&lt;br /&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-1182917662897311506?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/1182917662897311506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=1182917662897311506' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1182917662897311506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1182917662897311506'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2009/01/stab-reusing-test-code.html' title='A Stab @ Reusing Test Code'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-8625819389389475765</id><published>2008-12-22T13:14:00.005+10:00</published><updated>2009-05-19T19:03:42.950+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='share folder'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='VirtualBox'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 8.0.4'/><title type='text'>Sharing a VirtualBox folder with Windows on Ubuntu</title><content type='html'>&lt;div class="ReadMsgBody BorderTop" onclick="return Control.invoke('ReadingPane', '_onBodyClick', event);"&gt;     &lt;div class="ExternalClass PlainTextMessageBody" id="MsgContainer"&gt;             &lt;pre&gt;1. Install &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt; and the &lt;span style="font-weight: bold;"&gt;guest additions&lt;/span&gt; on Ubuntu.&lt;br /&gt;&lt;br /&gt;2. Install a flavour of Windows on the virtual image.&lt;br /&gt;&lt;br /&gt;If you are using the &lt;span style="font-weight: bold;"&gt;open-source&lt;/span&gt; version do the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;1. To find out the the &lt;span style="font-weight: bold;"&gt;name&lt;/span&gt; (and other information) of your vm use&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;vboxmanage list vms&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;You should get a listing of the sort:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Name:            WindowsXP&lt;br /&gt;Guest OS:        Windows XP&lt;br /&gt;UUID:            ...&lt;br /&gt;Config file:     /home/sanjiv/.VirtualBox/Machines/WindowsXP/WindowsXP.xml&lt;br /&gt;Memory size:     2000MB&lt;br /&gt;VRAM size:       64MB&lt;br /&gt;Boot menu mode:  message and menu&lt;br /&gt;ACPI:            on&lt;br /&gt;IOAPIC:          off&lt;br /&gt;Time offset:     0 ms&lt;br /&gt;Hardw. virt.ext: off&lt;br /&gt;State:           powered off (since 2008-12-22T02:18:59.000000000)&lt;br /&gt;Monitor count:   1&lt;br /&gt;Floppy:          empty&lt;br /&gt;Primary master:  /home/sanjiv/.VirtualBox/Machines/WindowsXP/Snapshots/{...}.vdi (UUID: ...)&lt;br /&gt;Primary slave:   /home/sanjiv/.VirtualBox/Machines/WindowsXP/Snapshots/{...}.vdi (UUID: ...)&lt;br /&gt;DVD:             /home/sanjiv/.VirtualBox/VBoxGuestAdditions_1.5.6.iso (UUID: ...)&lt;br /&gt;NIC 1:           MAC: ..., Attachment: NAT, Cable connected: on, Trace: off (file: &lt;null&gt;), Type: Am79C973&lt;br /&gt;NIC 2:           disabled&lt;br /&gt;NIC 3:           disabled&lt;br /&gt;NIC 4:           disabled&lt;br /&gt;UART 1:          disabled&lt;br /&gt;UART 2:          disabled&lt;br /&gt;Audio:           disabled (Driver: Unknown)&lt;br /&gt;Clipboard Mode:  Bidirectional&lt;br /&gt;Shared folders:&lt;br /&gt;&lt;br /&gt;&lt;/null&gt;&lt;/pre&gt;To find out specific information about a vm use&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;vboxmanage showvminfo&lt;/span&gt; &lt;span style="font-style: italic;"&gt;name_of_vm&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. On linux run:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;vboxmanage&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;sharedfolder&lt;/span&gt; &lt;span style="font-style: italic;"&gt;name_of_vm&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;-name&lt;/span&gt; &lt;span style="font-style: italic;"&gt;name_of_share&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;-hostpath&lt;/span&gt; &lt;span style="font-style: italic;"&gt;path_to_shared_linux_folder&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;vboxmanage sharedfolder&lt;/span&gt; &lt;span style="font-style: italic;"&gt;"WindowsXP"&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;-name&lt;/span&gt; &lt;span style="font-style: italic;"&gt;"vbshare"&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;-hostpath&lt;/span&gt; &lt;span style="font-style: italic;"&gt;"/home/sanjiv/vbshare"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. On the Windows VM, open &lt;span style="font-weight: bold;"&gt;Devices -&gt; Shared Folders...&lt;/span&gt; It should list&lt;br /&gt;your shared folder:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://by122w.bay122.mail.live.com/att/GetAttachment.aspx?tnail=0&amp;amp;messageId=8f8329ad-cbec-4b23-8706-1977e3b29439&amp;amp;Aux=4%7C0%7C8CB31F225CB1700%7C" style="cursor: pointer;" alt="" onclick="return Control.invoke('ReadingPane', '_onAttachmentClick', event);" height="329" width="460" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. Run&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;net use&lt;/span&gt; &lt;span style="font-style: italic;"&gt;DRIVE_LETTER_FOR_SHARE \\&lt;span style="font-weight: bold;"&gt;vboxsvr&lt;/span&gt;\name_of_share&lt;/span&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;net use&lt;/span&gt; &lt;span style="font-style: italic;"&gt;s: \\&lt;span style="font-weight: bold;"&gt;vboxsvr\&lt;/span&gt;vbshare&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;use the literal &lt;span style="font-weight: bold;"&gt;vboxsvr&lt;/span&gt; as is.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now when you write to your &lt;span style="font-weight: bold;"&gt;S:&lt;/span&gt; drive from Windows, you can see the changes in the linux folder&lt;br /&gt;you shared and vice versa. In the above example the linux folder is &lt;span style="font-weight: bold;"&gt;&lt;span&gt;/home/sanjiv/vbshare&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;.&lt;br /&gt;&lt;br /&gt;If you are using &lt;span style="font-weight: bold;"&gt;closed-sourced&lt;/span&gt; edition of VirtualBox do the following to share a folder:&lt;br /&gt;&lt;br /&gt;1. &lt;/span&gt;&lt;/span&gt;In the Windows VM, open &lt;span style="font-weight: bold;"&gt;Devices -&gt; Shared Folders...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;2. Click the &lt;span style="font-weight: bold;"&gt;Add new shared folder&lt;/span&gt; button.&lt;br /&gt;&lt;br /&gt;3. Select the path to the folder to share and give the shared folder a name.&lt;br /&gt;&lt;br /&gt;4. Open a command prompt and type:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;net use&lt;/span&gt; YOUR_DRIVE_LETTER&lt;span style="font-weight: bold;"&gt;:&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;\\vboxsvr&lt;/span&gt;\NAME_OF_SHARE&lt;br /&gt;&lt;br /&gt;eg. &lt;span style="font-weight: bold;"&gt;net use &lt;/span&gt;F:&lt;span style="font-weight: bold;"&gt; \\vboxsvr&lt;/span&gt;\myshare&lt;br /&gt;&lt;br /&gt;5. Your share should now be visible within My Computer.&lt;br /&gt;&lt;/pre&gt;     &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-8625819389389475765?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/8625819389389475765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=8625819389389475765' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8625819389389475765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8625819389389475765'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/12/sharing-virtualbox-folder-with-windows.html' title='Sharing a VirtualBox folder with Windows on Ubuntu'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-7598551815925422087</id><published>2008-12-18T00:26:00.005+10:00</published><updated>2008-12-18T00:59:00.122+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Apple Keyboard'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 8.10'/><title type='text'>Silver Apple Keyboard on Ubuntu 8.10</title><content type='html'>&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Edit the file /etc/modprobe.d/options and add the line:&lt;br /&gt;&lt;em style="font-weight: bold;"&gt;options hid pb_fnmode=0&lt;/em&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Save the file and execute the following command:&lt;br /&gt;&lt;strong&gt;&lt;em&gt;sudo update-initramfs -u&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Reboot.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Add the following to your &lt;span style="font-weight: bold;"&gt;~/.Xmodmap&lt;/span&gt; file. Create the file if there isn't one.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;br /&gt;keycode 191  = Insert&lt;br /&gt;keycode 192  = Print Sys_Req&lt;br /&gt;keycode 193  = Scroll_Lock&lt;br /&gt;keycode 194  =  Pause Break&lt;br /&gt;keycode 195  =  XF86AudioMute&lt;br /&gt;keycode 196  =  XF86AudioPrev&lt;br /&gt;keycode 197  =  XF86AudioNext&lt;br /&gt;&lt;br /&gt;clear Shift&lt;br /&gt;clear Lock&lt;br /&gt;clear Control&lt;br /&gt;clear Mod1&lt;br /&gt;clear Mod2&lt;br /&gt;clear Mod3&lt;br /&gt;clear Mod4&lt;br /&gt;clear Mod5&lt;br /&gt;add    Shift   = Shift_L Shift_R&lt;br /&gt;add    Lock    = Caps_Lock&lt;br /&gt;add    Control = Control_L Control_R&lt;br /&gt;add    Mod1    = 0 Alt_L 0x007D&lt;br /&gt;add    Mod2    = Num_Lock&lt;br /&gt;add    Mod4    = Super_L Super_R&lt;br /&gt;add    Mod5    = Mode_switch ISO_Level3_Shift ISO_Level3_Shift ISO_Level3_Shift&lt;br /&gt;&lt;br /&gt;keycode 0x7D =  equal&lt;br /&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-style: italic;"&gt;I've removed the command and alt key swapping from the above. If you want the key swap add the following as well&lt;/span&gt;:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;br /&gt;keycode 37 =    Control_L&lt;br /&gt;keycode 133 =   Alt_L Meta_L&lt;br /&gt;keycode 64 =    Super_L&lt;br /&gt;keycode 108 =   Super_R&lt;br /&gt;keycode 134 =   ISO_Level3_Shift Multi_key&lt;br /&gt;keycode 105 =   Control_R       Multi_key&lt;br /&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Logout and then back in.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;References: &lt;a href="https://help.ubuntu.com/community/AppleKeyboard"&gt;Ubuntu community&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-7598551815925422087?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/7598551815925422087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=7598551815925422087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/7598551815925422087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/7598551815925422087'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/12/silver-apple-keyboard-on-ubuntu-810.html' title='Silver Apple Keyboard on Ubuntu 8.10'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6532725023374953895</id><published>2008-09-05T16:55:00.009+10:00</published><updated>2008-09-09T14:45:05.592+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Enum'/><title type='text'>Enumerations with Null Objects</title><content type='html'>&lt;span style="font-size:130%;"&gt;What's all this about?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since Java 1.5 we can simply define elements of a fixed set of values  with the &lt;span style="font-weight: bold;"&gt;enum&lt;/span&gt; keyword. When a method accepts an &lt;span style="font-weight: bold;"&gt;enum&lt;/span&gt;, you have to either use a value from the enumeration or &lt;span style="font-weight: bold;"&gt;null&lt;/span&gt; to call that method. Altough I've been designing to interfaces, I, for some reason, never used interfaces when using &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;enums&lt;/span&gt;. I've also been trying to avoid using nulls. To get around   using them, I added an extra element to the &lt;span style="font-weight: bold;"&gt;enum&lt;/span&gt; to represent a &lt;a href="http://www.cs.oberlin.edu/~jwalker/nullObjPattern/"&gt;null object&lt;/a&gt;. This was not great, since it polluted the enumeration and lead to unnecessary conditional code in some of the methods. In this post I look @ another way of using null objects, via interfaces, where enumerations are accepted.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Show me the problem!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For this example I'm going to take the monetary values of 10, 20 and 50 dollar notes as an enumeration. Say I need to work with these 3 notes for some purpose. I also added an element value for any other value that does not exist (a null value). The resulting enumeration would look something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public enum DollarValueEnum {&lt;br /&gt;&lt;br /&gt;NULL(-1), TEN(10), TWENTY(20), FIFTY(50);&lt;br /&gt;&lt;br /&gt;private final int numericValue;&lt;br /&gt;&lt;br /&gt;DollarValueEnum(final int numericValue) {&lt;br /&gt; this.numericValue = numericValue;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void print() {&lt;br /&gt; if (!this.name().equals(NULL.toString())) {&lt;br /&gt;     System.out.println("The value of this element is: " + numericValue);&lt;br /&gt; } else {&lt;br /&gt;     System.out.println("There is no value for this element.");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Due to the NULL element the print method is a little ugly with the if-else block.&lt;br /&gt;&lt;br /&gt;We can run the above through a runner like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public final class DollarValueRunner {&lt;br /&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt;  print(DollarValueEnum.TEN);&lt;br /&gt;  print(DollarValueEnum.TWENTY);&lt;br /&gt;  print(DollarValueEnum.FIFTY);&lt;br /&gt;  print(DollarValueEnum.NULL);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private static void print(final DollarValueEnum dv) {&lt;br /&gt;  dv.print();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We get the output:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;The value of this element is: 10&lt;br /&gt;The value of this element is: 20&lt;br /&gt;The value of this element is: 50&lt;br /&gt;There is no value for this element.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So the above code lets us use the 3 element values (10, 20 and 50) along with another value (NULL) representing any other value that might be used (say when we needed to signify that there was no dollar value for something).&lt;br /&gt;&lt;br /&gt;Some of the problems with the above are:&lt;br /&gt;&lt;br /&gt;* The enumeration needlessly knows about the NULL element. It should only know about the valid elements (10, 20 and 50).&lt;br /&gt;* Methods that accept the enumeration can't accept anything else (using concrete classes).&lt;div&gt;* If we need values of the enumeration for processing some data then we need to exclude the NULL element from the values returned.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Eg. If I need to find all the notes less than or equal to 20, then I would have to write something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public List&lt; DollarValueEnum&gt; findDollarValuesLessThanOrEqual(final int numericValue) {&lt;br /&gt;        List&lt; DollarValueEnum&gt; reducedList = new ArrayList&lt; DollarValueEnum&gt;();&lt;br /&gt;        for (DollarValueEnum dollarValue : getDollarValuesExcludingNull()) {&lt;br /&gt;            if (dollarValue.getNumericValue() &lt;= numericValue) {&lt;br /&gt;                reducedList.add(dollarValue);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return reducedList;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public List&lt; DollarValueEnum&gt; getDollarValuesExcludingNull() {&lt;br /&gt;        final DollarValueEnum[] dollarValues = DollarValueEnum.values();&lt;br /&gt;        return Arrays.asList(dollarValues).subList(1, dollarValues.length);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;What other ways can we do this?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We could rewrite the above such that the DollarValueEnum implements an interface and thereby allows us to have a null object implementation of that interface outside the enumeration:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public interface DollarValue {&lt;br /&gt;void print();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The enumeration would be updated as so:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public enum DollarValueEnum implements DollarValue {&lt;br /&gt;&lt;br /&gt;TEN(10), TWENTY(20), FIFTY(50);&lt;br /&gt;&lt;br /&gt; private final int numericValue;&lt;br /&gt;&lt;br /&gt; DollarValueEnum(final int numericValue) {&lt;br /&gt;     this.numericValue = numericValue;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void print() {&lt;br /&gt;     System.out.println("The value of this element is: " + numericValue);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A null object could now be implemented:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public final class NullDollarValue implements DollarValue {&lt;br /&gt;&lt;br /&gt;public void print() {&lt;br /&gt; System.out.println("There is no value for this element.");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can also dynamically swap between implementations of the DollarValue interface (coding to interfaces):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public final class DollarValueRunner {&lt;br /&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt; print(DollarValueEnum.TEN);&lt;br /&gt; print(DollarValueEnum.TWENTY);&lt;br /&gt; print(DollarValueEnum.FIFTY);&lt;br /&gt; print(new NullDollarValue());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private static void print(DollarValue dv) {&lt;br /&gt; dv.print();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output would be the same as before:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;The value of this element is: 10&lt;br /&gt;The value of this element is: 20&lt;br /&gt;The value of this element is: 50&lt;br /&gt;There is no value for this element.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Why go through the extra effort?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* We can see from the above that we can use the DollarValueEnum class or any implementation of the DollarValue interface with the print method. This gives us greater flexibility.&lt;br /&gt;* The enumeration has no concept of a null object. This keeps the enumeration simple.&lt;br /&gt;* It's easier to mock out the interface in interaction tests, rather than using state-based tests for enumerations.&lt;br /&gt;&lt;br /&gt;Eg. If a method returned an enumeration then we would have to test that it would return any one of the enumeration values - not just one. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DollarValueEnum findDollar(Criteria criteria) { .. } &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If an interface was returned, we could simply use mocks to verify that what was expected was always returned.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DollarValue findDollar(Criteria criteria) { .. }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;What are the draw backs?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* We obviously have more classes now to do the same job. (&lt;span style="font-style: italic;"&gt;Although we could combine the interface and enumeration and null object into one class and cut down the number classes&lt;/span&gt;.)&lt;br /&gt;* It's arguable that it's clearer to have all states within the &lt;span style="font-weight: bold;"&gt;enum&lt;/span&gt; (including a null state) as it makes the code clearer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6532725023374953895?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6532725023374953895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6532725023374953895' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6532725023374953895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6532725023374953895'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/09/enumerations-with-null-objects.html' title='Enumerations with Null Objects'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-306744184540838756</id><published>2008-08-01T02:10:00.004+10:00</published><updated>2008-08-01T02:44:30.104+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Display Drivers'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>nVidia Video Drivers on Hardy</title><content type='html'>After my lovely ATI x1950Pro refused to work nicely with Ubuntu 8.0.4, I ran out and bough myself an nVidia 8800GT. The video drivers were surprisingly easy to install and I was up-and-running in less than 30 mins! :)&lt;br /&gt;&lt;br /&gt;Here are the steps:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Before you start, &lt;/span&gt;&lt;a style="font-style: italic;" href="http://www.nvidia.com/Download/index.aspx?lang=en-us"&gt;download&lt;/a&gt;&lt;span style="font-style: italic;"&gt; the latest nVidia driver for the 8800GT (or your card). Note where you downloaded it to, as you will need it in the following steps.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. In a terminal window type:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sudo apt-get install build-essential&lt;/pre&gt;&lt;br /&gt;2. followed by:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sudo apt-get remove nvidia*&lt;/pre&gt;to get rid of any unwanted nVidia drivers. Also check /lib/linux-restricted-modules/`uname -r`/video and make sure there's no nvidia directory in there.&lt;br /&gt;&lt;br /&gt;3. Change to terminal mode by using Ctrl+ALT+F1. (F1 to F6 should work)&lt;br /&gt;&lt;br /&gt;4. Shutdown any remnant gmd processes with:&lt;br /&gt;&lt;pre&gt;sudo /etc/init.d/gdm stop&lt;/pre&gt;5. Go to the directory where you downloaded the latest nVidia driver and type:&lt;br /&gt;&lt;pre&gt;chmod a+x NVIDIA-Linux-x86_64-173.14.05-pkg2.run&lt;/pre&gt;Depending on which release of the driver you downloaded the .run filename may change.&lt;br /&gt;&lt;br /&gt;6. Run the driver with:&lt;br /&gt;&lt;pre&gt;sudo sh ./NVIDIA-Linux-x86_64-173.14.05-pkg2&lt;/pre&gt;7. Answer the questions on screen.&lt;br /&gt;&lt;br /&gt;8. If you get an error about not finding a compiled kernel for your driver version, ask the installer to compile one for you.&lt;br /&gt;&lt;br /&gt;9. You may get an error of the type "/usr/lib32/libGL.so.173.14.05 can't be found". Ignore this error and continue.&lt;br /&gt;&lt;br /&gt;10. Reboot your machine with:&lt;br /&gt;&lt;pre&gt;reboot&lt;/pre&gt;11. On logging into your machine, open a terminal and run:&lt;br /&gt;&lt;pre&gt;sudo nvidia-settings&lt;/pre&gt;&lt;br /&gt;This will launce nVidia's gui configuration tool for you to make any changes :)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eusJ0yRMX3I/SJHnZnlfdHI/AAAAAAAAARE/d5YVv1OPbO0/s1600-h/Screenshot-NVIDIA+X+Server+Settings.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_eusJ0yRMX3I/SJHnZnlfdHI/AAAAAAAAARE/d5YVv1OPbO0/s400/Screenshot-NVIDIA+X+Server+Settings.png" alt="" id="BLOGGER_PHOTO_ID_5229215069662835826" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You should have compiz running. Desktop effects should have defaulted to "Extra"&lt;br /&gt;&lt;br /&gt;12. Install the 32-bit compatibility libraries (not sure if you really need this, but, it made my installation more stable under compiz) with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sudo apt-get install ia32-libs&lt;/pre&gt;&lt;br /&gt;Enjoy! :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;References: [&lt;a href="http://ubuntuforums.org/showthread.php?t=819043&amp;amp;highlight=dual+monitor+8800GT"&gt;1&lt;/a&gt;] [&lt;a href="http://www.linuxquestions.org/questions/ubuntu-63/booting-into-the-terminal-in-ubuntu-550831/"&gt;2&lt;/a&gt;]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-306744184540838756?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/306744184540838756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=306744184540838756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/306744184540838756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/306744184540838756'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/08/nvidia-video-drivers-on-hardy.html' title='nVidia Video Drivers on Hardy'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eusJ0yRMX3I/SJHnZnlfdHI/AAAAAAAAARE/d5YVv1OPbO0/s72-c/Screenshot-NVIDIA+X+Server+Settings.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-3889735912760144992</id><published>2008-05-20T00:48:00.004+10:00</published><updated>2008-11-06T09:46:46.934+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Apple Keyboard'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 8.0.4'/><title type='text'>Hardy Apple Crumble</title><content type='html'>&lt;span style="font-size:100%;"&gt;&lt;b&gt;Update&lt;/b&gt;&lt;/span&gt; &lt;a href="https://help.ubuntu.com/community/AppleKeyboard"&gt;This&lt;/a&gt;  wiki page on the Ubuntu site addresses this issue in full.&lt;br /&gt;&lt;br /&gt;Following the resolution problem with Ubuntu 8.0.4, the next hurdle I had was getting my slim apple keyboard to play nice. Due to driver updates, after logging into Ubuntu the keyboard becomes unusable. I later read this &lt;a href="https://answers.launchpad.net/ubuntu/+question/28153"&gt;post&lt;/a&gt; which reassured me that I wasn't going mad. (or madder than I currently am!)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"pressing "Clear" (numlock key) results in right part of the main keyboard part (keys g-l on the middle row + keys around) to behave as a numeric pad. To set it back, I found after lengthy trial-error, that I have to press F5 (or F6, I'm not sure)."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After banging the F6 key, my keyboard returned to normal. Phew. The only problem now was that the function keys performed as if the previously vestigial Fn was pressed the whole time. So for example if I  pressed F1, it would decrease the brightness of my laptop screen! How annoying!&lt;br /&gt;&lt;br /&gt;After digging around the I found a &lt;a href="http://ph.ubuntuforums.com/showthread.php?t=570036#5"&gt;this&lt;/a&gt; excellent post which helped me turn off the default &lt;span style="font-weight: bold;"&gt;Fn&lt;/span&gt; key behaviour for apple keyboards.&lt;br /&gt;&lt;br /&gt;To get your apple keyboard back to how it functioned in Ubuntu 7.10 do the following:&lt;br /&gt;&lt;br /&gt;1. Add a file to the  &lt;span style="font-weight: bold;"&gt;/etc/modprobe.d/&lt;/span&gt; directory with the following contents:&lt;br /&gt;&lt;br /&gt;options hid pb_fnmode=2&lt;br /&gt;&lt;br /&gt;This turns off the default &lt;span style="font-weight: bold;"&gt;Fn&lt;/span&gt; key behaviour of always being on.&lt;br /&gt;&lt;br /&gt;2. Add the following to &lt;span style="font-weight: bold;"&gt;Preferences-&gt;Session-&gt;Startup Programs&lt;/span&gt; section:&lt;br /&gt;&lt;br /&gt;xmodmap -e 'keycode 77='&lt;br /&gt;&lt;br /&gt;This turns off the mapping for the "Clear" key (keycode 77) on the apple keyboard which is wreaking havoc.&lt;br /&gt;&lt;br /&gt;3. Restart your machine and enjoy the normality :)&lt;br /&gt;&lt;br /&gt;This is now a &lt;a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/201711"&gt;bug&lt;/a&gt;. Hopefully it will be resolved soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-3889735912760144992?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/3889735912760144992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=3889735912760144992' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3889735912760144992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3889735912760144992'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/05/hardy-apple-crumble.html' title='Hardy Apple Crumble'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-7747374258699034304</id><published>2008-05-20T00:10:00.005+10:00</published><updated>2008-05-20T00:48:15.902+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='1680x1050'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu 8.0.4'/><category scheme='http://www.blogger.com/atom/ns#' term='Resolution'/><title type='text'>Hardy Resolution</title><content type='html'>&lt;div style="text-align: justify;"&gt;I recently upgraded from Ubuntu 7.10 to 8.0.4 through the automatic update process. I naively assumed "this is linux....it will just work". Yes. I was wrong.&lt;br /&gt;&lt;br /&gt;Firstly I was running Ubuntu on my Dell Inspiron 6400 laptop which has a ATl Mobility Radeon X1400 graphics card. I had this all setup on 7.10 to run @ the native 1680x1050 resolution. 8.0.4 had dropped that back to 1440 x 1050. Great. I followed all the same steps I had in 7.10 to get back my previous resolution and it worked (thankfully) once I manually added my 1680x1050 resolution to the /etc/X11/xorg.conf file. The steps are outlined below:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. Disable composite extensions&lt;/span&gt;&lt;br /&gt;The proprietary ATI dirver (fglrx) does not yet support composite.extensions In order to disable composite extensions you have to edit the xorg.conf file:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo gedit /etc/X11/xorg.conf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and add these lines at the end of the&lt;span style="font-weight: bold;"&gt; /etc/X11/xorg.conf&lt;/span&gt; file:&lt;br /&gt;&lt;br /&gt;Section "Extensions"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Option "Composite" "0"&lt;/span&gt;&lt;br /&gt;EndSection&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. Install the ATI driver&lt;/span&gt;&lt;br /&gt;Open a terminal and enter the following in order to install the ATI driver:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo apt-get update&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo apt-get install linux-restricted-modules-$(uname -r)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo apt-get install xorg-driver-fglrx&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo depmod -a&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. Configure the driver&lt;/span&gt;&lt;br /&gt;Type in the following to update the &lt;span style="font-weight: bold;"&gt;xorg.conf &lt;/span&gt;file with the new driver:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo aticonfig --initial&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo aticonfig --overlay-type=Xv&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4. Completing the installation&lt;/span&gt;&lt;br /&gt;Restart the computer with the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo shutdown -r now&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5. Post installation check&lt;/span&gt;&lt;br /&gt;Upon restarting the machine you should be able to choose the screen resolution of 1680x1050 under the &lt;span style="font-weight: bold;"&gt;Preferences&lt;/span&gt; -&gt; &lt;span style="font-weight: bold;"&gt;Screen Resolution&lt;/span&gt; setting. If the screen resolution can't be found and the max resolution is still 1440x1050, edit the &lt;span style="font-weight: bold;"&gt;xorg.cof &lt;/span&gt;file and add the 1680x1050 resolution manually:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo edit /etc/X11/xorg.conf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Update the &lt;span style="font-weight: bold;"&gt;Modes&lt;/span&gt; section to include the 1680x1050 resolution:&lt;br /&gt;&lt;br /&gt;Section "Screen"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Identifier "Default Screen"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Device "Generic Video Card"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Monitor "Generic Monitor"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;DefaultDepth 24&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SubSection "Display"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Modes "1400x1050" &lt;span style="font-weight: bold;"&gt;"1680x1050"&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;EndSubSection&lt;br /&gt;EndSection&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Restart the computer with the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sudo shutdown -r now&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Check the &lt;span style="font-weight: bold;"&gt;Preferences&lt;/span&gt; -&gt; &lt;span style="font-weight: bold;"&gt;Screen Resolution&lt;/span&gt; setting  and change the resolution to 1680x1050.&lt;br /&gt;&lt;br /&gt;To  verify that the fgl driver has been installed correctly, run the following command to check its output to ensure the fglrx driver is installed properly:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;fglrxinfo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The output from the driver should read:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;display: :0.0 screen: 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;OpenGL vendor string: ATI Technologies Inc.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;OpenGL renderer string: ATI Mobility Radeon X1400&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;OpenGL version string: 2.1.7412 Release&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Enjoy! :)&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-7747374258699034304?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/7747374258699034304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=7747374258699034304' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/7747374258699034304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/7747374258699034304'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/05/hardy-resolution.html' title='Hardy Resolution'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6963310360585185329</id><published>2008-04-23T23:39:00.002+10:00</published><updated>2008-04-24T07:18:51.646+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Router'/><category scheme='http://www.blogger.com/atom/ns#' term='Firewall'/><category scheme='http://www.blogger.com/atom/ns#' term='Google Maps'/><title type='text'>Google Maps - Blocked</title><content type='html'>My wireless router recently stopped working and I was forced to recede to my Billion (BiPAC 7402L) wired router. After reconfiguring the full network, I found out from my flatmate that &lt;a href="http://maps.google.com.au/"&gt;Google Maps&lt;/a&gt; wasn't working. Strange. After verifying this I had a look @ the firewall settings on the router and Port 80 was open for outgoing TCP traffic.&lt;br /&gt;&lt;br /&gt;I turned off the firewall and Google maps was up and running, proving that it was indeed a firewall problem. On a whim I added a UDP firewall rule for port 80 for outgoing traffic and this solved the problem! Something about the way Google Maps works requires UDP - not just TCP/IP. All very strange! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6963310360585185329?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6963310360585185329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6963310360585185329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6963310360585185329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6963310360585185329'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/04/google-maps-blocked.html' title='Google Maps - Blocked'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5883596890496605453</id><published>2008-03-07T19:42:00.005+10:00</published><updated>2008-03-14T01:31:57.987+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring 2.5.2'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Spring Annotations Hierarchy</title><content type='html'>A while back I got this cryptic error:&lt;br /&gt;&lt;br /&gt;"No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".&lt;br /&gt;&lt;br /&gt;I had wired hibernate3.3 with Spring 2.5.2 through annotations on a Spring Web Services project.&lt;br /&gt;&lt;br /&gt;I checked the obvious:&lt;br /&gt;&lt;br /&gt;1. That I had declared my transaction boundaries using the @Transactional annotation.&lt;br /&gt;2. The Hibernate SessionFactory was being injected as expected.&lt;br /&gt;3. I was using the &amp;lt;tx:annotation-driven /&amp;gt; tag with the default transaction manager.&lt;br /&gt;&lt;br /&gt;All were used and created as expected. I was using Spring's &amp;lt;context:component-scan&amp;gt; tag to automatically scan for component (@Component and its derivatives) classes.&lt;br /&gt;&lt;br /&gt;I also had two configuration files:&lt;br /&gt;&lt;br /&gt;1. (The default) spring-ws-servlet.xml.&lt;br /&gt;2. (A custom) persistence.xml&lt;br /&gt;&lt;br /&gt;My &amp;lt;context:component-scan&amp;gt; tag was in the spring-ws-servlet.xml while my &amp;lt;tx:annotation-driven /&amp;gt; tag  was in the persistence.xml file. This worked fine if I wired the transactional bean explicitly in the persistence.xml file.  After using &amp;lt;context:component-scan &amp;gt; I removed the explicit declaration. Following this I got the stated error message. For some reason when annotations were being used to wire the beans, the &amp;lt;tx:annotation-driven /&amp;gt; tag was not "visible" to the beans loaded through annotations. Once I moved the &amp;lt;tx:annotation-driven /&amp;gt; tag to the spring-ws-servlet.xml config file it all worked and the error went away.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;beans ...&amp;gt;&lt;br /&gt;     ...          &lt;br /&gt;     &amp;lt;context:component-scan ...&amp;gt;&lt;br /&gt;     &amp;lt;tx:annotation-driven /&amp;gt;&lt;br /&gt;     ...     &lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It would seem that there is a hierarchy in Spring configuration files. Where those resolved first are visible to those loaded after them and those resolved after are not visible to those resolved before them. I discussed this with a colleague (Dan Everton) who mentioned that Spring has a parent-child relationship when resolving configuration files. "The parent configuration file is like a base class and the child configuration file like a subclass." I assume that the annotation-wired beans are part of the "parent" configuration and are thus visible to all other configurations loaded there after.&lt;br /&gt;&lt;br /&gt;I did some hunting around but couldn't find any documentation to support or negate this theory. But using this assumption and moving the &amp;lt;tx:annotation-driven /&amp;gt; tag to the "parent" configuration file made everything work.&lt;br /&gt;&lt;br /&gt;If anyone knows how these files are resolved please add a comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5883596890496605453?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5883596890496605453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5883596890496605453' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5883596890496605453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5883596890496605453'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/03/spring-annotations-hierarchy.html' title='Spring Annotations Hierarchy'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5623914492578572987</id><published>2008-02-20T00:28:00.006+10:00</published><updated>2008-02-20T00:42:44.016+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Veitch Lister Consulting'/><category scheme='http://www.blogger.com/atom/ns#' term='GridGain'/><category scheme='http://www.blogger.com/atom/ns#' term='Grid'/><title type='text'>Gaining through Grids</title><content type='html'>&lt;a href="http://adams.id.au/blog"&gt;Tom's&lt;/a&gt; got a blurb on the excellent Grid &lt;a href="http://adams.id.au/blog/2008/02/off-the-grid-presentation/"&gt;presentation&lt;/a&gt;Nick and he gave at the recent &lt;a href="http://www.qjug.org/"&gt;QJUG&lt;/a&gt;. Some pictures follow:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/R7roQD6_mWI/AAAAAAAAALA/jHE65z1Cs7Q/s1600-h/Image053.jpg"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/R7roQD6_mWI/AAAAAAAAALA/jHE65z1Cs7Q/s400/Image053.jpg" alt="" id="BLOGGER_PHOTO_ID_5168698884989360482" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Nick and Glen conspire&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_eusJ0yRMX3I/R7roYz6_mXI/AAAAAAAAALI/waTdfbOnh0E/s1600-h/Image054.jpg"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_eusJ0yRMX3I/R7roYz6_mXI/AAAAAAAAALI/waTdfbOnh0E/s400/Image054.jpg" alt="" id="BLOGGER_PHOTO_ID_5168699035313215858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Good questions as always&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7romj6_mYI/AAAAAAAAALQ/-4_CW4HbAkg/s1600-h/Image055.jpg"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7romj6_mYI/AAAAAAAAALQ/-4_CW4HbAkg/s400/Image055.jpg" alt="" id="BLOGGER_PHOTO_ID_5168699271536417154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Interesting punch-lines! :)&lt;br /&gt;&lt;br /&gt;Good work guys! :)&lt;br /&gt;&lt;br /&gt;Many thanx to the wonderful folks @ &lt;a href="http://www.veitchlister.com.au/"&gt;VLC&lt;/a&gt; for hosting and giving us the opportunity to work on such an interesting project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5623914492578572987?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5623914492578572987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5623914492578572987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5623914492578572987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5623914492578572987'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/02/gaining-through-grids.html' title='Gaining through Grids'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_eusJ0yRMX3I/R7roQD6_mWI/AAAAAAAAALA/jHE65z1Cs7Q/s72-c/Image053.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-3650051977930677509</id><published>2008-02-19T00:25:00.009+10:00</published><updated>2008-02-20T00:14:28.164+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Install'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Aaaargclipse!</title><content type='html'>Oh how I love installing and using wondrous &lt;a href="http://www.blogger.com/www.eclipse.org"&gt;Eclipse&lt;/a&gt;. It is a tool of fun and frolic not to mention of much utility.&lt;br /&gt;&lt;br /&gt;No. Not really. A while back I was trying to install Eclipse on 64-bit Ubuntu 7.10. Easy enough. I had done it several times before. So this should be a cinch right? Well not exactly. When I ran eclipse after installation I kept getting weird errors  such as:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;error while loading shared libraries: libgtk-x11-2.0.so.0: cannot open shared object file: No such file or directory&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yes, brilliant! So what does that tell me? Oh so I need libgtk-x11-2.0.so.0. So why don't I have it? What? I do? Ok....?&lt;br /&gt;&lt;br /&gt;Or the equally self-explanatory:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mWtz6_mRI/AAAAAAAAAKY/AUdYw7j9VKo/s1600-h/Screenshot-Eclipse.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mWtz6_mRI/AAAAAAAAAKY/AUdYw7j9VKo/s400/Screenshot-Eclipse.png" alt="" id="BLOGGER_PHOTO_ID_5168327761160280338" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Superb! Could I ask for  a more meaningful error message? Possibly. Definitely. Maybe. (Isn't that a movie?)&lt;br /&gt;&lt;br /&gt;After hours of trying to fix this problem by installing libraries I didn't need, I found out that I had installed the 32-bit version of Eclipse on my 64-bit OS. An error message of the sort "&lt;span style="font-style: italic;"&gt;I think you are trying to install a 32-bit version of Eclipse on a 64-bit platform. Are you sure you want to do this&lt;/span&gt;?" might have been nice. It would have saved me hours of what I like to call "&lt;span style="font-style: italic;"&gt;wasting time with Eclipse&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;So why did I install the wrong version of Eclipse? The eclipse &lt;a href="http://www.blogger.com/www.eclipse.org"&gt;website&lt;/a&gt;  detects the version of the OS you are running and &lt;span style="font-style: italic;"&gt;guides&lt;/span&gt; you to the appropriate download. So when I went to the site from 64-bit Ubuntu it took me to:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eusJ0yRMX3I/R7q7iT6_mVI/AAAAAAAAAK4/EYUE63s46Gg/s1600-h/Eclipse+Downloads.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_eusJ0yRMX3I/R7q7iT6_mVI/AAAAAAAAAK4/EYUE63s46Gg/s400/Eclipse+Downloads.png" alt="" id="BLOGGER_PHOTO_ID_5168649720498723154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now if I click on the "linux" link, it takes me to the 32-bit download, which is totally wrong for my platform and leads to hours of fun, installing superfluous libraries! Yay!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mcGz6_mTI/AAAAAAAAAKo/T-8C0oFLe9k/s1600-h/32bitEclipse.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mcGz6_mTI/AAAAAAAAAKo/T-8C0oFLe9k/s400/32bitEclipse.png" alt="" id="BLOGGER_PHOTO_ID_5168333688215148850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But if I click on the "Eclipse Classic 3.3.1.1" link it takes me to the correct 64-bit download:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mcOz6_mUI/AAAAAAAAAKw/SzuIHcC5z5A/s1600-h/64bitEclipse.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mcOz6_mUI/AAAAAAAAAKw/SzuIHcC5z5A/s400/64bitEclipse.png" alt="" id="BLOGGER_PHOTO_ID_5168333825654102338" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So why is the eclipse web site so confusing? It's probably the same the reason why eclipse is so hard to use! :)&lt;br /&gt;&lt;br /&gt;If you are installing eclipse on Ubuntu 64-bit, make sure you have the&lt;br /&gt;xxxx-&lt;span style="font-weight: bold;"&gt;gtk-x86_64&lt;/span&gt;.tar.gz version as opposed to the xxxx-&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;-&lt;span style="font-weight: bold;"&gt;gtk&lt;/span&gt;.tar.gz version.&lt;br /&gt;&lt;br /&gt;Enough Eclipse-bashing. Have you tried &lt;a href="http://www.jetbrains.com/idea/"&gt;Intellij &lt;/a&gt;btw? ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-3650051977930677509?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/3650051977930677509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=3650051977930677509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3650051977930677509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/3650051977930677509'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/02/aaaargclipse.html' title='Aaaargclipse!'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_eusJ0yRMX3I/R7mWtz6_mRI/AAAAAAAAAKY/AUdYw7j9VKo/s72-c/Screenshot-Eclipse.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-749551409028346081</id><published>2008-02-05T16:16:00.000+10:00</published><updated>2008-02-06T19:37:00.138+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Traits'/><category scheme='http://www.blogger.com/atom/ns#' term='Partial Implementation'/><title type='text'>Partial Implementations with Traits</title><content type='html'>A &lt;a href="http://www.scala-lang.org/intro/traits.html"&gt;trait&lt;/a&gt; in Scala is similar to an interface in Java. It's similar in the sense that it defines a contract (through methods signatures) as a Java interface would. It also has the capability of implementing the methods it defines, similar to an abstract class in Java. This is known as "partial implementation" as it implements some but not all of the methods on the trait. Traits can also be used as &lt;a href="http://www.scala-lang.org/intro/mixin.html"&gt;mixins&lt;/a&gt; to given functionality similar to multiple inheritance. In Java we &lt;span style="font-weight: bold;"&gt;implement&lt;/span&gt; interfaces and in Scala we &lt;span style="font-weight: bold;"&gt;extend&lt;/span&gt; traits.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;The examples below use the trait's partial implementation similar to that of abstract classes in Java. I know many people hate using abstract classes and inheritance for that matter, due to one reason or another (hard to test, complex, inflexible take your pick - or have a look @ Tom's article &lt;/span&gt;&lt;a style="font-style: italic;" href="http://adams.id.au/blog/2007/03/the-practical-problems-of-inheritance/"&gt;The practical problems of inheritance&lt;/a&gt;&lt;span style="font-style: italic;"&gt;). But everything has a time and a place. We are going to ignore the above (valid) arguments for the moment and see what traits can do for us by providing partial implementations. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So let's see this partial implementation jazz already.&lt;br /&gt;&lt;br /&gt;Suppose we had an interface similar to the &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/MouseEvent.html"&gt;java.awt.event.MouseListener&lt;/a&gt; interface. Most of the time you are only interested in 1 or 2 of the methods on this interface and providing implementations for the other methods is a pain in the rear. The &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/MouseAdapter.html"&gt;java.awt.event.MouseAdaptor &lt;/a&gt;class provides default implementations of all methods on the MouseListener interface, allowing the developer to override only the method(s) of interest. Let's create a similar   interface to the MouseListener interface in Java:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public interface JavaMouseEvent {}&lt;br /&gt;&lt;br /&gt;public interface JavaMouseListener {&lt;br /&gt;   void mouseClicked(JavaMouseEvent e);&lt;br /&gt;   void mousePressed(JavaMouseEvent e);&lt;br /&gt;   void mouseReleased(JavaMouseEvent e);&lt;br /&gt;   void mouseEntered(JavaMouseEvent e);&lt;br /&gt;   void mouseExited(JavaMouseEvent e);    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now say we are only interested in the &lt;span style="font-weight: bold;"&gt;mouseClicked &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;. We create our own adaptor class in the form of a trusty abstract class or a base class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public abstract class JavaMouseAdaptor implements JavaMouseListener {&lt;br /&gt;   @Override&lt;br /&gt;   public void mouseClicked(JavaMouseEvent e) {}&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void mouseEntered(JavaMouseEvent e) {}&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void mouseExited(JavaMouseEvent e) {}&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void mousePressed(JavaMouseEvent e) {}&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void mouseReleased(JavaMouseEvent e) {}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now we can handle the mouseClicked event as so:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class JavaEventHandler extends JavaMouseAdaptor {&lt;br /&gt;   @Override&lt;br /&gt;   public void mouseClicked(JavaMouseEvent e) {&lt;br /&gt;       System.out.println("The mouse has been clicked! Call the mouse brigade");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Scala we could do the above with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;trait ScalaMouseEvent&lt;br /&gt;&lt;br /&gt;trait ScalaMouseListener {&lt;br /&gt;   def mouseClicked(e: ScalaMouseEvent): Unit = {}&lt;br /&gt;   def mousePressed(e: ScalaMouseEvent): Unit = {}&lt;br /&gt;   def mouseReleased(e: ScalaMouseEvent): Unit = {}&lt;br /&gt;   def mouseEntered(e: ScalaMouseEvent): Unit = {}&lt;br /&gt;   def mouseExited(e: ScalaMouseEvent): Unit = {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;final class ScalaEventHandler extends ScalaMouseListener {&lt;br /&gt;   override def mouseClicked(e: ScalaMouseEvent): Unit = {&lt;br /&gt;       println("The mouse has been clicked! Call the mouse brigade")&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We essentially, have cut out the adaptor class - which we didn't need thanks to partial implementation of traits in Scala. This is also easier to maintain because the implementation is in the same location/File as the definition of the contract.&lt;br /&gt;&lt;br /&gt;If we wanted to look beyond default implementations of a trait, we could implement a pattern such as the &lt;a href="http://www.fluffycat.com/Java-Design-Patterns/Template/"&gt;Template pattern&lt;/a&gt;, through a trait with partial implementation.  Say we had a &lt;span style="font-style: italic;"&gt;process&lt;/span&gt;, and every &lt;span style="font-style: italic;"&gt;process&lt;/span&gt; had a &lt;span style="font-style: italic;"&gt;start, step1, step2, step3 and end&lt;/span&gt; stages. And further assume that each &lt;span style="font-style: italic;"&gt;process &lt;/span&gt;has a &lt;span style="font-style: italic;"&gt;processName&lt;/span&gt;. We could model the &lt;span style="font-style: italic;"&gt;process&lt;/span&gt; through the template pattern in Java like so:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface Process {&lt;br /&gt;   void start();&lt;br /&gt;   void step1();&lt;br /&gt;   void step2();&lt;br /&gt;   void step3();&lt;br /&gt;   void process();&lt;br /&gt;   void end();&lt;br /&gt;   String getProcessName();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public abstract class AbstractProcess implements Process {&lt;br /&gt;   public void start() {&lt;br /&gt;       System.out.println("Starting process: " + getProcessName());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public abstract void step1();&lt;br /&gt;   public abstract void step2();&lt;br /&gt;   public abstract void step3();&lt;br /&gt;&lt;br /&gt;   public void process() {&lt;br /&gt;       start();&lt;br /&gt;       step1();&lt;br /&gt;       step2();&lt;br /&gt;       step3();&lt;br /&gt;       end();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void end() {&lt;br /&gt;       System.out.println("ending process: " + getProcessName());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public abstract String getProcessName();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public final class ReviewProcess extends AbstractProcess {&lt;br /&gt;   @Override&lt;br /&gt;   public String getProcessName() {&lt;br /&gt;       return "Review Process";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void step1() {&lt;br /&gt;       System.out.println("processing step1");&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void step2() {&lt;br /&gt;       System.out.println("processing step2");&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void step3() {&lt;br /&gt;       System.out.println("processing step3");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We run the code with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new ReviewProcess().process();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output we receive is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Starting process: Review Process&lt;br /&gt;processing step1&lt;br /&gt;processing step2&lt;br /&gt;processing step3&lt;br /&gt;ending process: Review Process&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Scala we could do the same thing through a trait:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;trait Process {&lt;br /&gt;   def start:Unit = println("starting process: " + processName)&lt;br /&gt;&lt;br /&gt;   def step1:Unit&lt;br /&gt;   def step2:Unit&lt;br /&gt;   def step3:Unit&lt;br /&gt;&lt;br /&gt;   def end:Unit = println("ending process: " + processName)           &lt;br /&gt;&lt;br /&gt;   def process():Unit = {&lt;br /&gt;       start&lt;br /&gt;       step1&lt;br /&gt;       step2&lt;br /&gt;       step3&lt;br /&gt;       end&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   def processName: String&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;final class ReviewProcess extends Process {&lt;br /&gt;   override def step1(): Unit = println("processing step1")&lt;br /&gt;   override def step2(): Unit = println("processing step2")&lt;br /&gt;   override def step3(): Unit = println("processing step3")&lt;br /&gt;   override def processName(): String = "Review Process" &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we run the above code with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new ReviewProcess().process&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output we receive is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;starting process: Review Process&lt;br /&gt;processing step1&lt;br /&gt;processing step2&lt;br /&gt;processing step3&lt;br /&gt;ending process: Review Process&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The template pattern implementation is much more terse in Scala. Just as you could override methods on base class via the subclass in Java, you can override methods implemented on the trait with the &lt;span style="font-weight: bold;"&gt;override&lt;/span&gt; keyword from the extensions of the trait:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;final class AutomationProcess extends Process {&lt;br /&gt;   override def step1(): Unit = println("automating step1")&lt;br /&gt;   override def step2(): Unit = println("automating step2")&lt;br /&gt;   override def step3(): Unit = println("automating step3")&lt;br /&gt;   override def processName(): String = "Automation Process"&lt;br /&gt;   &lt;span style="color: rgb(51, 102, 255);"&gt;override def start = println("Commencing the following process: " + processName)&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Running the above through &lt;pre&gt;new AutomationProcess().process&lt;/pre&gt; yeilds:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Commencing the following process: Automation Process&lt;br /&gt;automating step1&lt;br /&gt;automating step2&lt;br /&gt;automating step3&lt;br /&gt;ending process: Automation Process&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we don't want an implementation to be overridden, we declare the method final, with &lt;span style="font-weight: bold;"&gt;def&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;final&lt;/span&gt;. For example to prevent the &lt;span style="font-weight: bold;"&gt;start&lt;/span&gt; method being overridden, we could use the following on the &lt;span style="font-weight: bold;"&gt;Process&lt;/span&gt; trait:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 51, 255);"&gt;final&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt; &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(51, 51, 255);"&gt;def&lt;/span&gt; start:Unit = println("starting process: " + processName)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Making the template methods final is a good practice when implemented using inheritance. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So the question is whether implementations on the trait are a good thing. Sure, it's flexible but it goes against some "standard" practices in Java. I find traits useful for instances like the MouseListener example, where I only ever have one use for the extension and where I don't really care about the other implementations. For the template pattern a delegation solution would be easier to use and maintain without partial implementations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-749551409028346081?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/749551409028346081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=749551409028346081' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/749551409028346081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/749551409028346081'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/02/partial-implementations-with-traits.html' title='Partial Implementations with Traits'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-1878536109183699027</id><published>2008-02-03T12:53:00.000+10:00</published><updated>2008-02-03T12:55:35.567+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='Gmail'/><title type='text'>Gmail Vulnerable to Sidejacking</title><content type='html'>"&lt;span style="font-style: italic;"&gt;Last August, security researcher and CEO of Errata Security Robert Graham demonstrated just how easy it could be access potentially serious user information. His technique (nicknamed sidejacking), intercepts session ID cookies from the WiFi signal and used for a number of purposes, including sending and receiving e-mail. This type of attack takes place after the end-user has securely logged on to a service. Virtually all companies provide a secure login portal, but many do not secure the connection thereafter, which exposes the end-user to potential hacking as described above. During his demonstration at the time, Graham said that Google Mail users could switch to https://mail.google.com and secure their session from such snooping—but he's now backed away from and qualified that statement.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Check out the full article &lt;a href="http://arstechnica.com/news.ars/post/20080201-report-google-mail-vulnerable-to-sidejacking-despite-ssl.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-1878536109183699027?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/1878536109183699027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=1878536109183699027' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1878536109183699027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1878536109183699027'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/02/gmail-vulnerable-to-sidejacking.html' title='Gmail Vulnerable to Sidejacking'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-8342946214242995096</id><published>2008-02-03T10:18:00.000+10:00</published><updated>2008-02-03T10:48:57.480+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lshw'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu: What's Under the Hood</title><content type='html'>I recently stumbled upon the rather useful &lt;a href="http://www.linuxcertif.com/man/1/lshw/"&gt;lshw &lt;/a&gt;command. The lshw command provides you with hardware configuration information of your machine. Its man page states:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"lshw is a small tool to extract detailed information on the hardware configuration  of  the  machine. It can report exact memory configuration, firmware version, mainboard configuration, CPU version and speed, cache configuration,  bus  speed,  etc.  on  DMI-capable x86 or IA-64 systems and on some PowerPC machines  (PowerMac G4 is known to work).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;It currently supports DMI (x86 and IA-64 only), OpenFirmware device tree  (PowerPC  only),  PCI/AGP, CPUID (x86), IDE/ATA/ATAPI, PCMCIA (only tested on x86),  SCSI and USB.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Some sample usages:&lt;br /&gt;&lt;br /&gt;For a summary of devices on your system:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;sudo lshw -short&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;H/W path               Device     Class       Description&lt;br /&gt;=========================================================&lt;br /&gt;                               system      Desktop Computer&lt;br /&gt;/0                                bus         K8M800-8237&lt;br /&gt;/0/0                              memory      128KB BIOS&lt;br /&gt;/0/4                              processor   AMD Sempron(tm) Processor 2800+&lt;br /&gt;/0/4/8                            memory      128KB L1 cache&lt;br /&gt;/0/4/9                            memory      256KB L2 cache&lt;br /&gt;/0/18                             memory      1536MB System Memory&lt;br /&gt;/0/18/0                           memory      1GB DIMM 400 MHz (2.5 ns)&lt;br /&gt;/0/18/1                           memory      512MB DIMM 400 MHz (2.5 ns)&lt;br /&gt;/0/e4000000                       bridge      K8M800 Host Bridge&lt;br /&gt;/0/e4000000/1                     bridge      VT8237 PCI bridge [K8T800/K8T890 South]&lt;br /&gt;/0/e4000000/1/0                   display     S3 Unichrome Pro VGA Adapter&lt;br /&gt;/0/e4000000/9          scsi0      storage     VT6421 IDE RAID Controller&lt;br /&gt;/0/e4000000/a          eth0       network     DGE-530T Gigabit Ethernet Adapter (rev 11)&lt;br /&gt;/0/e4000000/f          scsi3      storage     VIA VT6420 SATA RAID Controller&lt;br /&gt;/0/e4000000/f/0        /dev/sda   disk        186GB WDC WD2000JS-60M&lt;br /&gt;/0/e4000000/f/0/1      /dev/sda1  disk        Linux filesystem partition&lt;br /&gt;/0/e4000000/f/0/2      /dev/sda2  disk        166GB Extended partition&lt;br /&gt;/0/e4000000/f/0/2/5    /dev/sda5  disk        Linux filesystem partition&lt;br /&gt;/0/e4000000/f/0/2/6    /dev/sda6  disk        Linux swap / Solaris partition&lt;br /&gt;/0/e4000000/f/1        /dev/sdb   disk        298GB ST3320620AS&lt;br /&gt;/0/e4000000/f/1/1      /dev/sdb1  disk        298GB Extended partition&lt;br /&gt;/0/e4000000/f/1/1/5    /dev/sdb5  disk        Linux filesystem partition&lt;br /&gt;/0/e4000000/f.1                   storage     VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE&lt;br /&gt;/0/e4000000/f.1/0      ide0       bus         IDE Channel 0&lt;br /&gt;/0/e4000000/f.1/0/0    /dev/hda   disk        PIONEER DVD-RW DVR-110&lt;br /&gt;/0/e4000000/f.1/0/0/0  /dev/hda   disk&lt;br /&gt;/0/e4000000/10                    bus         VT82xxxxx UHCI USB 1.1 Controller&lt;br /&gt;/0/e4000000/10/1       usb1       bus         UHCI Host Controller&lt;br /&gt;/0/e4000000/10.1                  bus         VT82xxxxx UHCI USB 1.1 Controller&lt;br /&gt;/0/e4000000/10.1/1     usb2       bus         UHCI Host Controller&lt;br /&gt;/0/e4000000/10.2                  bus         VT82xxxxx UHCI USB 1.1 Controller&lt;br /&gt;/0/e4000000/10.2/1     usb3       bus         UHCI Host Controller&lt;br /&gt;/0/e4000000/10.3                  bus         VT82xxxxx UHCI USB 1.1 Controller&lt;br /&gt;/0/e4000000/10.3/1     usb4       bus         UHCI Host Controller&lt;br /&gt;/0/e4000000/10.4                  bus         USB 2.0&lt;br /&gt;/0/e4000000/10.4/1     usb5       bus         EHCI Host Controller&lt;br /&gt;/0/e4000000/11                    bridge      VT8237 ISA bridge [KT600/K8T800/K8T890 South]&lt;br /&gt;/0/e4000000/11.5                  multimedia  VT8233/A/8235/8237 AC97 Audio Controller&lt;br /&gt;/0/100                            bridge      K8M800 Host Bridge&lt;br /&gt;/0/101                            bridge      K8M800 Host Bridge&lt;br /&gt;/0/102                            bridge      K8M800 Host Bridge&lt;br /&gt;/0/103                            bridge      K8M800 Host Bridge&lt;br /&gt;/0/104                            bridge      K8M800 Host Bridge&lt;br /&gt;/0/105                            bridge      K8 [Athlon64/Opteron] HyperTransport Technology Configuration&lt;br /&gt;/0/106                            bridge      K8 [Athlon64/Opteron] Address Map&lt;br /&gt;/0/107                            bridge      K8 [Athlon64/Opteron] DRAM Controller&lt;br /&gt;/0/108                            bridge      K8 [Athlon64/Opteron] Miscellaneous Control&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;For information on a specific class of device (the classes can be retrieved by the above command) such memory:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;sudo lshw -C memory&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;*-firmware&lt;br /&gt;&lt;br /&gt;     description: BIOS&lt;br /&gt;     vendor: Award Software International, Inc.&lt;br /&gt;     physical id: 0&lt;br /&gt;     version: FB (12/07/2005)&lt;br /&gt;     size: 128KB&lt;br /&gt;     capacity: 448KB&lt;br /&gt;     capabilities: pci pnp apm upgrade shadowing cdboot bootselect socketedrom edd int13floppy360 int13floppy1200 int13floppy720 int13floppy2880 int5printscreen int9keyboard int14serial int17printer int10video acpi usb agp ls120boot zipboot biosbootspecification&lt;br /&gt;&lt;br /&gt;*-cache:0&lt;br /&gt;&lt;br /&gt;     description: L1 cache&lt;br /&gt;     physical id: 8&lt;br /&gt;     slot: Internal Cache&lt;br /&gt;     size: 128KB&lt;br /&gt;     capacity: 128KB&lt;br /&gt;     capabilities: synchronous internal write-back&lt;br /&gt;&lt;br /&gt;*-cache:1&lt;br /&gt;&lt;br /&gt;     description: L2 cache&lt;br /&gt;     physical id: 9&lt;br /&gt;     slot: External Cache&lt;br /&gt;     size: 256KB&lt;br /&gt;     capacity: 256KB&lt;br /&gt;     capabilities: synchronous internal write-back&lt;br /&gt;&lt;br /&gt;*-memory&lt;br /&gt;&lt;br /&gt;     description: System Memory&lt;br /&gt;     physical id: 18&lt;br /&gt;     slot: System board or motherboard&lt;br /&gt;     size: 1536MB&lt;br /&gt;&lt;br /&gt;  *-bank:0&lt;br /&gt;&lt;br /&gt;        description: DIMM 400 MHz (2.5 ns)&lt;br /&gt;        physical id: 0&lt;br /&gt;        slot: A0&lt;br /&gt;        size: 1GB&lt;br /&gt;        width: 64 bits&lt;br /&gt;        clock: 400MHz (2.5ns)&lt;br /&gt;&lt;br /&gt;   *-bank:1&lt;br /&gt;&lt;br /&gt;        description: DIMM 400 MHz (2.5 ns)&lt;br /&gt;        physical id: 1&lt;br /&gt;        slot: A1&lt;br /&gt;        size: 512MB&lt;br /&gt;        width: 64 bits&lt;br /&gt;        clock: 400MHz (2.5ns)&lt;br /&gt;&lt;br /&gt;Or to get CPU information:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;sudo lshw -C processor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; *-cpu&lt;br /&gt;      description: CPU&lt;br /&gt;      product: AMD Sempron(tm) Processor 2800+&lt;br /&gt;      vendor: Advanced Micro Devices [AMD]&lt;br /&gt;      physical id: 4&lt;br /&gt;      bus info: cpu@0&lt;br /&gt;      version: AMD Sempron(tm) Processor 2800+&lt;br /&gt;      slot: Socket 754&lt;br /&gt;      size: 1600MHz&lt;br /&gt;      capacity: 4GHz&lt;br /&gt;      width: 64 bits&lt;br /&gt;      clock: 200MHz&lt;br /&gt;      capabilities: fpu fpu_exception wp vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt x86-64 3dnowext 3dnow up pni lahf_lm&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Remember to run the command with &lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;sudo&lt;/span&gt;&lt;span style="font-style: italic;"&gt; or you will only get a partial list of results.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-8342946214242995096?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/8342946214242995096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=8342946214242995096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8342946214242995096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8342946214242995096'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/02/ubuntu-whats-under-hood.html' title='Ubuntu: What&apos;s Under the Hood'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-1130143850495526436</id><published>2008-01-30T11:33:00.000+10:00</published><updated>2008-01-30T22:58:06.380+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Media Center'/><category scheme='http://www.blogger.com/atom/ns#' term='Vista'/><category scheme='http://www.blogger.com/atom/ns#' term='Play from HDD'/><category scheme='http://www.blogger.com/atom/ns#' term='DVD'/><title type='text'>WMC Finally Becomes Useful!</title><content type='html'>I have a media server onto which I have backed up all my DVDs. And why not? No more searching through my DVD collection, or looking for DVDs which have been misplaced in the wrong covers  or worrying about whether my DVDs are scratched.&lt;br /&gt;&lt;br /&gt;Anyway, until today on Vista (Home Premium) I had to always use another program such as &lt;a href="http://www.cyberlink.com/"&gt;PowerDVD&lt;/a&gt; to watch these movies as &lt;a href="http://en.wikipedia.org/wiki/Windows_Media_Center"&gt;Windows Media Center &lt;/a&gt;(WMC) did not play DVDs off the hard drive - only movies from an optical drive. So you had a few options, either play the movie from the original DVD or mount your extracted DVD as a virtual drive using tools like &lt;a href="http://www.daemon-tools.cc/dtcc/announcements.php"&gt;Daemon Tools&lt;/a&gt;. Both were a little too cumbersome for me given that I had spent all this time extracting all my DVDs to my media server.&lt;br /&gt;&lt;br /&gt;I stumbled upon this excellent &lt;a href="http://www.mediacollege.com/microsoft/windows/media-center/dvd-library.html"&gt;link &lt;/a&gt;that details how to hack WMC to detect and play extracted DVDs. Yay! :) Since I got it working in under 2 minutes, I'll show you how:&lt;br /&gt;&lt;br /&gt;1. Open regdit.exe&lt;br /&gt;&lt;br /&gt;2. Browse to &lt;span style="font-weight: bold;"&gt;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Media Center\Settings\DvdSettings&lt;/span&gt;&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;3. Edit the &lt;span style="font-weight: bold;"&gt;ShowGallery&lt;/span&gt; value and change it from &lt;span style="font-weight: bold;"&gt;Play&lt;/span&gt; to &lt;span style="font-weight: bold;"&gt;Gallery&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_eusJ0yRMX3I/R5_WDmEnSeI/AAAAAAAAAI8/r9WdqiDRQEk/s1600-h/regedit.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_eusJ0yRMX3I/R5_WDmEnSeI/AAAAAAAAAI8/r9WdqiDRQEk/s320/regedit.png" alt="" id="BLOGGER_PHOTO_ID_5161079055237728738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;4. Restart your computer (Shock! Horror!) &lt;span style="font-style: italic;"&gt;Rumour has it that you needn't restart windows. See what works for you&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;5. Once your computer restarts, log in and start WMC. You should have a new option under &lt;span style="font-weight: bold;"&gt;TV + Movies&lt;/span&gt; named &lt;span style="font-weight: bold;"&gt;dvd library&lt;/span&gt;. Previously this was named &lt;span style="font-weight: bold;"&gt;dvd&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R5_WOWEnSfI/AAAAAAAAAJE/NiSKQzdmtp0/s1600-h/Dvd+Library.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R5_WOWEnSfI/AAAAAAAAAJE/NiSKQzdmtp0/s320/Dvd+Library.png" alt="" id="BLOGGER_PHOTO_ID_5161079239921322482" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;6. Select &lt;span style="font-weight: bold;"&gt;dvd library&lt;/span&gt;. You should see 2 default clips (Apollo13 and Vertigo) that ship with WMC.  If you are using the microsoft remote click the &lt;span style="font-weight: bold;"&gt;i (more)&lt;/span&gt; button or if you are using a mouse, right click on an empty portion of the screen. Choose &lt;span style="font-weight: bold;"&gt;Add Movies &lt;/span&gt;from the context menu that pops up.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_XL2EnSgI/AAAAAAAAAJM/BvHgMjZFMoU/s1600-h/addmovies.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_XL2EnSgI/AAAAAAAAAJM/BvHgMjZFMoU/s320/addmovies.png" alt="" id="BLOGGER_PHOTO_ID_5161080296483277314" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;7. Select &lt;span style="font-weight: bold;"&gt;Add folder to watch&lt;/span&gt; and click &lt;span style="font-weight: bold;"&gt;Next&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_Xj2EnShI/AAAAAAAAAJU/2-zjT27l1vE/s1600-h/addfolder2watch.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_Xj2EnShI/AAAAAAAAAJU/2-zjT27l1vE/s320/addfolder2watch.png" alt="" id="BLOGGER_PHOTO_ID_5161080708800137746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;8. Select where you want to add your movie folder from (remote share, local or a mixture). Choose &lt;span style="font-weight: bold;"&gt;Next&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R5_X0WEnSiI/AAAAAAAAAJc/_ctTr8Wg5XU/s1600-h/addfolderlocallyorremotely.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R5_X0WEnSiI/AAAAAAAAAJc/_ctTr8Wg5XU/s320/addfolderlocallyorremotely.png" alt="" id="BLOGGER_PHOTO_ID_5161080992267979298" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;9. Choose your location(s) and click &lt;span style="font-weight: bold;"&gt;Finish&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;10. In order to get icons for each of your movies you need to save a picture of the DVD cover into the same folder as the VIDEO_TS and AUDIO_TS directories for your movie. This file must be named folder.jpg.  Have a search on &lt;a href="http://images.google.com/"&gt;google image search&lt;/a&gt; (or other sources) for a cover picture of your DVD and download it and save it as folder.jpg. &lt;span style="font-style: italic;"&gt;You can use a tool like MS Paint (launched by typing &lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;mspaint &lt;/span&gt;&lt;span style="font-style: italic;"&gt;into a run box) or the excellent &lt;a href="http://www.getpaint.net/"&gt;Paint.Net&lt;/a&gt;, to do the conversion&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_ZG2EnSkI/AAAAAAAAAJs/OZ0xrShU7lc/s1600-h/icons.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_ZG2EnSkI/AAAAAAAAAJs/OZ0xrShU7lc/s320/icons.png" alt="" id="BLOGGER_PHOTO_ID_5161082409607187010" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;11. Here's an example of where I have extracted my Undercover Brother DVD to my hard disk and browsed to it through WMC:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_Y52EnSjI/AAAAAAAAAJk/xtfbavNrUU8/s1600-h/folder.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/R5_Y52EnSjI/AAAAAAAAAJk/xtfbavNrUU8/s320/folder.png" alt="" id="BLOGGER_PHOTO_ID_5161082186268887602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I also read about a WMC plugin called &lt;a title="My Movies 2" href="http://www.mymovies.dk/" target="_blank"&gt;&lt;strong&gt;My  Movies 2&lt;/strong&gt;&lt;/a&gt;  that does all of the above and more. A review can be found &lt;a href="http://www.connectedinternet.co.uk/2008/01/07/my-movies-2-watch-dvds-in-windows-media-centre/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-1130143850495526436?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/1130143850495526436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=1130143850495526436' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1130143850495526436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/1130143850495526436'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/01/wmc-finally-becomes-useful.html' title='WMC Finally Becomes Useful!'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_eusJ0yRMX3I/R5_WDmEnSeI/AAAAAAAAAI8/r9WdqiDRQEk/s72-c/regedit.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6971107324737983871</id><published>2008-01-25T01:01:00.000+10:00</published><updated>2008-01-25T01:16:42.539+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Vista'/><category scheme='http://www.blogger.com/atom/ns#' term='SB X-fi'/><title type='text'>Flaky Sound on Vista</title><content type='html'>I've got a Creative SB X-fi running on Windows Vista. Support for this card is very flaky on Vista, compared to the support on Windows XP. I've noticed intermittent audio failure on Vista for apparently no good reason! I've since found the culprit to be the &lt;span style="font-weight: bold;"&gt;Windows Audio Service&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;If you find your audio suddenly not working on Vista then:&lt;br /&gt;&lt;br /&gt;1. Launch the Services Console (type &lt;span style="font-style: italic;"&gt;services.msc&lt;/span&gt; in a run box)&lt;br /&gt;2. Right-click on the &lt;span style="font-weight: bold;"&gt;Windows Audio&lt;/span&gt; service and choose &lt;span style="font-style: italic;"&gt;stop&lt;/span&gt;.&lt;br /&gt;3. Once stopped, then start the service again by right-clicking on the &lt;span style="font-weight: bold;"&gt;Windows Audio&lt;/span&gt; service and choosing &lt;span style="font-style: italic;"&gt;start&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_eusJ0yRMX3I/R5iq0GEnSaI/AAAAAAAAAIc/hoKVmsV93kQ/s1600-h/Services_Console.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_eusJ0yRMX3I/R5iq0GEnSaI/AAAAAAAAAIc/hoKVmsV93kQ/s320/Services_Console.png" alt="" id="BLOGGER_PHOTO_ID_5159061185112787362" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you're lucky your audio should be working again! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6971107324737983871?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6971107324737983871/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6971107324737983871' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6971107324737983871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6971107324737983871'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/01/flaky-sound-on-vista.html' title='Flaky Sound on Vista'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_eusJ0yRMX3I/R5iq0GEnSaI/AAAAAAAAAIc/hoKVmsV93kQ/s72-c/Services_Console.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-2749943772493073679</id><published>2008-01-21T16:22:00.000+10:00</published><updated>2008-01-22T10:42:12.531+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Abstract Data Types. Pattern Matching'/><category scheme='http://www.blogger.com/atom/ns#' term='Algebraic Data Types'/><title type='text'>What is an Algebraic Data Type?</title><content type='html'>&lt;a href="http://blog.tmorris.net/"&gt;Tony Morris&lt;/a&gt; recently ran an excellent Scala course for some of the guys @ the &lt;a href="http://www.workingmouse.com/"&gt;office&lt;/a&gt;. The course really opened my eyes to the power of functional programming languages like Haskell and to the object-oriented/functional programming hybrid - Scala.&lt;br /&gt;&lt;br /&gt;Scala leverages all the goodness (or badness- as Tony might say) of Java. One of the main hindrances I found when moving to Scala and any functional programming language for that matter were, the concepts and and the terminology.&lt;br /&gt;&lt;br /&gt;In this post, I hope to shed some light on what an &lt;span style="font-style: italic;"&gt;Algebraic Data Type&lt;/span&gt; is.&lt;br /&gt;&lt;br /&gt;Here are some definitions I have found for algebraic data types:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;A type defined by giving several alternatives, each of which come with their own constructor. It usually comes with a way to decompose the type through pattern matching. The concept is found &lt;/span&gt;&lt;span style="font-style: italic;"&gt;in specification languages and functional programming languages. Algebraic data types can be emulated in Scala with case classes. - Programming in Scala&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;In computer programming, an algebraic data type is a datatype each of whose values is data from other datatypes wrapped in one of the constructors of the datatype. Any wrapped data is an argument to the constructor. In contrast to other datatypes, the constructor is not executed and the only way to operate on the data is to unwrap the constructor using pattern matching. - Wikipedia&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"It is using types to define an algebra" - Tony Morris&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While all of the above definitions are correct in some form or other, it doesn't make it easy for a new-comer to understand these concepts due to implementation details such as "constructors" , "pattern matching", "case classes". After much deliberation with Tony, we finally came up with a simple definition of an algebraic data type:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"An algebraic data type is  a classification&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;There. That's very easy to understand. Anything and everything around you can be classified. We do this in Java with classes. For example, Person could be an &lt;span style="font-style: italic;"&gt;algebraic data type&lt;/span&gt; with Barney and Fred as two elements of that type:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Person {}&lt;br /&gt;final class Fred extends Person {}&lt;br /&gt;final class Barney extends Person {}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You could use the values of Fred and Barney to figure out which Person element was being used. In Java you could do this by:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if (person instanceof Fred) {&lt;br /&gt;   //do something&lt;br /&gt;} else if (person instanceof Barney){&lt;br /&gt;   //do something else&lt;br /&gt;} else {&lt;br /&gt;   throw new IllegalArgumentException("There are only 2 people. I don't know what you are.") &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or if you used an enum:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   public enum Person {&lt;br /&gt;       Fred, Barney&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   ...&lt;br /&gt;   ...&lt;br /&gt;   switch (person) {&lt;br /&gt;       case Fred: //do something; break&lt;br /&gt;       case Barney: //do something else; break&lt;br /&gt;       default: //show error&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Scala you could pattern match (select the values of the algebraic data type) with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;person match {&lt;br /&gt;   case Fred =&gt; //do something&lt;br /&gt;   case Barney =&gt;// do something else&lt;br /&gt;   case _ =&gt; //handle this exceptional case.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;as you can see it is very similar to switching with an enumerated type in java. One main difference is that you can pull out values from a matched element  (deconstruct) if it were passed to its constructor:&lt;br /&gt;&lt;br /&gt;  if Fred had a constructor of the form:   &lt;pre&gt;Fred(name: String, surname: String)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-style: italic;"&gt;then we could match and deconstruct (pull out parameters) with:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   case Fred(name, surname) =&gt; //use name and surname.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Person could be called a &lt;span style="font-style: italic;"&gt;closed data type&lt;/span&gt; if it defined a finite set of member elements (&lt;span style="font-style: italic;"&gt;or closed sum type (to use more mathematical and rigorous terminology) - Tony&lt;/span&gt;). For example take a Java enum of Person:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public enum Person {&lt;br /&gt; &lt;br /&gt;   Fred("Flintstone"),&lt;br /&gt;   Barney("Rubble");&lt;br /&gt;&lt;br /&gt;   private final String surname;&lt;br /&gt; &lt;br /&gt;   private Person(final String surname) {&lt;br /&gt;       this.surname = surname;&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   public String getSurname() {&lt;br /&gt;       return surname;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We know that since we can't extend &lt;span style="font-style: italic;"&gt;enums&lt;/span&gt; externally that there are only ever 2 Person elements: Fred and Barney. In Scala a &lt;span style="font-style: italic;"&gt;closed data type&lt;/span&gt; could be implemented with a &lt;span style="font-style: italic;"&gt;sealed trait&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sealed trait Person&lt;br /&gt;final case class Fred(surname: String, age: Int) extends Person&lt;br /&gt;final case class Barney(salutation: String) extends Person&lt;br /&gt;&lt;br /&gt;   ...&lt;br /&gt;   ...&lt;br /&gt;   person match {&lt;br /&gt;     case Fred(surname, age) =&gt; println("Hello Fred " + surname + " your age is " +  age)&lt;br /&gt;     case Barney(salutation) =&gt; println("Hello " + salutation + " Barney")&lt;br /&gt;     case _ =&gt; println("Who are you?")&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Scala lets you define different constructors for each type unlike in Java &lt;span style="font-style: italic;"&gt;enums&lt;/span&gt; where all elements of a type have to have the same constructors.&lt;br /&gt;&lt;br /&gt;This contrasts with an &lt;span style="font-style: italic;"&gt;open data type&lt;/span&gt; like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Person {}&lt;br /&gt;final class Fred extends Person {}&lt;br /&gt;final class Barney extends Person {}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here Person could have an infinite number of subclasses or elements in its &lt;span style="font-style: italic;"&gt;algebraic data type&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Another confusing concept I came across was the &lt;span style="font-style: italic;"&gt;Abstract Data Type&lt;/span&gt;, which I sometimes confused with &lt;span style="font-style: italic;"&gt;Algebraic Data Types&lt;/span&gt;. An &lt;span style="font-style: italic;"&gt;abstract data type&lt;/span&gt; is an &lt;span style="font-style: italic;"&gt;algebraic data type&lt;/span&gt; (it's a classification) which does not expose the construction details of its elements. In Java it would be something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public abstract class Person {&lt;br /&gt; &lt;br /&gt;   public abstract String getName();&lt;br /&gt;&lt;br /&gt;   private Person() { }&lt;br /&gt; &lt;br /&gt;   private static class Fred extends Person {&lt;br /&gt;       @Override&lt;br /&gt;       public String getName() {&lt;br /&gt;           return "Fred";&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   private static class Barney extends Person {&lt;br /&gt;       @Override&lt;br /&gt;       public String getName() {&lt;br /&gt;           return "Barney";&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   public static Person createFred() {&lt;br /&gt;       return new Fred();&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   public static Person createBarney() {&lt;br /&gt;       return new Barney();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's an example of an &lt;span style="font-style: italic;"&gt;abstract data type&lt;/span&gt; in Scala written by Tony for &lt;a href="http://adams.id.au/blog/"&gt;Tom&lt;/a&gt;'s &lt;a href="http://adams.id.au/blog/2008/01/obi-is-born/"&gt;Obi&lt;/a&gt; project:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sealed trait Javac {&lt;br /&gt;   def apply(srcdir: SrcDir): Javac = this match {&lt;br /&gt;       case Javac_(_) =&gt; Javac_(Some(srcdir))&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   def srcdir(s: String) = apply(SrcDir.srcdir(s))&lt;br /&gt;&lt;br /&gt;   def srcdir = this match {&lt;br /&gt;       case Javac_(s) =&gt; s&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private final case class Javac_(srcdir: Option[SrcDir]) extends Javac&lt;br /&gt;&lt;br /&gt;object Javac {&lt;br /&gt;   def javac: Javac = Javac_(None)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since the Javac_ class is private the only way to instantiate the class is through the static javac method on the object JavaC.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-2749943772493073679?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/2749943772493073679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=2749943772493073679' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2749943772493073679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2749943772493073679'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/01/what-is-algebraic-data-type.html' title='What is an Algebraic Data Type?'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6368515599279277571</id><published>2008-01-18T01:20:00.001+10:00</published><updated>2008-01-18T02:00:55.046+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ghosting'/><category scheme='http://www.blogger.com/atom/ns#' term='x1950 Pro'/><category scheme='http://www.blogger.com/atom/ns#' term='Vista'/><category scheme='http://www.blogger.com/atom/ns#' term='ATI'/><title type='text'>DVD Ghosting On Vista</title><content type='html'>I recently noticed prominent ghosting on my Dell FPW2405, while, watching &lt;a href="http://www.imdb.com/title/tt0117500/"&gt;The Rock&lt;/a&gt; on my Vista (Home Premium) box. I hadn't watched a DVD on my PC in a while and I kept second-guessing myself as to whether it was a problem that already existed (with the display) or whether it was something new that I hadn't noticed until now. I was using a Sapphire ATI Radeon x1950 Pro graphics card.&lt;br /&gt;&lt;br /&gt;After some cursory research, I came to the conclusion that my Dell FPW2405 was to blame. Strangely enough I didn't have any ghosting on the copious amounts of TV series I watch on a regular basis. Hmmm. I didn't know what was going on and decided to buy a new monitor when the time and price was right.&lt;br /&gt;&lt;br /&gt;I recently stumbled across this &lt;a href="http://apcmag.com/7847/howto_fix_atis_video_smearing"&gt;post &lt;/a&gt;which alluded to a fix for problem I was having. After a quick registry hack, I noticed almost a 90% reduction in ghosting while watching DVDs! :) I have since installed the latest &lt;a href="http://game.amd.com/us-en/drivers_catalyst.aspx?p=vista32/common-vista32"&gt;ATI drivers &lt;/a&gt;and catalyst centre for the graphics card and everything is still working very well!&lt;br /&gt;&lt;br /&gt;In summary all you need to do is:&lt;br /&gt;&lt;br /&gt;1. Launch regedit&lt;br /&gt;2. Browse to &lt;span style="font-style: italic;"&gt;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video&lt;/span&gt;. There should be a many subfolders beneath this key which have a "0000" subkey. Find the subkey that had child folders (expandable) and browse to &lt;span style="font-style: italic;"&gt;0000\UMD\DXVA&lt;/span&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;.&lt;/span&gt;&lt;br /&gt;3. Right-click on the view pane and choose &lt;span style="font-weight: bold;"&gt;New-&gt;String value&lt;/span&gt; and create the key values below:&lt;br /&gt;&lt;p style="font-weight: bold;"&gt;TRDenoise = 0&lt;br /&gt;DXVA_DetailEnhance = 0&lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/R493pBxC9uI/AAAAAAAAAH4/wtZtZtEwBuQ/s1600-h/ghosting-vista-x1950pro.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/R493pBxC9uI/AAAAAAAAAH4/wtZtZtEwBuQ/s320/ghosting-vista-x1950pro.png" alt="" id="BLOGGER_PHOTO_ID_5156471645094999778" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. Restart your computer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;If you have a copy of &lt;a href="http://www.imdb.com/title/tt0117500/"&gt;The Rock &lt;/a&gt;, have a look @ the first 10 minutes of the movie where the commandos break into the army artillery. There should be severe ghosting before the fix.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6368515599279277571?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6368515599279277571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6368515599279277571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6368515599279277571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6368515599279277571'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2008/01/dvd-ghosting-on-vista.html' title='DVD Ghosting On Vista'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_eusJ0yRMX3I/R493pBxC9uI/AAAAAAAAAH4/wtZtZtEwBuQ/s72-c/ghosting-vista-x1950pro.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-4485613648298605189</id><published>2007-12-28T16:51:00.000+10:00</published><updated>2007-12-28T20:26:24.187+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='hashCode'/><category scheme='http://www.blogger.com/atom/ns#' term='equals'/><title type='text'>You can't Skimp on HashCode</title><content type='html'>I sometimes use hashCode() like it's a necessary evil when overriding equals() (override hashCode() when you override equals() has been drummed into my head over and over again).&lt;br /&gt;&lt;br /&gt;The hashCode() method has a few nuances worth noticing. If you ever add your  Objects into a hash such a HashSet or a HashMap, it will take precedence over the equals() method when comparing Objects. This is quite subtle and it makes sense when you think about it for a while.&lt;br /&gt;&lt;br /&gt;Say you create the ubiquitous Person class with a name, surname and age.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package com.blogspot.babyloncandle;&lt;br /&gt;&lt;br /&gt;public final class Person {&lt;br /&gt;&lt;br /&gt;  private String name;&lt;br /&gt;  private String surname;&lt;br /&gt;  private int age;&lt;br /&gt;&lt;br /&gt;  public Person(final String name, final String surname,&lt;br /&gt;      final int age) {&lt;br /&gt;      this.name = name;&lt;br /&gt;      this.surname = surname;&lt;br /&gt;      this.age = age;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String getName() {&lt;br /&gt;      return name;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String getSurname() {&lt;br /&gt;      return surname;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int getAge() {&lt;br /&gt;      return age;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public int hashCode() {&lt;br /&gt;      return surname.hashCode();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public boolean equals(final Object obj) {&lt;br /&gt;      if (obj == null || !(obj instanceof Person)) {&lt;br /&gt;          return false;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      final Person incoming = (Person) obj;&lt;br /&gt;      return incoming.getSurname().equals(surname);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Say we initially state that any Person with the same Sunrname is equal. The hashCode() implementation also returns a value based on the Surname for a Person.&lt;br /&gt;&lt;br /&gt;Using &lt;a href="http://code.google.com/p/instinct/"&gt;Instinct&lt;/a&gt;, we could then create a &lt;a href="http://code.google.com/p/instinct/wiki/InstinctIn2Minutes"&gt;Context&lt;/a&gt; for Person to specify that 2 People with the same surname are equal:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package com.blogspot.babyloncandle;&lt;br /&gt;&lt;br /&gt;import static com.googlecode.instinct.expect.Expect.expect;&lt;br /&gt;import com.googlecode.instinct.integrate.junit4.InstinctRunner;&lt;br /&gt;import com.googlecode.instinct.marker.annotate.Context;&lt;br /&gt;import com.googlecode.instinct.marker.annotate.Specification;&lt;br /&gt;import org.junit.runner.RunWith;&lt;br /&gt;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;@Context&lt;br /&gt;@RunWith(InstinctRunner.class)&lt;br /&gt;public class APersonContext {&lt;br /&gt;&lt;br /&gt;  @Specification&lt;br /&gt;  public void shouldEquatePeopleWithTheSameSurname() {&lt;br /&gt;     final Person person1 = new Person("Humpty", "Dumpty", 5);&lt;br /&gt;     final Person person2 = new Person("Lumpy", "Dumpty", 6);&lt;br /&gt;&lt;br /&gt;     expect.that(person1).isEqualTo(person2);&lt;br /&gt;&lt;br /&gt;     final Set&amp;lt;Person&amp;gt; uniquePeople = new HashSet&amp;lt;Person&amp;gt;();&lt;br /&gt;     uniquePeople.add(person1);&lt;br /&gt;     uniquePeople.add(person2);&lt;br /&gt;&lt;br /&gt;     expect.that(uniquePeople).isOfSize(1);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The specification passes with no dramas. Now if we change the hashCode() method of the Person object such that the hashCode is calculated on age:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public int hashCode() {&lt;br /&gt;      return age;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we rerun the specification, it fails with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;java.lang.AssertionError:&lt;br /&gt;Expected: &lt;1&gt;&lt;br /&gt;   got: &lt;2&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This implies that the uniquePeople Set now has 2 elements instead of 1. This almost seems counter-intuitive as we have not changed the implementation of the equals() method of Person.&lt;br /&gt;&lt;br /&gt;Why is the spec failing? It has to do with how equals() and hashCode() works. If 2 Objects are equal they MUST have the same hashCode(). (But 2 Objects with the same hashCode() need not be equal). We have now broken this contract. (as equals() works on Surname and hashCode() works on Age) The implications are more subtle though. The only reason the specification actually failed is because we used a hash implementation (HashSet) to store the 2 Person Objects.&lt;br /&gt;&lt;br /&gt;If we add a System.out.Println() to the equals() method of Person, we see that it is never called when it's in the Set. If we add a System.out.Println() to the hashCode() method of Person, we see that it is called for each Person Object within the Set.&lt;br /&gt;&lt;br /&gt;This has to do with the way hashing works in Java. The hashCode is used to select a "bucket" into which each Object is added. If Object are in different buckets (meaning they have different hashCodes) they are never compared for equality. This is very important, because, if you go against the equals/hashCode specification, your Objects could never be found in hash implementations.  If you revert the hashCode() of Person to use Surname, while retaining the System.out.Println() statements, you'll see that hashCode() is called on each Object before equals().&lt;br /&gt;&lt;br /&gt;So it's not just that you should override hashCode() when you override equals() as many people do automatically. (without paying much attention to the hashCode value). You should override it such that you always maintain their contracts or you could end up with hard-to find errors.&lt;br /&gt;&lt;br /&gt;Lots of people use a default value (eg. 42) for hashCode(). This satisfies the equals/hashCode contract. It is not so great for hash performance though, as all Objects land in the same bucket increasing processing time.&lt;br /&gt;&lt;br /&gt;You also have to be careful between choosing a highly unique hashCode (A bucket per equal Objects of a certain type - this leads to an massive increase of buckets) and choosing a hashCode that is not unique at all (1 bucket for all Objects - this could lead to large processing times). Depending on the performance requirements of your application,  you may need to make some compromises on the value of hashCode you choose to return.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-4485613648298605189?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/4485613648298605189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=4485613648298605189' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4485613648298605189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/4485613648298605189'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/12/you-can.html' title='You can&apos;t Skimp on HashCode'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-2477811860101754360</id><published>2007-12-23T14:52:00.001+10:00</published><updated>2008-02-20T11:07:36.578+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Vim'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu: Highlight me Vim</title><content type='html'>&lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; (Vi Improved) gives you many features over that of the standard Vi feature set such, as syntax highlighting, incremental searching, bracket matching and many others. Here's how to install Vim for Ubuntu:&lt;br /&gt;&lt;br /&gt;1. Run &lt;code&gt;sudo apt-get install vim&lt;/code&gt; from  a command prompt.&lt;br /&gt;2. Copy the the default &lt;code&gt;vimrc&lt;/code&gt; file from &lt;code&gt;/etc/vim&lt;/code&gt; to your home directory with with the name &lt;code&gt;.vimrc&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;cp /etc/vim/vimrc ~/.vimrc&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;3. &lt;code&gt;"&lt;/code&gt; denote commented features. Uncomment any features you want to turn on. To turn on syntax highlighting change &lt;code&gt;"syntax on&lt;/code&gt; to &lt;code&gt;syntax on&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;4. Open a java file to see the highlighting in action:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;vim yourfile.java&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eusJ0yRMX3I/R23uMxxC9qI/AAAAAAAAAHQ/BK1nPczNnGE/s1600-h/Screenshot-sanjivsahayam%40sanj-inspiron:+%7E-projects-BeanPropertyTester-src-au-com-greenbar-test-util.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_eusJ0yRMX3I/R23uMxxC9qI/AAAAAAAAAHQ/BK1nPczNnGE/s320/Screenshot-sanjivsahayam%40sanj-inspiron:+%7E-projects-BeanPropertyTester-src-au-com-greenbar-test-util.png" alt="" id="BLOGGER_PHOTO_ID_5147031852439238306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;5. If you get the following error:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;E319: Sorry, the command is not available in this version: syntax on&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;it means that you haven't installed vim properly and that you are using tinyVim which, comes standard with Ubuntu. Install Vim as per Step1 again and look out for any errors.&lt;br /&gt;&lt;br /&gt;The following is a list of features I use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;" This line should not be removed as it ensures that various options are&lt;br /&gt;" properly set to work with the Vim-related packages available in Debian.&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;runtime! debian.vim&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;" Vim5 and later versions support syntax highlighting. Uncommenting the next&lt;br /&gt;" line enables syntax highlighting by default.&lt;br /&gt;&lt;span style="color: rgb(51, 204, 255);"&gt;syntax on&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;" If using a dark background within the editing area and syntax highlighting&lt;br /&gt;" turn on this option as well&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set background=dark&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;" The following are commented out as they cause vim to behave a lot&lt;br /&gt;" differently from regular Vi. They are highly recommended though.&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set showcmd       &lt;/span&gt; " Show (partial) command in status line.&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set showmatch       &lt;/span&gt; " Show matching brackets.&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set ignorecase       &lt;/span&gt; " Do case insensitive matching&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set smartcase       &lt;/span&gt; " Do smart case matching&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set incsearch&lt;/span&gt;        " Incremental search&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set autowrite&lt;/span&gt;        " Automatically save before commands like :next and :make&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set hidden&lt;/span&gt;             " Hide buffers when they are abandoned&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set mouse=a&lt;/span&gt;        " Enable mouse usage (all modes) in terminals&lt;br /&gt;&lt;br /&gt;" Source a global configuration file if available&lt;br /&gt;" XXX Deprecated, please move your changes here in /etc/vim/vimrc&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;if filereadable("/etc/vim/vimrc.local")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt; source /etc/vim/vimrc.local&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;endif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"this line is a comment .... one which begins with double-quotes&lt;br /&gt;" The best is the bold font, try all of these and pick one....&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set guifont=8x13bold&lt;/span&gt;&lt;br /&gt;"set guifont=9x15bold&lt;br /&gt;"set guifont=7x14bold&lt;br /&gt;"set guifont=7x13bold&lt;br /&gt;"&lt;br /&gt;" Highly recommended to set tab keys to 4 spaces&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set tabstop=4&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set shiftwidth=4&lt;/span&gt;&lt;br /&gt;"&lt;br /&gt;" The opposite is 'set wrapscan' while searching for strings....&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set nowrapscan&lt;/span&gt;&lt;br /&gt;"&lt;br /&gt;" The opposite is set noignorecase&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set ignorecase&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set autoindent&lt;/span&gt;&lt;br /&gt;"&lt;br /&gt;" You may want to turn off the beep sounds (if you want quite) with visual bell&lt;br /&gt;&lt;span style="color: rgb(51, 255, 255);"&gt;set vb&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-2477811860101754360?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/2477811860101754360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=2477811860101754360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2477811860101754360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2477811860101754360'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/12/ubuntu-highlight-me-vim.html' title='Ubuntu: Highlight me Vim'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eusJ0yRMX3I/R23uMxxC9qI/AAAAAAAAAHQ/BK1nPczNnGE/s72-c/Screenshot-sanjivsahayam%40sanj-inspiron:+%7E-projects-BeanPropertyTester-src-au-com-greenbar-test-util.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-396084122471729946</id><published>2007-12-21T01:13:00.000+10:00</published><updated>2007-12-21T16:23:07.884+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Intellij'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='Instinct'/><title type='text'>Configuring Eclipse Plugins May Cause Trauma, defection to Intellij</title><content type='html'>I've been trying to use &lt;a href="http://www.eclipse.org/"&gt;Eclipse &lt;/a&gt;in an environment where &lt;a href="http://www.jetbrains.com/idea/"&gt;Intellij&lt;/a&gt; was and is the IDE of choice. I hate to say it but, basic Eclipse plugins (such as for subversion and checksyle) are annoying to configure and use. Eg. The first thing that I was greeted with after installing the Subclipse plugin was a huge error message. Not exactly the confidence-building outcome you would expect.&lt;br /&gt;&lt;br /&gt;The plugins also take multiple steps to do somewhat simple configuration. While recently using a Checkstyle plugin (Eclipse-CS) I was forced to configure it via 3 separate routes for all the settings to take effect! (One through Windows-&gt;Preferences, one through Project properties, and one through the context menu) This is obviously way to hard for the average user, who would readily turn to Intellij where basic plugins are very easy to setup, requiring little configuration.&lt;br /&gt;&lt;br /&gt;I'm currently working on &lt;a href="http://code.google.com/p/instinct/"&gt;Instinct&lt;/a&gt; which was primarily developed using Intellij. We are now catering for Eclipse developers and want an even playing field for users and developers alike.&lt;br /&gt;To this end I've been creating how-tos on using basic plugins for  Eclipse.&lt;br /&gt;&lt;br /&gt;I am quite pleased with the progress Eclipse has made in the last few years and don't think Intellij is miles ahead of it as it was maybe 3 years ago. What we need are better plugins and more userfriendly features.&lt;br /&gt;&lt;br /&gt;The Harry Potter culture of Wizardry has got to stop! Wizards may seem to make your life easier initially but in the long run they make everything more prolong and confusing. Why click through 5 screens when you can set all your options in one place?&lt;br /&gt;&lt;br /&gt;I also found that shortcut keys could not be associated with these plugins in Eclipse, while Intellij lets you define shortcuts even for plugins. All pretty basic really. Why right click, click and click again when you can simply press a shortcut in 1/2 the time?&lt;br /&gt;&lt;br /&gt;How-tos on installing and configuring Subclipse and Eclipse-CS can be found below:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/instinct/wiki/SVNForEclipse"&gt;Installing and configuring Subclipse&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/instinct/wiki/CheckstyleForEclipse"&gt;Installing Eclipse-CS&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-396084122471729946?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/396084122471729946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=396084122471729946' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/396084122471729946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/396084122471729946'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/12/configuring-eclipse-plugins-may-cause.html' title='Configuring Eclipse Plugins May Cause Trauma, defection to Intellij'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-7081209591630199797</id><published>2007-12-04T21:13:00.000+10:00</published><updated>2007-12-05T22:47:41.026+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wireless Apple Keyboard Vista'/><title type='text'>Wireless Apple Keyboard on Vista</title><content type='html'>I recently purchased an Apple wireless keyboard. I blame it on being surrounded by Mac evangelists at the time. I had the quaint notion of using the keyboard on my Windows Vista box. To cut a long story short, I spent around a week trying to get the keyboard paired with my Asus bluetooth dongle (WL-BTD201M) and although I did succeed, the results were less than satisfactory. This was due to many reasons such as the keyboard being a Mac keyboard and Vista's flaky support for bluetooth. I say flaky because pairing the keyboard with a MacBook took around 20 seconds! I experienced unreliable bluetooth functionality on Vista with the connection reset every so often - too often to make it usable. Unlike other components on your system, if your keyboard or mouse is non-functional it gets frustrating pretty fast.&lt;br /&gt;&lt;br /&gt;Here's what I liked about the apple keyboard:&lt;br /&gt;&lt;br /&gt;1. Very small. See pic against my Microsoft keyboard.&lt;br /&gt;2. The keys are very nice to the touch and spaced exactly right.&lt;br /&gt;3. The bluetooth connection light emanates from an almost  invisible led on the keyboard.&lt;br /&gt;4. The packaging was fantastic as per usual Apple standard.&lt;br /&gt;5. The keyboard is one of the thinnest and lightest keyboards I have ever seen. See pic.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's what I disliked about it:&lt;br /&gt;&lt;br /&gt;1. It was maybe too small. I found it hard to type with it at times. But then again if you have smaller hands than  I do, I doubt this will be a problem.&lt;br /&gt;2. It was missing some important keys I frequently use like home, end, insert, backspace, page up/down and printscreen to name a few! I was told that home and end keys were (command + &lt;-) and (command + -&gt;) on the Mac, which is great if I could only find some software to do the mapping for me.&lt;br /&gt;3. Some of the keys like the function key (fn) didn't work out of the box and needed special software to work. The remaining keys can be mapped with a tool like &lt;a href="http://www.randyrants.com/software.html"&gt;SharpKeys&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here are the steps I followed to get the keyboard paired on Windows Vista:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;This guide is for dongles using the Widcomm bluetooth stack only. You need another working keyboard (preferably wired) for use to enter the pin code.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. Remove the following updates if installed:&lt;br /&gt;&lt;br /&gt;Update &lt;a href="http://support.microsoft.com/kb/941600"&gt;941600&lt;/a&gt; (Cumulative update rollup for USB core components in Windows Vista)&lt;br /&gt;Update &lt;a href="http://support.microsoft.com/kb/941649"&gt;941649&lt;/a&gt; (An update that improves the compatibility, reliability, and stability of Windows Vista)&lt;br /&gt;&lt;br /&gt;2. Install the Widcomm drivers that came with your bluetooth dongle.&lt;br /&gt;3. Launch regedit.&lt;br /&gt;4. Locate the &lt;em style="font-style: italic;"&gt;HKEY_CURRENT_USER\Software\Widcomm\BtConfig\General&lt;/em&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt; key.&lt;br /&gt;5. Set the key &lt;span style="font-weight: bold;"&gt;PinCodeWord&lt;/span&gt; to a  decimal value of 1111&lt;br /&gt;6. Set the key &lt;span style="font-weight: bold;"&gt;UseFixedPin&lt;/span&gt; to a  decimal value of 1&lt;br /&gt;7. Set the key &lt;span style="font-weight: bold;"&gt;NoSleepingWhileConnected&lt;/span&gt; to a decimal value of 1 (Disallows the keyboard going to sleep while connected to via bluetooth)&lt;br /&gt;8. Set the key &lt;span style="font-weight: bold;"&gt;DeviceInactivityDuration &lt;/span&gt;to a decimal value that represents the time in seconds before the keyboard disconnects from the bluetooth dongle. Eg. A value of 10800 is 3 hours. (60x60x3)&lt;br /&gt;9. Set the key &lt;span style="font-weight: bold;"&gt;MinPINLength&lt;/span&gt; to a decimal value of 3. This is the minimum pin code length).&lt;br /&gt;10. &lt;span style="font-weight: bold;"&gt;Restart the computer and log in with your other keyboard &lt;/span&gt;(not the Apple keyboard).&lt;br /&gt;11. Attempt pairing the keyboard with the dongle. Once the keyboard is detected, select it and click &lt;span style="font-weight: bold;"&gt;next&lt;/span&gt; to proceed. On the next screen you will need to enter a pairing key, which you won't be able to enter! :) The key you entered into the registry at step 5 is what you need to enter here. Using your &lt;span style="font-weight: bold;"&gt;other keyboard&lt;/span&gt; type in the pin code. You will &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; see the key strokes but they will be entered into the dialog.&lt;br /&gt;12.  Press the Return key on the &lt;span style="font-weight: bold;"&gt;Apple keyboard&lt;/span&gt;.&lt;br /&gt;13. The  bluetooth authentication dialog should accept this value. If it doesn't your  probably entered the wrong passkey. You may have to repeat the pairing process a few times before it succeeds.&lt;br /&gt;&lt;br /&gt;If and when the keyboard disconnects, I use the bluetooth driver in Vista to disable and enable bluetooth (using the mouse since my keyboard is not working). This then redetects the keyboard and reconnects to it in about 10 seconds. Failing this I eject and reinsert the dongle after about a 10 second wait.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_eusJ0yRMX3I/R1ZwOIWOlEI/AAAAAAAAAGQ/WOVpBZE1H3M/s1600-h/IMG_0353.JPG"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_eusJ0yRMX3I/R1ZwOIWOlEI/AAAAAAAAAGQ/WOVpBZE1H3M/s320/IMG_0353.JPG" alt="" id="BLOGGER_PHOTO_ID_5140419412751193154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_eusJ0yRMX3I/R1ZvwIWOlCI/AAAAAAAAAGA/TLgG7BxZP7Y/s1600-h/IMG_0355.JPG"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_eusJ0yRMX3I/R1ZvwIWOlCI/AAAAAAAAAGA/TLgG7BxZP7Y/s320/IMG_0355.JPG" alt="" id="BLOGGER_PHOTO_ID_5140418897355117602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eusJ0yRMX3I/R1Zv-oWOlDI/AAAAAAAAAGI/cLxNC23wm50/s1600-h/IMG_0358.JPG"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_eusJ0yRMX3I/R1Zv-oWOlDI/AAAAAAAAAGI/cLxNC23wm50/s320/IMG_0358.JPG" alt="" id="BLOGGER_PHOTO_ID_5140419146463220786" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-7081209591630199797?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/7081209591630199797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=7081209591630199797' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/7081209591630199797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/7081209591630199797'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/12/wireless-apple-keyboard-on-vista.html' title='Wireless Apple Keyboard on Vista'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_eusJ0yRMX3I/R1ZwOIWOlEI/AAAAAAAAAGQ/WOVpBZE1H3M/s72-c/IMG_0353.JPG' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-5874264248058519049</id><published>2007-12-02T21:08:00.000+10:00</published><updated>2007-12-02T21:37:41.380+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>JPA - Not Another API (NAA)?</title><content type='html'>I've recently started looking at JPA (Java Persistence API). I must admit I was a little annoyed. I already knew how to use hibernate and it suites most  purposes. So why learn yet another annoying Sun API?&lt;br /&gt;&lt;br /&gt;You can use JPA in EJB3 which really standardizes EJB persistence - this is a good thing. Fantastic. What if you avoid EJB technologies like the plague? Why do you need yet another API to handle standalone data persistence?&lt;br /&gt;&lt;br /&gt;While looking for resources to get my first JPA project off the ground, I was pleasantly surprised by 2 excellent how-tos. One with Hibernate and one with TopLink. It seems very easy and it has much of the goodness of Hibernate - so it's not all bad! :)&lt;br /&gt;&lt;br /&gt;Unfortunately it doesn't seem to have anything similar to the Criterion API in Hibernate. (I could be wrong - if so please let me know!) The Hibernate implementation also offers a few niceties which in my opinion subvert the JPA by making things "automatic". Obviously if you switch JPA providers this magic won't work - so it's not really standard. Hmmm. A non-standard use of standardized API. Wot tha?&lt;br /&gt;&lt;br /&gt;A main driving factor for me learning JPA was the that Spring 2.5 only supports JPA and not the "old-school style" Hiberate templates. Hiss! Boo! Since many of the big players (Sun, Spring etc) are moving to JPA, it seems like a good time to learn to reinvent the persistent wheel!&lt;br /&gt;&lt;br /&gt;As with any new API, the hardest part is to get your first "hello world" application running. I found 2 simple how-tos on JPA to help you get started:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://javahowto.blogspot.com/2006/07/helloworld-with-jpa-toplink-and-mysql.html"&gt;HelloWorld JPA example in TopLink&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.hibernate.org/397.html"&gt;HelloWorld JPA example in Hibernate 3&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-5874264248058519049?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/5874264248058519049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=5874264248058519049' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5874264248058519049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/5874264248058519049'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/12/jpa-not-another-api-naa.html' title='JPA - Not Another API (NAA)?'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-8716172019919590852</id><published>2007-11-16T18:38:00.000+10:00</published><updated>2008-02-03T13:06:47.802+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OS'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><title type='text'>Running Leopard on a PC</title><content type='html'>Stop the press! There is an updated non-hackety guide &lt;a href="http://www.lifehacker.com.au/tips/2008/01/25/install_os_x_on_your_hackintosh_pc_no_hacking_required-2.html#comments"&gt;here&lt;/a&gt;. The hackety guide is outlined below:&lt;br /&gt;&lt;br /&gt;There is an excellent &lt;a href="http://www.lifehacker.com/"&gt;LifeHacker &lt;/a&gt;article on how to run Leopard (Max OS 10.5) on a regular PC! :)  So hopefully we can get all the goodness of a Mac (Tom Adam's anyone?) without all the proprietary hardware crapiola of an Apple! Yay! Give the guide a go &lt;a href="http://www.lifehacker.com.au/tips/2007/11/14/build_a_hackintosh_mac_for_und.html#comments"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-8716172019919590852?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/8716172019919590852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=8716172019919590852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8716172019919590852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8716172019919590852'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/11/running-leopard-on-pc.html' title='Running Leopard on a PC'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-8024943491450627796</id><published>2007-10-30T07:47:00.000+10:00</published><updated>2007-11-02T00:32:36.986+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Pair Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Pair Programming : Compatibility of a Pair Really Matters</title><content type='html'>I've been a practitioner and supporter of Agile methodologies for a few years now and most of the time I think it's great. TDD/BDD (Test-Driven Development/Behaviour-Driven Development) and Pair Programming are import tools in one's Agile tool set.&lt;br /&gt;&lt;br /&gt;Recently I've been pairing in Java with some very intelligent guys from a Ruby and C++ background. This obviously made for some very interesting pairing. Being primarily from a Java background myself (having left C++ in the dust over 5 years ago) I've become accustomed to certain niceties in Java. A single class with a single purpose, meaningful method and variables names, refactoring, IDE support and most importantly testing/specing code before writing it are some of the more important ones.&lt;br /&gt;&lt;br /&gt;These concepts blend very well with someone with a Ruby background mainly because they use some or all of these concepts and have other great concepts that Java could adopt. Unsurprisingly, pairing with the Ruby guys was very productive and the code fairly well designed and implemented.&lt;br /&gt;&lt;br /&gt;In the last week I've been pairing with someone from a pure C++ background and the results have been mixed. Pure C++ programmers are eager to come up with the "best" the solution to a problem immediately. No TDD/BDD, no testing/specing - just full steam ahead! I feel this is anti-agile, as you have preconceived notions about how the code should be written before even writing it. This leads to a somewhat haphazard "design" and hence complicates everything from this point onward. When TDDing/BDDing, we drive out a good design through tests/specs and by bypassing these steps we loose out on this benefit.&lt;br /&gt;&lt;br /&gt;The other important difference I saw between pure C++ and C++/Ruby programmers was that it was more challenging to get the pure C++ programmer to write even the simplest test/spec. "Why do we need it?", "I know what the solutions is", "This is a waste of time" were some of the usual comments that one could hear floating around. These are all valid questions/statements. But it hinders more than helps when you have to constantly justify to someone why testing/specing is good. This definitely slows down any forward momentum. I feel that anyone doing pair programming should at least have a cursory understanding of the benefits and drawbacks of TDD/BDD.&lt;br /&gt;&lt;br /&gt;Another facet of pure C++, namely writing the most efficient solution upfront is another hurdle to jump over when pairing. Premature optimization usually leads to very hard-to-maintain code. I find it very hard to get someone out of this mindset when programming in a language like Java. Long variables and method names look ridiculous to pure C++ programmers because this is not what they are used to. Soon it becomes a struggle. You want to name everything in the most readable way possible while the pure C++ programmer wants to name everything as terse as possible. You want to have more classes with a single purpose, they want to have less classes which were are compact as possible. You want to reduce complexity, C++ programmers are "used to" complexity and don't have problem with it. What to do, what to do?!&lt;br /&gt;&lt;br /&gt;As with anything in life, there has to be some give and take. All taking and no giving does not make anyone happy...well....almost no one! :) So you have to make sacrifices (at the Java alter of goodness) and win wars and fore go  battles. Corners get cut and your confidence in the code and that warm fuzzy feeling begins to dwindle.&lt;br /&gt;&lt;br /&gt;So at the end of the day, the question is, how good is your solution when you have such forces competing in opposite directions? I would say less than optimal. Did we get a working solution ? Yes, definitely. Is it something I thought was great and easy to understand and maintain? Probably not. Was it something the pure C++ programmer thought was efficient and the most elegant solution? Probably not. So was this a win-win situation for the customer and programmers involved? Probably not.&lt;br /&gt;&lt;br /&gt;So the point to my long rambling is this: The effectiveness of pair programming depends on who you are pairing with, their technical background, personality, work ethic and how much they like working in a "team".  To get the best out of a pair I definitely feel that these factors should be considered before pairing together 2 individuals to solve any business problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-8024943491450627796?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/8024943491450627796/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=8024943491450627796' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8024943491450627796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/8024943491450627796'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/10/pair-programming-compatibily-of-pair.html' title='Pair Programming : Compatibility of a Pair Really Matters'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-902936590392285833</id><published>2007-10-20T01:14:00.001+10:00</published><updated>2007-10-20T10:38:41.201+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Install'/><category scheme='http://www.blogger.com/atom/ns#' term='JRE'/><category scheme='http://www.blogger.com/atom/ns#' term='JDK'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu: Installing the latest JDK or JRE</title><content type='html'>In this tutorial I will show you how to install the latest JDK or JRE on your Ubuntu box. I am using JDK1.6 update 3 on Ubuntu 7.0.4 (64-bit) on an AMD64 CPU for this tutorial.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;Commands&lt;/span&gt;&lt;span style="color: rgb(0, 204, 204);"&gt; &lt;/span&gt;are in bold and blue,  &lt;span style="font-weight: bold;"&gt;paths&lt;/span&gt; are in bold while user &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;input&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt; &lt;/span&gt;and &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;program output&lt;/span&gt; are in green italics.&lt;br /&gt;&lt;br /&gt;1. Check your current version of java with:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;java -version&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This should give you something similar to:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;java version "1.4.2"&lt;/span&gt; &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;gij (GNU libgcj) version 4.1.2 (Ubuntu 4.1.2-0ubuntu5)&lt;/span&gt;  &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;Copyright (C) 2006 Free Software Foundation, Inc.&lt;/span&gt; &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;This is free software; see the source for copying conditions.  There is NO&lt;/span&gt; &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;/span&gt;  &lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;If you have the default Ubuntu JRE installed.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;2. Download the latest bin file for the java version you require (for linux) from &lt;a href="http://java.sun.com/"&gt;Sun&lt;/a&gt;. (Ensure you get the correct bit version for your operating system (32 or 64)). I used Jdk1.6 update 3 for 64-bit linux running on an amd64 cpu. (&lt;span style="font-weight: bold;"&gt;jdk-6u3-linux-amd64.bin&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;3. I usually install all shared software under &lt;span style="font-weight: bold;"&gt;/opt&lt;/span&gt;. Copy the downloaded bin file into &lt;span style="font-weight: bold;"&gt;/opt&lt;/span&gt; with: &lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;cp Desktop/jdk-6u3-linux-amd64.bin /opt&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;assuming you downloaded the file to your desktop. If not use the correct path to your bin file in the above copy statement.&lt;br /&gt;&lt;br /&gt;4. Make the bin file executable with the following:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;sudo chmod 777 jdk-6u3-linux-amd64.bin&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Enter your user's password when prompted. Check that the above command succeeded with:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="color: rgb(0, 204, 204);"&gt;ls -l  jdk-6u3-linux-amd64.bin&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The output should be similar to the following:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;-rwxrwxrw&lt;span style="font-weight: bold; color: rgb(255, 255, 255);"&gt;x&lt;/span&gt; 1 root root 62140783 2007-10-20 01:03 jdk-6u3-linux-amd64.bin&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;We are interested in the last &lt;span style="font-weight: bold;"&gt;x&lt;/span&gt; in the list of privilege which specifies that all users can e&lt;span style="font-weight: bold;"&gt;x&lt;/span&gt;ecute the bin file.&lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;5. Run the bin file as &lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;sudo&lt;/span&gt;&lt;span style="color: rgb(0, 204, 204);"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;sudo ./jdk-6u3-linux-amd64.bin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This should bring up Sun's documentation with a &lt;span style="font-weight: bold;"&gt;--More--&lt;/span&gt; displayed at the bottom.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eusJ0yRMX3I/Rxjlxc7RhEI/AAAAAAAAACE/gwVZlax3UCc/s1600-h/java_install1.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_eusJ0yRMX3I/Rxjlxc7RhEI/AAAAAAAAACE/gwVZlax3UCc/s320/java_install1.png" alt="" id="BLOGGER_PHOTO_ID_5123097213875094594" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Use the &lt;span style="font-weight: bold;"&gt;enter&lt;/span&gt; key to navigate to the bottom of the document. When asked whether to accept the conditions type:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;yes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/Rxjl2M7RhFI/AAAAAAAAACM/PQF3RHWpc6E/s1600-h/java_install2.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/Rxjl2M7RhFI/AAAAAAAAACM/PQF3RHWpc6E/s320/java_install2.png" alt="" id="BLOGGER_PHOTO_ID_5123097295479473234" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This will extract the bin file into the &lt;span style="font-style: italic; font-weight: bold;"&gt;/opt&lt;/span&gt; directory, creating a &lt;span style="font-style: italic; font-weight: bold;"&gt;jdk1.6.0_03&lt;/span&gt; directory. If you did get permission errors while running the bin file ensure that you ran the bin file with &lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;sudo&lt;/span&gt; and that you are in the &lt;span style="font-style: italic; font-weight: bold;"&gt;admin&lt;/span&gt; group of the machine on which you are installing  java.&lt;br /&gt;&lt;br /&gt;6. Create a symbolic link to the installed java version with the following from the &lt;span style="font-style: italic; font-weight: bold;"&gt;/opt&lt;/span&gt; directory:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;sudo ln -s jdk1.6.0_03 jdk16&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/span&gt;This will create a symbolic link to the &lt;span style="font-weight: bold;"&gt;jdk1.6.0_03 &lt;/span&gt;directory through the &lt;span style="font-weight: bold;"&gt;jdk16&lt;/span&gt; directory. A sybolic link is similar to a shortcut in Windows. It provides an alias to directory. The benefit of this is that if you install the next latest version of java you can simply update the symbolic link to that version and all your programs that refer to &lt;span style="font-weight: bold;"&gt;jdk16&lt;/span&gt; will work with the latest version of java.&lt;br /&gt;&lt;br /&gt;Verify that the symbolic link has been created with following from &lt;span style="font-weight: bold;"&gt;/opt&lt;/span&gt;:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;ls -l&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;The &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(255, 255, 255);"&gt;jdk16 &lt;/span&gt;&lt;span style="color: rgb(255, 255, 255); font-weight: bold;"&gt;-&gt; jdk1.6.0_03&lt;/span&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; signifies the symbolic link.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;lrwxrwxrwx  1 root root           11 2007-10-20 01:05 jdk16 -&gt; jdk1.6.0_03&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;7. Now we need to update &lt;span style="font-weight: bold;"&gt;PATH&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;JAVA_HOME &lt;/span&gt;variables for your user. Edit the  &lt;span style="font-weight: bold;"&gt;.profile &lt;/span&gt;file found in your home directory (&lt;span style="font-weight: bold;"&gt;home/your_user&lt;/span&gt;) with a text editor such as &lt;span style="font-weight: bold;"&gt;vi&lt;/span&gt; or &lt;span style="font-weight: bold;"&gt;gedit&lt;/span&gt;:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 204, 204);"&gt;vi ~/.profile&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(0, 204, 204);"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt; &lt;span style="color: rgb(255, 255, 255);"&gt;or&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 204, 204);"&gt;gedit ~/.profile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span style="font-style: italic;"&gt;&lt;span style="color: rgb(0, 204, 204);"&gt;~&lt;/span&gt; denotes your home directory&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;Add the following lines to the bottom of this file:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;export PATH=/opt/jdk16/bin:$PATH&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;export JAVA_HOME=/opt/jdk16&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;save and close the file. The &lt;span style="font-weight: bold;"&gt;.profile &lt;/span&gt;file is run when you log into the system. So the next time you login the &lt;span style="font-weight: bold;"&gt;PATH&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;JAVA_HOME&lt;/span&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;variables will be set appropriately.&lt;br /&gt;&lt;br /&gt;8. Logout of your user and log back in. You can do this in the GUI or simply type:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;logout&lt;/span&gt;&lt;br /&gt;if you are connecting through a terminal.&lt;br /&gt;&lt;br /&gt;9. Log back in with your user.&lt;br /&gt;&lt;br /&gt;Verify that the PATH is set to the jdk bin directory by typing the following:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;env | grep PATH&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(0, 204, 204);"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This should give you something like:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;PATH=/opt/jdk16/bin:/usr/local/sbin:/usr/local/bin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Make sure the &lt;span style="font-weight: bold;"&gt;/opt/jdk16/bin&lt;/span&gt; is the first path entry.&lt;br /&gt;&lt;br /&gt;Verify the &lt;span style="font-weight: bold;"&gt;JAVA_HOME&lt;/span&gt; variable with the following:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;env | grep JAVA_HOME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;this should give you the following:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;JAVA_HOME=/opt/jdk16&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now verify the java version with:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 204, 204);"&gt;java -version&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You should get something similar to the following:&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;java version "1.6.0_03"&lt;/span&gt; &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;Java(TM) SE Runtime Environment (build 1.6.0_03-b05)&lt;/span&gt; &lt;span style="font-style: italic; color: rgb(0, 153, 0);"&gt;Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_03-b05, mixed mode)&lt;/span&gt;  &lt;span style="color: rgb(0, 153, 0);"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;10. Congratulations, you have now installed the latest version of java! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-902936590392285833?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/902936590392285833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=902936590392285833' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/902936590392285833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/902936590392285833'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/10/ubuntu-installing-latest-jdk-or-jre.html' title='Ubuntu: Installing the latest JDK or JRE'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eusJ0yRMX3I/Rxjlxc7RhEI/AAAAAAAAACE/gwVZlax3UCc/s72-c/java_install1.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-374525307328334957</id><published>2007-10-15T19:20:00.000+10:00</published><updated>2007-10-16T21:38:53.305+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wacky'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='Vista'/><title type='text'>How Wacky can Windows Get?</title><content type='html'>Yeah, don't answer that. I was recently copying some files from my digital camera and got this surprisingly astute message:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eusJ0yRMX3I/RxMxds7Rg_I/AAAAAAAAABc/pcZhbM-gzJ0/s1600-h/wacky_windows_vista_copy.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_eusJ0yRMX3I/RxMxds7Rg_I/AAAAAAAAABc/pcZhbM-gzJ0/s320/wacky_windows_vista_copy.png" alt="" id="BLOGGER_PHOTO_ID_5121491587596125170" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, I won't be alive for another 21860 days (59 years) until 321 MB is copied from my memory card, well maybe... What to do? What to do? :P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-374525307328334957?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/374525307328334957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=374525307328334957' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/374525307328334957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/374525307328334957'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/10/how-wacky-can-windows-get.html' title='How Wacky can Windows Get?'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eusJ0yRMX3I/RxMxds7Rg_I/AAAAAAAAABc/pcZhbM-gzJ0/s72-c/wacky_windows_vista_copy.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-2229838077307107114</id><published>2007-10-07T22:21:00.001+10:00</published><updated>2007-10-16T21:39:56.508+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uname'/><category scheme='http://www.blogger.com/atom/ns#' term='Edgy'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Version'/><category scheme='http://www.blogger.com/atom/ns#' term='lsb_release'/><category scheme='http://www.blogger.com/atom/ns#' term='Fiesty'/><title type='text'>Ubuntu: How do I find out my Ubuntu version?</title><content type='html'>Type&lt;span style="font-style: italic;"&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;lsb_release -a&lt;/span&gt;&lt;/span&gt; at a command prompt. This will give you information about the version of Ubuntu that is running plus it's code name etc. Type &lt;span style="color: rgb(0, 153, 0);"&gt;uname -a&lt;/span&gt; get information about whether you are running 32-bit or 64-bit Ubuntu.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_eusJ0yRMX3I/RxShJ87RhDI/AAAAAAAAAB4/oSRhNCQC3hg/s1600-h/ub_version704_with_64bit_release.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_eusJ0yRMX3I/RxShJ87RhDI/AAAAAAAAAB4/oSRhNCQC3hg/s320/ub_version704_with_64bit_release.png" alt="" id="BLOGGER_PHOTO_ID_5121895868572730418" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This shows information about the 64-bit (or x86_64) Ubuntu 7.0.4 (Fiesty).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eusJ0yRMX3I/RxSg-M7RhCI/AAAAAAAAABw/Ctey6PInLY4/s1600-h/ub_version704_with_32bit_release.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_eusJ0yRMX3I/RxSg-M7RhCI/AAAAAAAAABw/Ctey6PInLY4/s320/ub_version704_with_32bit_release.png" alt="" id="BLOGGER_PHOTO_ID_5121895666709267490" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This shows information about the 32-bit (or 686) Ubuntu 6.10 (Edgy).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-2229838077307107114?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/2229838077307107114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=2229838077307107114' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2229838077307107114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/2229838077307107114'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/10/ubuntu-how-do-i-find-out-my-ubuntu.html' title='Ubuntu: How do I find out my Ubuntu version?'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_eusJ0yRMX3I/RxShJ87RhDI/AAAAAAAAAB4/oSRhNCQC3hg/s72-c/ub_version704_with_64bit_release.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4288112407600774150.post-6286224757486221852</id><published>2007-10-06T11:55:00.000+10:00</published><updated>2007-10-17T07:13:08.051+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Welcome'/><category scheme='http://www.blogger.com/atom/ns#' term='Vision'/><title type='text'>Welcome</title><content type='html'>&lt;span style="font-style: italic;"&gt;Welcome to the Babylon Candle! The "Babylon Candle" is a concept I "borrowed" from the movie Stardust. A Babylon Candle allows the owner to transport him/herself anywhere in the world just by focusing on that location. So it doesn't make much sense for a blog name, but it does sound cool! :)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This blog will focus mainly on development related articles using Java, Windows (Shock! Horror!) and Ubuntu. Being a mostly windows programmer I moved to Ubuntu around 6 months ago. The learning curve has been pretty steep, but I'm moving all my machines to Ubuntu one by one. I hope to blog some general how-to's with Ubuntu specially for that windows user who has made the recent move.&lt;br /&gt;&lt;br /&gt;- Sanj&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4288112407600774150-6286224757486221852?l=babyloncandle.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://babyloncandle.blogspot.com/feeds/6286224757486221852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4288112407600774150&amp;postID=6286224757486221852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6286224757486221852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4288112407600774150/posts/default/6286224757486221852'/><link rel='alternate' type='text/html' href='http://babyloncandle.blogspot.com/2007/10/welcome.html' title='Welcome'/><author><name>sanj</name><uri>http://www.blogger.com/profile/02260021367486704509</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_eusJ0yRMX3I/R6UbH2EnSnI/AAAAAAAAAKA/dEnn2l4aD6s/S220/1851.jpg'/></author><thr:total>0</thr:total></entry></feed>
