My Google Nexus One

I’ve been using Google Nexus One since its release. Google got the phone to me within 24 hours of the announcement. (Thank you Google!) This isn’t the first Android phone I used. I also have the HTC Magic aka T-Mobile myTouch 3G aka Google Ion. To be blunt, up till now Android has been a disappointment to me. They are sluggish, ugly, and the software were very rough. I was cautiously optimistic about Nexus One. After all, this time around Google is selling it directly unlocked. The specs look great on paper, but will it actually translate to good user experience this time? I resisted writing this review right away, because I really want to give it a fair chance. So other than posting a bunch of pictures on Flickr, I waited till now to write this after using it since Jan 6th.

So what’s the verdict? For those of you who just want to know right now. The short version is “Google Nexus One wins on hardware, Apple iPhone 3GS wins on software.”

First let’s talk about hardware. When you hold Nexus One. The first thing you notice is the lovely AMOLED screen. The phone is thinner than iPhone. The build quality is high. The images are crisp thanks to the high resolution. The iPhone screen is 3.5 inches with resolution of 320×480. The Nexus One is 3.7 inches with resolution of 480×800. Though at the default setting, the Nexus One screen is much darker than iPhone. The 5 megapixel camera takes excellent photos. The color palette produce high contrast and saturated photo, much like a Canon DSLR, which I love. The camera is also able to capture video at 720×480 at 20fps+. In fact, the camera has hardware based autofocusing system. It has a LED flash, which is useful in a pinch when you are taking night shoots.

It has a removable battery. The 3G support for T-Mobile’s new full speed HSPA 7.2Mbps is very fast. It also has a active noise canceling mic. On Nexus One, there is a 2nd mic which is used to measure ambient noise and filter it out during your phone call. It works very well in a noisy environment. The call quality is good. Though the speaker at high volume is a bit metallic.

The 1ghz SnapDragon processor is very very fast. The first place you’ll notice this is when you rotate the phone. On other Android phones I’ve used, rotating the phone causes a lag before the screen will redraw in different orientation. On Google Nexus One, it happens right away. No more lag. The built-in GPU also makes this the first Andorid phone I would actually consider develop game for. It supports OpenGL ES 2.0, and has excellent performance. It’s really the first phone I’ve played with that surpass iPhone 3GS’s OpenGL ES 2.0 performance, and that’s no small feat. It has excellent hardware support for H264 decoding too. Videos playback is very smooth and easy on the battery life. The memory has been increased to 512MB, it’s still quite small due to the fact that you can ONLY install Android apps to system memory only. So the MicroSD Slot which allows you to use a 32GB card is basically only for data. It of course has Active GPS, digital compass and accelerometer.

The only con I have on the hardware side is, the touch screen isn’t very accurate. I’m very used to the very accurate iPhone. On Nexus One, touching a small navigation button leads to mistouch very often. This is compounded by the fact that Nexus doesn’t support pinch and zoom. It makes using the web browser a frustrating experience at times. On the bottom row of the screen are 4 dedicated touch buttons for “Previous Screen”, “Menu”, “Home”, and “Search”. I can’t begin to tell you how many times that in the middle of using the virtual keyboard to input my new tweet only to accidentally trigger “Home” button, thus losing EVERYTHING I just typed. It happens a lot because the “Home” key is just below “Space” on the virtual keyboard and with how inaccurate the touch screen is, I mistouch it very often. The other issue deal with editing existing text I typed. On Android, to place the cursor between letters you tap between the two letters. It doesn’t let you zoom and hover like iPhone. So with the inaccuracies of the touch screen, I end up keep taping hoping to land the cursor in the right place.

The other small complaint is, no accessories at all. It launched with nothing. The phone does come with charger, USB cable, headphone and a very cute carrying case. But the dock that was talked about quite a bit only came out a couple of days ago. Mine should be here in the next day or so.

