Sunday May 11, 2008

Time flies by, it has been ten months since last post. :-)

Recovering from another JavaOne, this year I participated in Project Hydrazine, created a web tool that can be used to create new services given a RSS/ATOM feed or just XML document contains recurrent elements. The tool also allows you to easily provision services on your phone. The team had created a solid foundation for this web tool to be possible.

Here is my favorite story at the JavaOne Project Hydrazine booth: A developer came see the demo, and he said Slashdot when we asked his favorite feed, so we locate the RSS feed, and in minutes we got to read Slashdot on the phone. Imagine combine this tool with Yahoo Pipes, you can get fully personalized services on your phone.

If you were not there at JavaOne, you probably would like to check out here for sessions available online. Personally, I think the lottery program powered by the Blue Wonder demo is pretty neat, congratulations on another good work for JavaOne, Mike.

 

 

Tuesday Jul 03, 2007

I had being using fetchmail + exim4 + courier IMAP server at home to allow me get IMAP service for my Gmail service. One reason is of course, I like to use thunderbird or evolution better than web-based interface. Another important reason is that, as many developers, I have quite a few mailing list subscription for different open source projects, I would like to automatically sort emails from those subscription into different folders, which I have being using procmail for that purpose.

But my Ubuntu desktop at home somehow screwed up the root file system after I tried the "switch user" and "automatically login" feature(to allow my one-month-to-five-year-old son playing games from the web), and that old P4 server consumes 80-100 watts constantly while my laptop only consumes 25 or so, I decided to ditch the home server until I can get my hands to a NSLU2 or other similar devices.

With that decision, I would like to give Gmail web interface a chance as I do like the conversation view although many people seems to hate it. But, I need to sort emails from various mailing list subscription with correct label, so that I can read them when I like, delete them permanently easily while allow me to keep other emails in archive(I have used 800MB+ quota due to those archived emails).

Supposedly, I should be using filter and label systems to do that. But as you may know, Gmail does not offer filter based on arbitrary headers, although there are mailing lists put prefix on Subject, but that is less reliable than using headers like List-Id or List-Post. Thus, I decided to write a simple Ruby script with gmailer library to do just that.

Unfortunately, Google does not like the idea of scripting and locked my account. Shortly after the account was unlocked, even I apply label manually from the web caused another lock.

I don't really understand the mindset of not providing simple features like arbitrary header filter against regular expression, maybe 80-20 rule would explain. But not allowing people to do it with simple script?

 

Unless Google is willing to loosen the restriction a little bit or provide
a better solution to create filters, I guess I will have to setup another server.

 

Friday May 18, 2007

Remember when I first saw Roger Meike showcased Sun SPOT by making a ball pass through his head utilizing the 3-axis accelerometer and LEDs on two Sun SPOTs at a Sun internal SEED event, I was thinking(as I was working on the Robosapien SDK) maybe we can connect a  to a Robosapien, then we can hold others in both hands and have Robosapien imitate the operator, that would be really funny.

Now with the Sun SPOT development kit and Robosapien Java SDK available, this is really feasible as I learned that it is possible to connect them through serial port. What you need to do is to connect one Sun SPOT to Robosapien through serial port(a pretty easy modification) and write an MIDlet on Robosapien to wait for instructions from the Sun SPOT connected to the Robosapien. The challenging part would be that the serial port is used as console as well.  While SPOTs can communicate to each other through IEEE 802.15.4, I bet there could be a lot of fun. 

During JavaOne, I am glad to learn that Arshan and Mohamed are going to work together to do something interesting with Sun SPOT and Robosapien, but I cannot tell you what it is yet. :-)

Too bad I don't have spare money for a Sun SPOT developer kit now, maybe after 2 years, I can use my son's 7th birthday as a good excuse.

Wednesday May 16, 2007

It has been fun, fun, fun to play with Robosapien. WowWee RS Media is quite an impressive humanoid robot for a toy, and there has been a community around it. Now with the Java SDK first available at JavaOne (Note: It's an evaluation/beta copy has certain limitation.), you can program an MIDlet to control it.

If you have been to James' The Toy Show keynote or come to the booth at JavaOne, you may have seen it danced, it also made appearance on a few medias. Two clips are on YouTube as well.

And, Bernard, may I call you Mr. Roboto from now on? :-) 

Anyway, I would like to see more dances in Java code, so here I would like to offer some help. If you have ever created a personality dance or compose some movement with WowWee's PC Editing Suite, the following Ruby script would help you convert it into a set of Java function calls. Although the generated code is not a complete program, but you will be able to embed it into your class pretty easy.

Talk about Ruby, you have to check out the NetBeans 6 with Ruby support, it's fantastic, and the script works well in JRuby as expected.

#! /usr/bin/ruby