Onward to software. Android has come a long way. I’ve used Android since the pre 1.0 SDK. And I’ve played with each major release since. So I saw how Android is growing up every step of the way. It’s getting much better. But still rough in places. First let’s talk about the good stuff. I love how Google implemented voice input feature. It’s part of the virtual keyboard as a mic icon. You tap it and process with voice input. It translates it into text as if you just typed it. This means it will work on anything that is a text input. Very well thought out. The new Google Maps with the turn by turn voice navigation is the first alternative I would consider against my favorite: TeleNav on Blackberry. Though Google Maps’ speech synthesis for voice navigation is still to robot sounding, it’s very useable. The home screen is now very iPhone-ish. You have multiple pages of apps you can scroll back and forth. But in addition to app shortcuts, you can also place widgets that are irregular size. I especially like the new News and Weather widget, given that I’m a news junkie. The new weather app is also very cool, giving you very detail break down on a interactive timeline. The new full 3d wallpaper is lovely both as eyecandy as well as a demonstration of the GPU’s power. Even if it does suck your battery. Another widget I really like let you change bluetooth/wifi/gps/sync/brightness with a single toggle. No need to go to setting screen. I’m a Google Voice heavy user. Nexus One’s total integration with Google Voice is second to none. The gmail app also address one of my long standing complaint. Up till now you can only access the gmail account that’s associated with your Android phone, to read other gmail accounts you have to set it up as a pop3/imap in the other mail app. That’s just totally silly. In Google Nexus One, finally you can access multiple gmail accounts. The web browser receives some UI tweaks also. The url window is now always visible. The surfing experience is also far more responsive. Not having multitouch is still annoying, but patents, what can you do? The over all UI also has many more transition effects to give it a more smooth experience. This is especially obvious when you bring up the “List of All Apps” screen.

On the negative side. In Android Webkit browser, like iPhone Safari, you can also double tap to “fill” the screen with the section or the graphics you are interested in reading. But Android’s Webkit browser is far worse at guessing. On iPhone, if I double tap on a graphic, it will fill 100% of the screen correctly everytime. On Nexus One, most of time I only end up with 80% of the screen filled. It also guess wrong quite often when I’m reading multi column website and double tap to read a particular section.

The music player is terrible. It’s very barebone. It doesn’t support podcast at all. I use Google Listen, which is an app available from Marketplace. It’s serviceable. But it updates feed very slowly, is missing many popular podcasts, and most importantly it stores the downloaded audio in a goofy file name so if I dock the Nexus One into a mp3 playing device. It won’t play. The clock app only has alarm, but no timer or stop watch function. There is no dedicated video player, only a YouTube player. The calculator supports sin/cos by using a “advance” panel is pretty useless.

I have mix feelings about the Market Place. I’m not the type of person that goes “App Store has 100k apps, Andorid Market Place has 20k, thus, Android sucks!” If that’s the logic you want to use, we should all be using Windows. The reason I have mix feelings are two folds. 1: For the apps I’m looking for, there are less apps which are “good”. 2: The same apps on iPhone vs Nexus One. The Nexus One version are worse, at least for the ones I use.

Let me give an example for the first reason. Twittering Apps. On iPhone I switch back and forth between Tweetie and EchoFon often because they are both very good and they constantly are trying to outdo each other with new features and new UIs. On Android, I use both Twidroid and Seesmic. Frankly, both of them are at best, serviceable. Twidroid’s UI is a mess. It feels like “never saw a dropdown we don’t like”. Seesmic is more polished, but it crashes every so often. And the notification feature is not reliable. Another example would be gaming apps. On iPhone, I’m completely addicted to Civ Revolution. It doesn’t exist on Android, the end.

A couple of example of the 2nd reason are WeatherBugs, and AP Mobile. WeatherBugs is very fast and smooth on iPhone. It displays data right away, and screen updates are fast. Interacting with it is instantaneous. On Nexus One, WeatherBugs is laggy, shows me blank screen with no data often, and seems to take forever to acquire GPS lock to give me current location weather. AP Mobile on Android looks far worse than iPhone. On iPhone it does background push notification to tell you about breaking news. On Android, even though I have the notification turned on, it never works.

Now I can hear it. “But it’s not fair. Just because the apps you use are written badly, it’s not Nexus One’s fault”. Sadly, market place don’t care. All they care about is, do apps I use exist on Nexus One? And if so, do they run well?

From a game developer point of view, there are a couple of road blocks in bringing a high end commercial game to Nexus One. The first one I already touched on, it’s a space issue. I have to fit the entire game into a very small package that can only be installed onto the main memory. The second one is lack of any sound streaming and mixing API. Sound is a major factor in gaming. Android’s sound API is frankly terrible, and it’s not something I can work around by using native SDK.

But at the end of the day, I like Google Nexus One. I think it’s the first credible competitor to iPhone. And I love competitions.

ftp using Groovy and Grape UPDATE

People always look at me in disbelieve when I say I use groovy to setup a bunch of cron scripts to ftp and process millions of records daily. Then they are even more surprised when I said I can set it up in a matter of minutes. Here is how I do it.

import org.apache.commons.net.ftp.FTPClient

start()