$move_number = nil
$rxp_number = Regexp.new('movement group .*:(\d+)')
$rxp_motor = Regexp.new('/usr/bin/robot/scripts/MotorRel.sh ([[:xdigit:]]+) ([[:xdigit:]]+) ([[:xdigit:]]+)')
$rxp_wait = Regexp.new('/usr/bin/robot/scripts/wait_rtn.sh *(\d*)')
$rxp_delay = Regexp.new('/usr/bin/robot/scripts/time_delay.sh (\d+)')
$dance_body =  "\nprotected void doDance(Humanoid robot) {\n"
$dance_body += "    this.robot = robot;\n"

$servo_name = %w{ HEAD_UP_DN_SERVO HEAD_LR_SERVO SHOULDER_LEFT_SERVO SHOULDER_RIGHT_SERVO ARM_LEFT_SERVO ARM_RIGHT_SERVO
    WAIST_UP_DN_SERVO WAIST_LR_SERVO WAIST_SLR_SERVO LEFT_LEG_SERVO RIGHT_LEG_SERVO HEAD_UPPER_BODY }
$servo_multiplier = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1 ]

def convert(l, f)
    case l
    when $rxp_number
        f << "}\n" unless nil == $move_number
        $move_number = $1.to_i
        f << "\nprivate void move#{$move_number}() {\n"
        $dance_body += "    move#{$move_number}();\n";
        return false
    when $rxp_motor
        motor_no = $1.to_i(16) - 1
        pos = $2.to_i(16) / $servo_multiplier[motor_no]
        speed = $3.to_i(16)
        s = "    robot.#{$servo_name[motor_no]}.moveToPosition(#{pos}, #{speed});\n"
    when $rxp_wait
        if $1 == "" then
            s = "    robot.waitUntilStop();\n"
        else
            s = "    robot.waitUntilStop(#{$1.to_i});\n"
        end
    when $rxp_delay
        s =  "    try {\n"
        s += "        Thread.sleep(#{$1.to_i});\n"
        s += "    } catch (InterruptedException ex) {\n"
        s += "    }\n"
    else
        return
    end
    if nil == $move_number
        $dance_body += s
    else
        f << s
    end
    false
end

if ARGV.length != 2
    puts "Usage: bcn2java <bcn filename> <java filename>"
end

java = File.open(ARGV[1], "w")
File.open(ARGV[0], "r") { |f|
    f.each_line { |l|
        convert(l, java)
    }
}
java << "}\n" unless nil == $move_number
$dance_body += "    this.robot = null;\n"
$dance_body += "}\n"
java << $dance_body
java.close

Thursday Dec 07, 2006

During Thanksgiving weekend, I had an interesting challenge.

A friend of mine lost his photos on a xD when transferring them to his PC running the you-know-what-OS. Somehow the disk became "unformatted". He came to me with little hope that those photos can be recovered.

The first thing I thought was that maybe it is just the partition table been destroyed, if I can restore the partition table, which should be relative simple, then we will be good.

Anyway, we needed to get the disk image first. So with my laptop running Nevada build 50, I did following:

$ dd if=/dev/dsk/c3t0d2p0 of=xd.img

Used xxd which is distributed with vim, I peeked into the first sector to see if there is 0x55AA mark. It looked like a directory structure for FAT and of course, 0x55AA was not there. Look further, the FAT table was ruined as well.

Now it would be hard to recover from the file system perspective. Since this is digital camera, most of it would be JPEG files and those are what we care about, and more likely it would be continuous data rather than scatter around the disk. With that assumption, I googled for the JPEG file format, and find this page by TsuruZoh Tachibanaya. With that, I was able to write a simply Ruby script to play with the disk image.

Viola, 567 images are recovered and only 4 of them having problem. Happy Thanksgiving!

For those who might be interested, here is the script. Not perfect but working, and given that I am still learning the language, comments are welcome. :-)

def fn(sno, ext="jpg")
  sprintf("F%06d.%s", sno, ext)
end

def to_hex(x)
  sprintf("%X", x)
end

def find_SOI(f)
  found = false
  until f.eof? || found
    x = f.getc
    if x == 0xff then
      x = f.getc
      if x == 0xd8 then
        found = true
        print "SOI detected at #{to_hex(f.pos - 2)}\n"
      else
        f.ungetc(x)
      end
    end
  end
  found
end
        
def find_EOI(f, of)
  found = false
  until f.eof? || found
    x = f.getc
    of.putc(x)
    if x == 0xff then
      x = f.getc
      if x == 0xd9 then
        found = true
        of.putc(x)
        print "EOI detected at #{to_hex(f.pos - 2)}\n"
      else
        f.ungetc(x)
      end
    end
  end
  found
end
        
def find_SOS(f, of)
  found = false
  until found
    x = f.getc
    if x != 0xff then
      print "Error: Marker expected at #{to_hex(f.pos - 1)}\n"
      return false
    end
    of.putc(x)
    x = f.getc
    of.putc(x)
    print "Marker 0xFF#{to_hex(x)} detected at #{to_hex(f.pos - 2)},"
    if x == 0xda then
      found = true
    end
    x = f.getc
    of.putc(x)
    sz = x << 8
    x = f.getc
    of.putc(x)
    sz |= x
    print " with size #{sz}\n"
    of.write(f.read(sz - 2))
  end
  found
end
  
f = File.open(ARGV[0])
seq = 0
until f.eof?
  rv = find_SOI(f)
  if rv then
    seq += 1
    of=File.open("#{fn(seq)}", "w")
    of.putc(0xff)
    of.putc(0xd8)
    rv = find_SOS(f, of) && find_EOI(f, of)
    of.close
    unless rv then
      File.rename(fn(seq), fn(seq, "dat"))
    end
  end
end
f.close

# vim: set ts=2 sw=2 tw=80 et:

Wednesday Apr 05, 2006

News with title Apple Unveils Software to Run Windows XP grabs my attention immediately, after read about Boot Camp, I am disappointed. Although I believe Apple makes it easy. :-)

Dual boot, in fact, multiple boot, is nothing new, it has been there for years. For me, the solution only works for a different machine from the one I conduct my work. Running different OS simultaneously is something I really needed on the machine I used everyday.

With CPUs support virtualization technology, it is possible to run a unmodified OS in a VM. Although I haven't get a chance to play with it, Xen 3.0 seems to be supporting that. And that's what I need to have multiple OS running on my desktop(laptop).

Thursday Mar 30, 2006

We were driving north on highway 680 at 65-70 MPH after a get together at a friend's place on Saturday night, remained straight in the lane. Bang, our car almost started spin. After stabilize the car and pull over to the road side, the red car causing the accident just fled away.

Praise the Lord, although my wife was a little bit panic, both of us and our two young children in car seats at the back are safe. It was dark and things happened fast, we were not capable to get the license plate before we can start thinking, and no one else stopped. Therefore, although we have Uninsured Motorist policy with Allstate, the damage to our 2000 Honda Accordit is not covered, bummer.

CHP officers shown up from nowhere in 10 minutes(we were kind of dumb to call insurance first before 911), ask me what do I want to do. This is kind of ironic when I would like him to tell me what can he do. The officer then wrote a collision report for us.

I am disappointed that CHP made no attempt to chase or intercept the suspect, and there is no a effective system to find the suspect when you don't get the license plate. At lease one thing can be improved is to require bodyshop to report damage over $750 just like how DMV requires car owners to do so.

Now I can only hope some witness got the license plate and is willing to report to CHP.

Wednesday Nov 02, 2005

As JDS source is released on 10/28, I decide it is a good time to try it out. If everything works as expected, maybe pkgtool/pkgbuild can become the official package building environment for OpenSolaris.

So I read the instruction and start to follow.

I would like to have the build environment in my home directory rather than the default /jds/cbe, with Gman saying it should work, I decide to give it a try.

So, step 1, add myself with Software Installation profile. Open up /etc/user_attr and modified. Done.

step 2, ./cbe-install. Failed with following message:

Run this script as root or a user with the "Software Installation" profile
See the user_attr(4) and profiles(1) manual pages for details

After some investigation, there is a /usr/sfw/bin/profiles which is started rather than the desired /usr/bin/profiles. Setting my path by move /usr/sfw/bin to last. Move on.

Need some packages from Solaris, OK. Pop in my nv_24 DVD, and give the path, /cdrom/sol_11_x86/Solaris_11/Product, all needed packages are installed. Easy!

Now, base directory, like I said, I would like to use home directory, so I tried:

Enter the base directory (prefix) of the cbe [/jds/cbe]: ~/jds/cbe
Would you like to create it now? [yes]:
Failed to create directory ~/jds/cbe (mkdir: "/~/jds/cbe": Permission denied)
Okeydo, try absolute path.
Enter the base directory (prefix) of the cbe [/jds/cbe]: /home/henryjen/jds/cbe
Would you like to create it now? [yes]:

That works, continue, argh, my Sun Studio does not have the required patch, how about smpatch analyze? Need to register, OK, updatemanager, register without a key, updating ..., a dialog popup, Read System Analysis Data Error. Try again as directed, the same.

OK, try another way. Download required patch as mentioned at http://opensolaris.org/os/community/tools/sun_studio_tools/. Follow the instruction. Voila, it is building CBE.

Saturday Aug 20, 2005

Just for fun. To be fair, I check out a English->Chinese dictionary for the vocabulary

Your IQ Is 120
Your Logical Intelligence is Exceptional Your Verbal Intelligence is Genius Your Mathematical Intelligence is Genius Your General Knowledge is Average

Only if I double check :-)

Your IQ Is 135
Your Logical Intelligence is Genius Your Verbal Intelligence is Genius Your Mathematical Intelligence is Genius Your General Knowledge is Exceptional

Tuesday Aug 16, 2005

Martin Fowler is one of my favorite author/blogger. Reading his article always give me something to learn or think about, "inspiring", yup, that's the word. His article about Rake is another good one and now I am thinking if this can help me to achieve something like Gentoo's portage or OE's BitBake with more flexibilities.

This blog copyright 2009 by slowhog