@Grab(group='commons-net', module='commons-net', version='2.0')
def start()
{
  def ftpClient = new FTPClient()
  ftpClient.connect("ftp server address here")
  ftpClient.enterLocalPassiveMode()
  println(ftpClient.replyString)
  ftpClient.login("username","password")
  println(ftpClient.replyString)
  ftpClient.changeWorkingDirectory("directory the file is in")
  println(ftpClient.replyString)
  ftpClient.fileType=(FTPClient.BINARY_FILE_TYPE)
  println(ftpClient.replyString)

  def incomingFile = new File("localfilename")
  incomingFile.withOutputStream { ostream ->
    ftpClient.retrieveFile("remotefilename", ostream )
  }
  println(ftpClient.replyString);
  ftpClient.disconnect()
}

I use Grab so I don’t have to worry about dependencies. At each step after issuing a command, I then do a “println(ftpClient.replyString)” to see the output for diagnostic purposes. I’m also using “enterLocalPassiveMode()” to use ftp passive mode. I wrapped it in start() to work around the @Grab in Groovy 1.6 must be attached to something. You won’t need to do that if you are using Groovy 1.7. I also set the transfer mode to explicitly binary because most of the times I’m dealing with zip files.

Then I open a local file, use Groovy’s with block to manage the download. Then disconnect.

Groovy makes this so simple it takes me longer to explain it than writing the code, which is why I post it here instead of keep emailing this to everyone who asked. :)

UPDATE: Guillaume Laforge, the master of Groovy himself suggested I use with.{} block to avoid repeating the prefix over and over again. He posted it here.

It’s a great suggestion. I must admit to this date, I often forget about with.{}. I’ve reproduced his code below.

@Grab(group='commons-net', module='commons-net', version='2.0')
import org.apache.commons.net.ftp.FTPClient

new FTPClient().with {
    connect "ftp server address here"
    enterLocalPassiveMode()
    login "username", "password"
    changeWorkingDirectory "directory the file is in"
    ftpClient.fileType = FTPClient.BINARY_FILE_TYPE
    def incomingFile = new File("localfilename")
    incomingFile.withOutputStream { ostream -> retrieveFile "remotefilename", ostream }
    disconnect()
}

Ninety-Nine Problems In Clojure Part 1 1-15

The original Ninety-Nine Prolog Problems was written by Werner Hett at the Berne University of Applied Sciences in Berne, Switzerland.  Phil Gold then adapted it to Ninety-Nine Scala Problems. I had fun reading them. It has inspired me to do a series of Ninety-Nine Problems in different languages. I’m starting with Clojure.

I’m taking a more practical approach. I use built-in library whenever possible. I use clojure-contrib as well. Because on a day to day basis, this is what we all do. They exist for a reason after all. If you feel that’s cheating. Feel free to write your own. :)

The difficulty ranking was for Prolog. The original text says

The problems have different levels of difficulty. Those marked with a single asterisk (*) are easy. If you have successfully solved the preceeding problems you should be able to solve them within a few (say 15) minutes. Problems marked with two asterisks (**) are of intermediate difficulty. If you are a skilled Proglog programmer it shouldn’t take you more than 30-90 minutes to solve them. Problems marked with three asterisks (***) are more difficult. You may need more time (i.e. a few hours or more) to find a good solution.

I think the difficulty scale for the most part is comparable in Clojure.

P01 (*) Find the last element of a list.
Example:

user=> (last [1 1 2 3 5 8])
8
P02 (*) Find the last but one element of a list.
Example:

user=> (penultimate [1 1 2 3 5 8])
5
P03 (*) Find the Kth element of a list.
By convention, the first element in the list is element 0.Example:

user=> (nth2 2 [1 1 2 3 5 8])
2
P04 (*) Find the number of elements of a list.
Example:

user=> (length [1 1 2 3 5 8])
6
P05 (*) Reverse a list.
Example:

user=> (reverse [1 1 2 3 5 8])
(8 5 3 2 1 1)
P06 (*) Find out whether a list is a palindrome.
Example:

user=> (palindrome? [1 2 3 2 1])
true
P07 (**) Flatten a nested list structure.
Example:

user=> (flatten [[1 1] 2 [3 [5 8]]])
(1 1 2 3 5 8 )
P08 (**) Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.Example:

user=> (compress "aaaabccaadeeee")
(\a \b \c \a \d \e)
P09 (**) Pack consecutive duplicates of list elements into sublists.
If a list contains repeated elements they should be placed in separate sublists.Example:

user=> (pack "aaaabccaadeeee")
((\a \a \a \a) (\b) (\c \c) (\a \a) (\d) (\e \e \e \e))
P10 (*) Run-length encoding of a list.
Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as tuples (N, E) where N is the number of duplicates of the element E.Example:

user=> (encode "aaaabccaadeeee")
((4 \a) (1 \b) (2 \c) (2 \a) (1 \d) (4 \e))
P11 (*) Modified run-length encoding.
Modify the result of problem P10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N, E) terms.Example:

user=> (encode-modified "aaaabccaadeeee")
((4 \a) (\b) (2 \c) (2 \a) (\d) (4 \e))
P12 (**) Decode a run-length encoded list.
Given a run-length code list generated as specified in problem P10, construct its uncompressed version.Example:

user=> (decode [[4 \a] [1 \b] [2 \c] [2 \a] [1 \d] [4 \e]])
(\a \a \a \a \b \c \c \a \a \d \e \e \e \e)
P13 (**) Run-length encoding of a list (direct solution).
Implement the so-called run-length encoding data compression method directly. I.e. don’t use other methods you’ve written (like P09’s pack); do all the work directly.Example:

user=> (encode-direct "aaaabccaadeeee")
((4 \a) (\b) (2 \c) (2 \a) (\d) (4 \e))
P14 (*) Duplicate the elements of a list.
Example:

user=> (duplicate "abccd")
(\a \a \b \b \c \c \c \c \d \d)
P15 (**) Duplicate the elements of a list a given number of times.
Example:

user=> (duplicate-n 3 "abccd")
(\a \a \a \b \b \b \c \c \c \c \c \c \d \d \d)

Bleeding Edge Clojure Development using clj-gradle

Clojure is evolving very rapidly. I find myself using clojure and clojure-contrib from github most of the time. It’s rather annoying to have to keep git pull and build them often. A few days ago, a CI server was setup for clojure.org to build both clojure and clojure-contrib and made them available in mvn style repo.

Excellent, this means I can just use Gradle to handle it for me. For any new bleeding edge clojure project, all you need is the clj-gradle-1.0.0.jar and build.gradle file. If you don’t have the clj-gradle-1.0.0.jar go here to see how to build it.

Here is the updated version of the build.gradle file.

buildscript {
  repositories {
    flatDir(dirs:'lib')
  }
  dependencies {
    classpath name: 'clj-gradle-1.0.0'
  }
}

usePlugin(de.kotka.gradle.ClojurePlugin)
  repositories {
    flatDir(dirs:'lib')
  }

configurations {
  compileOnly {
    setVisible(false)
    setTransitive(false)
  }
  compile.extendsFrom(compileOnly)
}

repositories {
  mavenCentral()
  mavenRepo urls: "http://build.clojure.org/snapshots"
}

dependencies {
  compileOnly name: 'clj-gradle-1.0.0'
  compile 'org.clojure:clojure-lang:1.1.0-alpha-SNAPSHOT'
  compile 'org.clojure:clojure-contrib:1.0-SNAPSHOT'
}

task initProject(description: 'Initialize project directory structure.') << {
  ['clojure'].each {
  convention.sourceSets.all*."${it}".srcDirs*.each { it.mkdirs() }
  }
}

task copyToLib(dependsOn: configurations.default.buildArtifacts, type: Copy) {
  into('build/lib')
  from configurations.default
  from configurations.default.allArtifacts*.file
}

I’m using the shorthand syntax for dependencies. I also added mvn repo support. There is a separate entry to point to build.clojure.org. Two tasks were also added. One is initPrjoject. The initProject task was both inspired by Gradle cookbook as well as Hubert Klein Ikkink’s blog post on mixed Groovy and Java using Gradle.

The copyToLib was from the Gradle cookbook also.

That’s all there is to it. Gradle will now take care of all your build needs. If you want to use clojure 1.0 instead of the bleeding edge. Change the line “compile ‘org.clojure:clojure-lang:1.1.0-alpha-SNAPSHOT’” to “compile ‘org.clojure:clojure:1.0.0′”. There isn’t a mvn repo version of clojure-contrib though.

At some point, the artifact id is changing from clojure-lang to just clojure as per this ticket. When that happens, just change your build.gradle file accordingly.

Wave Robot Using Groovy and Gaelyk Part 1 UPDATE

When I first saw Google Wave, all sorts of ideas came to me right away. I wanted to use Google App Engine and Google Wave to do some prototyping on some of the gaming ideas I have. Really, real time XMPP open system with the scalability of Google App Engine, what’s not to like?

The question is, what tools to use. Right now Wave Robot has to be hosted on Google App Engine. I tend to use Groovy for rapid prototyping. That quickly narrows it down to Grails vs Gaelyk. I decided to go with Gaelyk because this really isn’t a traditional web application. Wave Robots interact with people through a series of servlets. Using Grails would be unnecessary for my needs. The approach Guillaume Laforge took with Gaelyk where he effectively groovifed the GAE API is a good fit. My plan is to split the code into three parts. Groovy servlets to handle Wave Robot interaction. Gaelyk to handle the GAE interaction such as DataStore, TaskQueue, Mail, and also to display some simple info if people come to the app itself. The final part is the Game AI part. Given GAE’s daily cpu quota, I don’t know if a complex AI engine will burn it up. I’ll find out soon enough.

I’ll be using IntelliJ 8.1.3. It has terrific support for Groovy and Google App Engine. So let’s get started. You need to download the Google App Engine SDK if you don’t already have it.

First let’s create a new Google App Engine project. For details on how to do that,  check here

Then we need to set it up for Gaelyk.

Edit web/WEB-INF/appengine-web.xml
You have to put in the application id you’ve registered for Google App Engine.
Version number default is 1. That’s fine. Version number is a string, so you can put anything. you can put “theawesomeapp” if you like. If you do that, that particular version of the app will be available under the url theawesomeapp.latest.(yourappid).appspot.com. This let you test and deploy multiple versions of the app.

Add the following to the file

<static-files>
<exclude path="/WEB-INF/**.groovy" />
<exclude path="**.gtpl" />
</static-files>

Now to edit web/WEB-INF/web.xml

Add the following

<!-- The Gaelyk Groovlet servlet -->
<servlet>
<servlet-name>GroovletServlet</servlet-name>
<servlet-class>groovyx.gaelyk.GaelykServlet</servlet-class>
</servlet>

<!-- The Gaelyk template servlet -->
<servlet>
<servlet-name>TemplateServlet</servlet-name>
<servlet-class>groovyx.gaelyk.GaelykTemplateServlet</servlet-class>
</servlet>

<!-- Specify a mapping between *.groovy URLs and Groovlets -->
<servlet-mapping>
<servlet-name>GroovletServlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>

<!-- Specify a mapping between *.gtpl URLs and templates -->
<servlet-mapping>
<servlet-name>TemplateServlet</servlet-name>
<url-pattern>*.gtpl</url-pattern>
</servlet-mapping>

<!-- Define index.gtpl as a welcome file -->
<welcome-file-list>
<welcome-file>index.gtpl</welcome-file>
</welcome-file-list>

now create web/index.gtpl
put the following in the file.

<html>
<body>
<p>
<% def message = "Gaelyk is working!" %>
</p>
<ul>
<% 3.times { %>
<li>${message}</li>
<% } %>
</ul>
</body>
</html>

under web/WEB-INF, create a groovy directory and a lib directory.

edit web/WEB-INF/groovy/dostuff.groovy
put the following in the file.

html.html {
body {
[1, 2, 3, 4].each { number -> p number }

p "Let's have a thumb war!"
}
}

you also need to put the following jars in web/WEB-INF/lib

first the two jars from Google App Engine SDK:appengine-api-1.0-sdk-1.2.6.jar and appengine-api-labs-1.2.6.jar.

the Groovy jar: groovy-all-1.6.5.jar

Then the Gaelyk jar. I build gaelyk-0.3-SNAPSHOT.jar from github. Mostly because Guillaume hasn’t had time to build 0.3 yet. You can use 0.2 from Gaelyk site..

After this, add lib to your module library path.

Congratulation, your Gaelyk environment is all set. Run it, and you’ll see the output “Gaelyk is working!” 3 times. That comes from index.gtpl. Now go to http://localhost:8080/dostuff.groovy you’ll see the output from the dostuff.groovy Groovlet.

With Gaelyk setup out of the way, it’s time to get to the Wave Bot.  First you need to download a few files from Wave Robot Java Client Library. Get all 4 of them and place them under WEB-INF/lib.  We only need 3 of them right now. But oauth will come in handy later.

Create a new directory called _wave under web. And create a file web/_wave/capabilities.xml,

<?xml version="1.0"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:capabilities>
<w:capability name="blip_submitted"/>
</w:capabilities>
<w:version>Alpha1</w:version>
</w:robot>

This is where we tell Wave which events our Wave Robot cares about. In this case, we want blip_submitted. This event occurs everytime someone “completes” a blip by either clicking on “Done”, or hit shift-enter. There is also a version number for the Wave Robot. This version number has NOTHING to do with the Google App Engine version number. Everytime you create a new version of the Wave Robot you have to change this. Because Google Wave caches your robot. Again, it’s a string. So you can put whatever you want.

Now to create the servelets that let our Wave Robot to pretend to be human. Under src, create a groovy directory.

First create src/groovy/ProfileServlet.groovy using the following

import com.google.wave.api.ProfileServlet

class ProfileServlet extends com.google.wave.api.ProfileServlet {

  String RobotName="Wave Nakama"
  String RobotAvatarUrl="http://wavenakama.appspot.com/images/wnlogo.gif"
  String RobotProfilePageUrl="http://wavenakama.appspot.com/"

}

This servlet is called whenever someone try to get the profile on your Wave Robot.

Then create src/groovy/SayanythingServlet.groovy using the following

import com.google.wave.api.*

class SayanythingServlet extends AbstractRobotServlet {

    void processEvents(RobotMessageBundle bundle) {
        def wavelet = bundle.wavelet
        if (bundle.wasSelfAdded()) {
            def blip = wavelet.appendBlip()
            def textView = blip.document
            textView.append("Your wish is my command!")
        }
        for (event in bundle.events) {
            if (event.type == EventType.BLIP_SUBMITTED) {
                def blip = wavelet.appendBlip()
                def textView = blip.document
                textView.append("Tell me more about ${event.blip.document.text} Please. You are so interesting!")
            }
        }
    }

The servlet responds to two events. The first was is “wasSelfAdded”. This happens when the Wave Robot is first added to the Wave. Think of it as your Wave Robot’s greeting. The second one is what we marked back in the capabilities.xml, BLIP_SUBMITTED. You can access the blip that just occurred in event.blip.document.text.

Now we have to edit the the web.xml again to register the two servlets. Google Wave expects the Wave Robot to repsond to specific urls.

Add the following to the web.xml

<servlet>
<servlet-name>Sayanything</servlet-name>
<servlet-class>SayanythingServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Sayanything</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>Profile</servlet-name>
<servlet-class>ProfileServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Profile</servlet-name>
<url-pattern>/_wave/robot/profile</url-pattern>
</servlet-mapping>

The Profile servlet must respond to the url /_wave/robot/profile. The Wave Robot communicate with the Wave system using /_wave/robot/jsonrpc

That’s it. Right now there is no way to test Wave Robot locally. However, you can see if the Wave Robot is responding to the Profile call correctly by going to http://localhost:8080/_wave/robot/profile. If everything is working, you’ll see a JSON output of the Wave Robot profile.

I created an image to be used as the Wave Robot profile picture and placed it under web/images.
Final step, time to upload the application to Google App Engine.

When it’s done, try it out by going to (applicationid).appspot.com to verify your app is working. Then create a new Wave. Add your Wave Robot as a participant by using the address (applicationid)@appspot.com. For example, in my case it’s wavenakama@appspot.com.

If all goes well, you now have the basic Gaelyk and Wave Robot setup for you to experiment with.

One thing you’ll notice is the Profile url for the Wave Robot doesn’t appear to be working. I’m guessing it’s a bug of the API.

UPDATE: Thanks to Tim Yate who tracked this done. The official code is wrong. It’s RobotProfilePageUrl, not RobotProfileUrl. I’ve corrected the code sample, and filed an issue with Google.

Gradle + Clojure = clj-gradle

I’m not a maven fan. I use it with lift, but that’s pretty much it. In short, I only use it when I’m forced to. So when Gradle came along, I adapted it pretty early on. If you don’t know what Gradle is. Check it out here. It has extensive documentation, which is very impressive considering the project is so young.

When Meikel Brandmeyer announced he wrote clj-gradle, I really wanted to try it out. I finally found time to give it a spin. I ran into a few bumps, but I did get it to work. Here is what I did, step by step.

Get the source. You need mercurial. Use “hg clone http://bitbucket.org/kotarak/clj-gradle/”

In the directory, “mkdir lib”, then put clojure-1.0.0.jar in lib.

Check the build.gradle file, the version number should be set to 1.0.0

Issue “gradle build”. You should get a build successful. The file clj-gradle-1.0.0.jar is created under build/libs.

You are done. Time to try it out.

Create a new sandbox directory. Then issue “mkdir lib”, you need to put both clj-gradle-1.0.0.jar clojure-1.0.0.jar in lib.

I followed the README and created src/main/clojure/test/example.clj, then pasted in the code from it.

(ns test.example
  (:gen-class))

(defn -main
  []
  (println "Hello, World!"))

I then use the build script from README, with a few changes to put in specific version number.

buildscript {
  repositories {
    flatDir name: 'lib', dirs: 'lib'
  }
  dependencies {
    classpath name: 'clj-gradle-1.0.0'
  }
}

usePlugin(de.kotka.gradle.ClojurePlugin)
  repositories {
    flatDir name: 'lib', dirs: 'lib'
  }

configurations {
  compileOnly {
    setVisible(false)
    setTransitive(false)
  }
  compile.extendsFrom(compileOnly)
}

dependencies {
  compileOnly name: 'clj-gradle-1.0.0'
  compile name: 'clojure-1.0.0'
}

Now issue “gradle build”, you should get a build successful. To run it, I used “java -cp lib/clojure-1.0.0.jar:build/libs/cljgradletest-unspecified.jar test.example” I used cljgradletest-unspecified.jar because the name of my sandbox directory is cljgradetest. All goes well, you’ll see the “Hello, World!” output. Congratulation, your clojure project is now backed by Gradle.

Kindle 2 International Version

I’ve been reading books on laptops and PDAs for years. I still remember fondly of reading on my Clie NZ90. With the latest price drop and the new international version I decided it was time to give Kindle 2 a shot.

It arrived in a tiny brown box, with a cute opening tab

When you open it up, this is what you see.

The unit feels thin and light in your hand.

The manual is under the unit

The cable is under the manual

Here is the charging cable by itself

The back of the unit feels cheap to me. I don’t know why there are all these streaking marks all over the metal plate.

To show you what reading on Kindle 2 is like. I took this picture at normal reading distance using a normal view lens. I also use daylight in a cloudy day. The book on the screen is Programming in Clojure. You can see how it wraps the code due to not enough space.

When you buy Kindle, it comes pre-registered to the amazon account you used to buy it. If it’s a gift or for someone else you’d have to de-register on the buying account first. They did this so it works “out of the box”. Amazon has clearly take a page from Apple when it comes to packaging and presentation. The packaging feels small footprint, environmentally friendly and “green”.

The e-ink screen reading experience is good. I can totally understand why one of my friends said “This is so much better than reading on laptop. I don’t feel like someone is shinning a flashlight into my eyeballs”. But the e-ink display is still slow at refreshing the page. There is a 1-2 sec pause between flipping pages. When you press next page, the screen will go completely black briefly before rendering the next page.

I don’t think Kindle 2 is a good device for reading tech books though. If you look at the screen shot above, you’ll see how the code wraps very badly due to not enough space. I’ve also seen tables rendered very poorly again due to lack of space. When I read tech books, I tend to flip back and forth quite a bit. This is clumsy to do on Kindle 2. The navigation UI is not that great either.

On the other hand, I bought two mystery novels, two fantasy novels, and two political science books. Reading those on Kindle 2 is great. Because they don’t really have any tables/digrams. No color content existed at all. I’m just reading them through, page by page. In those situations, Kindle 2 works as advertised.

So for the time being, I’d say Kindle 2 is excellent if you are reading for fun. But as a tool for teachers/students/researcher, not so much.

I did run into two issues trying to buy books for Kindle 2. The first one was when I tried to buy 6 books rapidly in a row, since Amazon does this as six transactions in a row. The bank rejected the 6th transactions. I wish I can buy them as a single transaction. After all, it’s not uncommon for me to go to bookstore and buy 6 books together.

The second problem isn’t a Kindle one, but really more of a sad note. I was looking for tech books that works on Kindle 2. O’Reilly supports Kindle 2 using the mobi format, and I saw O’Reilly is doing a buy 2 get 1 free. I figured since O’Reilly used to be my favorite publisher, this should be no problem. Sadly after looking for about 30 minutes, I could only find two. One of them in fact is just the ebook version of the printed “Real World Haskell” I already own. Manning and APress really has taken over as the superior tech book publishers.

Lift Comet Chat Example

I recently did a presentation on Lift. A lot of the materials were drawn from:David Pollak’s Java One Presentation and Marius Danciu’s Presentation. I posted the slides at linkedin. I wanted to demostrated Lift’s strength. So I created a quick Comet Chat example based on David’s code.

There were quite a few requests on the code. Instead of just create a zip file to let you download it. I’m going to walk you through how to build it.

First you need maven2. You can’t do anything with lift without it. You can download it here Come back to this when you finish downloading and installing it. You need to be able to issue mvn command.

Next we are going to create the lift project. For this one, we’ll use the lift-archetype-blank archetype.

mvn archetype:generate -U \
  -DarchetypeGroupId=net.liftweb \
  -DarchetypeArtifactId=lift-archetype-blank \
  -DarchetypeVersion=1.0 \
  -DremoteRepositories=http://scala-tools.org/repo-releases \
  -DgroupId=demo.app \
  -DartifactId=chat \
  -Dversion=1.0-SNAPSHOT

After tons of maven stuff scrolling through your screen. When it’s done. A directory called chat will be created. Now let’s run it to make sure it works.

cd chat
mvn jetty:run

If this part worked. You’ll see jetty up and running at port 8080. You can check it out by going to http://localhost:8080 on your browser.

Hit Ctrl-C and stop the running jetty. Onward to the next part.

Now you need to create src/main/scala/demo/app/comet/Chat.scala

package demo.app.comet

import scala.actors.Actor
import Actor._
import net.liftweb._
import http._
import js._
import SHtml._
import JsCmds._

case class Messages(msgs: List[String])

object ChatServer extends Actor with ListenerManager {
  private var msgs: List[String] = Nil

  protected def createUpdate = Messages(msgs)

  override def highPriority = {
    case s: String if s.length > 0 =>
      msgs ::= s
      updateListeners()
  }

  this.start
}

class Chat extends CometActor with CometListenee
{
  private var msgs: List[String] = Nil

  def render =
    { msgs.reverse.map( m =>
  • {m}
  • ) }
{ ajaxText("", s => {ChatServer ! s; Noop}) }
protected def registerWith = ChatServer override def highPriority = { case Messages(m) => msgs = m ; reRender(false) } }

That takes care of the code. You now have to include it in the view. To do this, edit src/main/webapp/index.html

The default file looks like below

<lift :surround with="default" at="content">
                <h2>Welcome to your project!</h2>
                <p><lift:helloWorld.howdy /></p>
</lift:surround>

Replace it with

<lift :surround with="default" at="content">
                <lift:comet type="Chat" />
</lift:surround>

That’s it. Now issue

mvn jetty:run

And you’ll see the Comet Chat in all its glory.

ASUS 1000HE Netbook

When netbooks first started coming out last year, I was very interested. I’m a sucker for tiny laptops. Plus the first waves of netbooks were all running Linux, which is a major plus. I’ve been using Linux for a LONG time, but always on desktop. Wifi and Power management were always the two pain points when running Linux on laptops.

I never bought any of them because they were under powered, screen was too hard to read, and quite frankly the keyboards were for the birds.

ASUS 1000HE changed all that. It has a 10 inch LCD screen with resolution of 1024×600. The keyboard size is 92% of a full size keyboard. The keys are square and straight up just like the MacBook keyboards. And the Intel N280 Atom CPU at 1.66ghz is fast enough. So far pystone is the only benchmark I’ve run. I got 24000 on the 1000HE. For comparison, I got 43000 on my 1.86ghz MacBook Air. Yes, I know pystone isn’t the greatest benchmark in the world. :)

This is also the first time where Linux on laptop “just worked”. Fedora 10 installation was very fast. Upon booting the first time, it configured the screen to the right resolution. Found the 802.11 N card, configured it, and brought it up. All ACPI functions are working, which means power management is working perfectly.

It has 160GB 5400 RPM Seagate drive, 3 USB port, 4-in-1 SD card slot, VGA out, and Ethernet port. It also has a 1.3megapixel camera for video conference.

The mousepad also supports 2 fingers scrolling gestures, and 3 fingers swipe gestures. Big bonus since I’m so used to my Mac laptops. I find myself doing 2 finger scrolling on any laptops I touch, and tend to think something is broken when I can’t scroll doing that.

The battery life is crazy good. I got 7.5 hours on the first attempt to drain the battery.

So far, the only negatives are:
1: the GPU sucks. It’s the Intel 945GSE. Yes, the Intel extreme graphics chip, where the only thing extreme about it is extremely slow. It would’ve been nice to have the GN40, but honestly, this barrier will be up to Nvidia and ATI to shatter. In particular, Nvidia’s upcoming Ion chipset for netbooks, which is really a GeForce 9400M.
2: The mousepad doesn’t feel as responsive as my MacBook Air.
3: I wish I can put 4GB on it.

In short, I love it.

Photo set here

DSLR, What Have You Done To Me?

As most of you know, I’m lazy and don’t like to get up early in the morning. I don’t like to walk. I don’t like to stand.

So how is it that I end up at Franklin Park Conservatory at 9AM in the morning today, getting in line to collect my two butterflies to release into the Pacific Forest area? I blame DSLR. Ever since I started getting into taking pictures in Dec. I started doing things like this, things that me go “Huh?”

These are my two butterflies to be released.

Here is P releasing her first one.

I took over 400 photos. I’m still sorting and uploading them right now. I’ve created a set. As new photos are uploaded, they will be added to the set.

I took Canon 50D, 1 zoom lens and 1 prime lens. The zoom is 70-300mm. The prime is 50mm 1.8. More on the gears later, since there has been several questions about my messenger bag.

←Older