Dec 23, 2010

java.lang.VerifyError caused by Play-Morphia

It comes out intermittently and shows something like:
Exception in thread "main" java.lang.VerifyError: (class: models/NodeDelta, method: findById signature: (Ljava/lang/Object;)Lplay/modules/morphia/Model;) Wrong return type in function
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(
at java.lang.Class.getDeclaredMethods(
at play.modules.morphia.MorphiaPlugin.afterApplicationStart(
at play.Play.start(
at play.Play.init(
at play.server.Server.main(

Something is wrong obviously in the bytecode enhancer. But I just can't figure it out until i noticed the line of code:
CtMethod findById = CtMethod.make("public static Model findById(java.lang.Object id) { return mf.findById(id); }",ctClass);

Where mf is an instance of play.db.Model.Factory, and method play.db.Model.Factory#findById return an instance of play.db.Model, while actually a play.modules.morphia.Model is expected. Changing the line to the follows fixed the VerifyError:
CtMethod findById = CtMethod.make("public static Model findById(java.lang.Object id) {return (Model)mf.findById(id); }",ctClass);

Dec 15, 2010

Create a hierachical navigator in IBM Lotus WCM

I googled for long time for a solution that could produce hierarchical unordered list corresponding to site areas. Something like:




I follow the method introduced here. However I found it does not work out the whole hierarchies. I guess the NAV--SubNavigation with StartType equals to "Current Site Area" prevent it from happening.

The final solution is to use navigator to generate a linear list of nodes and use javascript to reconstruct the hierarchies.

Here is navigator definition:

Start Type: selected
Include Start: false
Ancestor Level: none
Descendant Level: All (or choose the level of hierarchies you want)
Preceding Siblings Level: none
Next Siblings Level: none
Show Site: false
Show content: false
Expand current navigator branch one level: false
Expand navigator to display current site area: false
Results per page: 1000 (or choose a number that is larger than the maximum items)
Start page: 1
Maximum pages to include: 1000 (or choose a number large enough)
Pages to read ahead: 1000 (or choose a number large enough)
Distinguish items with no children using the final navigator result design: false
Header: <url>
Footer: </ul>
Navigator result design 1:
<li class="l1" id="<Placeholder tag="idnum"/>"><a href="<Placeholder tag="href"/>" target="_self" title="<Placeholder tag="Title"/>"><Placeholder tag="Title"/></a></li>

Navigator result design 2:
<li class="l2" id="<Placeholder tag="idnum"/>"><a href="<Placeholder tag="href"/>" target="_self" title="<Placeholder tag="Title"/>"><Placeholder tag="Title"/></a></li>

Navigator result design 3:

And this navigator gives the following html code:
<li class="l1">A</li>
<li class="l2">A.1</li>
<li class="l2">A.2</li>
<li class="l1">B</li>
<li class="l2">B.1</li>
<li class="l2">B.2</li>
<li class="l2">B.3</li>
<li class="l3">B.3.1</li>
<li class="l3">B.3.2</li>
<li class="l3">B.3.3</li>

Now it's javascript's work. In order to re-constructure the hierarchies, I write the following codes:

function process(level) {
var sel = 'li.l' + (level - 1);
jQuery.each(root.children(sel), function(id, el){
var pe = jQuery(this);
var dock;
var nl = pe.nextUntil(':not(li.l' + level + ')');
jQuery.each(nl, function(id, el){
if (!dock) dock = getDock(pe, level - 1);

function getDock(pe, level) {
var ul = pe.children('ul');
if (ul.size() == 0) {
ul = jQuery('<ul class="l' + level + 'ul"></ul>').appendTo(pe);
} else {
ul = ul[0];
return ul;

var root = null;
root = jQuery('#ul'); //you should update #ul accordingly
jQuery.each([5,4,3,2], function(id, val){process(val)});

Now a good rendered hierarchies presented in my final html page.

Nov 16, 2010

Build full text search capability upon MongoDB

Recently I am working on a content management system migration project. We have exported the existing system into a folder composed of 18k xml files organized into a set of sub folders. What we need to do is to understand the relationships among the files and folders, manipulate them by adding/removing/updating and then import into a new server.

Navigating through these huge amount of files is definitely not an easy task, and the embedded base64 encoded content makes this task almost an MIP. This is why I decide to build a full-text search tool to help us quickly locate files contain certain contents we are interesting at any time.

I pick up MongoDB because it is a document database, don't need restricted schema definition, and I am quite familiar with it as the author of play-morphia plugin. So what I am doing is to write a script (in perl) parse all XML files into the database. The script parse tags/attributes/text nodes/CDATAs of the XML files, decode base64 element if found. The interesting part is how to setup a full-text search capability in MongoDB. Following this article, I've created an array column called keywords for each document. The XML parser script will add into keywords array for each words found in tags/attributes/text/CDATA and decoded Base64 content.

Next is to implement a query for full text search, which is not specified in the article mentioned above. The key for full text query is use $all operator and regular expression. For example, if you want query documents including both "NSW" and "QLD", the query statement in javascript could be:{_keywords:{$all:[/\bNSW\b/, /\bQLD\b/]}});

In java, the code snippet could be:

DBObject q = new BasicDBObject();
if (keys_.size() > 0) {
DBObject keys = new BasicDBObject();
List pl = new ArrayList();
for (String w: keys_) {
w = w.replace("\\s+", "\\s+");
keys.put("$all", pl.toArray(new Pattern[]{}));
q.put("_keywords", keys);
DBCursor c = col_.find(q);
if (0 < skip_) c.skip(skip_);
if (0 < limit_) c.limit(limit_);

Oct 1, 2010

Google.load vs. $(document).ready()

I am trying to use google visualization in my recent project. After some study, I found it is quite different in terms of usage from my previous mindset. Usually when we need an external javascript library, we go to the web site and download it, and include it in our html file like:

<script type='text/javascript' src='url-to-the-js-lib'></script>

However, this is quite different with google visualization case. A typical usage with google visualization could something like:

<script type='text/javascript' src='http://'></script>
<script type='text/javascript'>
google.load('visualization', '1', {'packages':['piechart', 'table', 'linechart']});
</script >

the API name "setOnLoadCallback" is misleading to me. It looks like a special hook that get invoked when the visualization (or other google apis) loaded into the dom. So here is my hypothetical google-loader.js:
$('<div id="google-loading-overlay"></div>').css({
'position': 'fixed',
'top': 0,
'right': 0,
'bottom': 0,
'left': 0,
'background': 'url(/img/busy.gif) no-repeat center center',
'background-color': '#ECECEC',
'z-index': 9999
google.load('visualization', '1', {'packages':['piechart', 'table', 'linechart']});
The idea is simple, create an overlay before calling google.load(...), preventing user from operating the current page and display a busy indicator. After the visualization apis get loaded, remove the overlay and draw the charts.

However, it just don't work. You always get a blank page, in Chrome, it shows an null error, in firefox it looks like the loading process never end. So what's going on here? I suddenly see the light when reading this thread: The problem that you're having here is that google.setOnLoadCallback and $(document).ready are essentially synonymous.. setOnLoadCallback basically means your dom construction is finished. So the solution is very simple, just put the following line in my google-loader.js:
google.load('visualization', '1', {'packages':['piechart', 'table', 'linechart']});

Sep 20, 2010

Setting up Django environment in CentOS 5

I am trying to setup Django v1.2.3 to run on our server which is CentOS 5.2.

Though Django support python2.4 bundled with this OS, I decide to get it running on Python2.6, which makes me feel not so out. In the beginning I was thinking it could be a task of 10 mins, and not expecting so many unexpected things happened:

The first issue is replacing python2.4 with python2.6 breaks the yum toolkit on CentOS 5.2. Shame for that. Fortunately some other guys has met the problem already and there are lot's of blogs and question/answers addressing this issue. I follow this one: how to install python2.6 on centos5 without breaking yum. It almost works, just a minor problem: yum report that libffi-3.0 not found while installing python2.6. So google again, and there it is:
After installing this rpm package, I can get python2.6 installed.

Now download Django-1.2.3.tar.gz from official site, unpack, and run python26 install. Oops, wait, there is problem:

invalid Python installation: unable to open usr/lib/python2.6/config/Makefile

Okay, google again, and someone said it's due to you have not installed python-dev package. Let's try yum install python26-dev and then run python26 install again. Bingo!

Now that we have the Django installed at /usr/lib/python2.6/site-packages. Let's give it a try:

1. update /etc/bashrc, add "export DJANGO_HOME=/usr/lib/python2.6/site-packages/django"
2. . /etc/bashrc && chmod a+x $DJANGO_HOME/bin/*.py
3. ln -s $DJANGO_HOME/bin/ /usr/bin/
4. cd /tmp
5. django-admin startproject mysite

Oops, error again:
Traceback (most recent call last):
File "/usr/bin/", line 2, in ?
from django.core import management
ImportError: No module named django.core

Damn it, I forgot django is installed to python26. Okay, let me do something to hack it:
# cd $DJANGO_HOME/bin
# find . -name '*.py' | sed -i 's/env python/env python26/'

now run django-admin startproject mysite works. and let me continue:
6. cd mysite && python26 runserver

OMG, it breaks again, all the files generated by django-admin use python as default env, not python26. I am getting tired of adding my hacks to Django. I need to figure out some other ways.

Yes, python support virtualenv, that's exactly what I need! Follow the process described in this blog, I can continue again:
# wget
# tar xzf virtualenv-1.5.1.tar.gz
# cd virtualenv-1.5.1
# su greenl
$ python26 ~/opt/local
$ cd ~
$ wget
$ tar xzf virtualenvwrapper-1.23.tar.gz
$ cd virtualenvwrapper-1.23
$ cp virtualenvwrapper_bashrc ~/bin
$ cd ~
$ mkdir .virtualenvs
$ mkvirtualenv django
$ workon django
$ easy_install django
$ cd /tmp
$ sudo rm -rf mysite
$ startproject mysite
$ cd mysite
$ python runserver &
$ lynx localhost:8000

Works perfect!

In conclusion:
1. You can install python2.6 on CentOS 5 without breaking yum
2. You can install django latest version (currently v1.2.3) on python2.6 site-packages
3. You need to install virtualenv in order to get django run on python2.6 transparently
4. You may want to install virtualenvwrapper in order to make your life easier with virtualenv.
5. After you have done all these, you have an nice env for your django journey!

Sep 19, 2010

Routing problem with GreenScript configurator

In the morning when I play with GreenScript configurator to verify it's compatibility with Play-1.0. I found all these mapping entries do not work anymore:
  • http://localhost:9000/gs/
  • http://localhost:9000/gs/conf
  • http://localhost:9000/gs/configure
  • http://localhost:9000/gs/setting

However, this link works: http://localhost:9000/gs (without "/" suffix!)

Later I realized that I have an entry in the routing table of the demo app: GET /gs/ staticDir:public/gs, for shortcut of URL to compressed/minimized files.

Yes, this is the problem. You can't make both static file and controller mapping to the same url path!

Play python interface compatibility

it looks like the new version of GreenScript is quite welcome in the community.

Tom is obviously one of them who love this plugin. He report a bug very promptly. After installed v1.1, as long as he try to invoke any play command like play eclipsify or play greenscript:cp .... it will end up with the following error:
C:\code\phase3>play eclipsify
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~ play!,
Traceback (most recent call last):
File "C:\play-\play", line 1459, in
File "C:\play-\modules\greenscript-1.1\", line 4,
from play.utils import *
ImportError: No module named play.utils

This is my fault. I didn't expect the play command interface has been changed since play-1.1. Here is the solution:

# play_command is defined in Play-1.0 only
except NameError:
play_command = None
if play_command is None:
# ~~~~~~~~~~~~~~~~~~~~~ running on v1.1
# go v1.1 logic
# ~~~~~~~~~~~~~~~~~~~~~ running on v1.0
# go v1.0 logic

Sep 18, 2010

Play-GreenScript v1.1 Released

This is a version with huge improvements:
  • Many bug fixes
  • Completely new Plugin Configurator
  • Add Command to enable user copy module tags/templates to user app directory
  • More clear configuration settings
  • Even more simplified tag syntax
  • Support zero configuration
  • Document improvement

Comparison to v1.0

  1. Configuration:

    • v1.0 - The dependency configuration file: "greenscript.conf" is mandatory
    • v1.1 - Zero configuration
  2. Dynamic configuration

    • v1.0 - A simple window with a <textarea> tag. You are on your own to write the content in the textarea. Error prone: typos, unattended updates to dependencies
    • v1.1 - A sophisticated web interface help you clearly view the status/configuration of GreenScript plugin and prevent you from making mistakes when you try to turn on/off minimizing/compressing/cache.
  3. Tags

    • v1.0 - #{greenscript.css import:['css1', 'css2']/}
    • v1.1 - #{greenscript.css 'css1 css2'/}

      For existing greenscript users, the old syntax also works, but you are encourage to move to the new simple version.

  4. Commands

    • v1.0 - no command support
    • v1.1 - play greenscript:cp -a --tag=xx | -t --template=xx

For more information please go to GreenScript home.

PS: Forgot the secret weapon: with "play greenscript:cp -a .", you can use tags in this way:

#{js 'js1 js2 ...' /}
#{css 'css1, css2, ...' /}

How can you expect anything simpler than this?

Sep 17, 2010

int is not Assignable to Integer!

I've met a strange issue with play-morphia: Model.findById(theId) method failed while Model.filter("_id", theId) method works perfect. Digging into the code stack for while, I found a surprising behavior of java.lang.Class.isAssignableFrom(Class cls) method: If you pass a type of primitive type int/long etc (get from reflection of course) to it's corresponding object type class: Integer.class/Long.class, the method will return false! So while the following line of code compiles and runs perfect (because of autoboxing), the primitive type is NOT assignable to it's peer object type!

Integer i0 = 5; int i1 = i0;

Now the solution:

Object theId =, Model.Manager.factoryFor(clazz).keyType());

As you might noticed, the method is fairly poor in terms of performance because of lot of conversion and reflection operations. And here comes my suggestion to play-morphia user who use @Id to annotate user defined ID fields:

always override public static findById(Object id) method, that will do you big favor. The default findById method is provided in case you are too lazy to implement your own, and the result is it could be pretty slow.

For model classes relies on system generated ID, e.g. you have no field annotated with @Id, you don't need to worry about this. The enhancer will provide faster version of findById() method implementation for your model.

Sep 14, 2010

Unlimited unbinding loop when using ObjectId

Just got the following error in my play templates:

RuntimeException occured : java.lang.StackOverflowError

play.exceptions.JavaExecutionException: java.lang.StackOverflowError
at play.mvc.ActionInvoker.invoke(
at Invocation.HTTP Request(Play!)
Caused by: java.lang.RuntimeException: java.lang.StackOverflowError
at play.templates.BaseTemplate.throwException(
at play.templates.GroovyTemplate.render(
at play.mvc.results.RenderTemplate.(
at play.mvc.Controller.renderTemplate(
at play.mvc.Controller.renderTemplate(
at play.mvc.Controller.render(
at controllers.CKBoxes.index(
at play.mvc.ActionInvoker.invokeControllerMethod(

at play.mvc.ActionInvoker.invokeControllerMethod(

at play.mvc.ActionInvoker.invoke(
... 1 more
Caused by: java.lang.StackOverflowError
at java.lang.Class.privateGetDeclaredFields(
at java.lang.Class.getDeclaredFields(

The problem happens when Unbinder tries to unbind a static field called _nextInc of type org.bson.types.ObjectId:

private static AtomicInteger _nextInc

In AtomicInteger there is a reference to sun.misc.Unsafe which in turn refer to a field with the same type: sun.misc.Unsafe

So what should be the solution? Here are what comes in my mind at the moment:
1. Unbinder do not try to unbind a static field ?
2. Some mechanism should be implemented in Unbinder to prevent endless unbinding loop like this case

As a temporary workaround I add ".toString()" to explicitly get String represent of ObjectId object:

original: #{a @{edit(}edit{/#}
workaround: #{a @{edit(}edit{/#}


Play-Menu published at github. Features include:

* Define menu structure with yaml data file
* Provide easy to use menu tag to insert navigation menu to your web page
* Support current menu
* Support hierarchical structure
* Support customer defined menu model (for those GAE app developers)

Sep 8, 2010

Guice your Play Model class?

This blog discuss a DI implementation pattern on Play model class. However it might also be helpful for developer using other MVC frameworks.

As stated in this page, Model should NOT be kept as a set of simple Java Beans and leave the application logic back into a “service” layer which operates on the model objects.

So there are often good reasons to call to some services utilities/executing tasks from within your model class in order to complete an application logic inside the model class. Here is one example in my recent development work. When users login to the web site, they needs to be able to turn on parent mode for some time, say 1 hour. The parent mode setting will automatically turn off as timeout.

The first version of turnOnParentMode() is like

public void turnOnParentMode(int timeout) {
if (parentMode) return;
if (null == ip) throw new IllegalStateException("Cannot set parent mode when IP address is null");
parentMode = true;
TimeKeeper.register(username, timeout);

As you can see, TimeKeeper::register is implemented as a static class member function so that we can easily call it from anywhere, like from within a Model class. There is nothing wrong with that approach, unless later I decide to unit test this method with JMock. The immediate question I need to answer is how can I mock TimeKeeper::register as it is a static class member?

Vampires (if you don't know who are vampires, take a look at this blog) from the underworld told me that DJ is the answer to questions like the above one. In the beginning they advocate a beast named Spring, but recently they look like be more addicted to a monster called Guice. Since I decide to be part of them I turned to Guice to look for my answer.

Everything is good as I quickly found Guice is supported by Play with play-guice plugin. Yes so far so good until I read this statement: "... inject into your application’s Controller, Job and Mail classes (based on @javax.inject.Inject)". What? injection can only be operate on Controller, Job and Mail classes? Why my poor model class is not in the list?

Alright, let's do something to get it work! First I will change the implementation of turnOnParentMode() to:

@javax.inject.Inject private static timer;
public void turnOnParentMode(int timeout) {
if (parentMode) return;
if (null == ip) throw new IllegalStateException("Cannot set parent mode when IP address is null");
parentMode = true;
timer.register(username, timeout);

And of couse, TimeKeeper::register method will become a non-static instance member. Now we are ready for injection.

Since GuicePlugin won't inject Model class, specifically Playframework won't inject Model class, we need to hack the code of GuicePlugin by adding a new method:

private void injectModelClasses(BeanSource source) {
List classes = Play.classloader.getAssignableClasses(Model.class);
for(Class clazz : classes) {
for(Field field : clazz.getDeclaredFields()) {
if(Modifier.isStatic(field.getModifiers()) && field.isAnnotationPresent(Inject.class)) {
Class type = field.getType();
try {
field.set(null, source.getBeanOfType(type));
} catch(RuntimeException e) {
throw e;
} catch(Exception e) {
throw new RuntimeException(e);

And add the following line to the end of onApplicationStart() method:


Okay, let's compile GuicePlugin by running ant, and then "play run", everything is okay, TimeKeeper debug info shows out, looks like our code is good, and more importantly we don't rely on static TimeKeeper::register method, we have some flexibility to inject different implementation of TimeKeeper instance to our model class.

But wait, we haven't solve the problem of unit test turnOnParentMode() method yet, how to replace the injection with a mock object of TimeKeeper? I will answer this question in next blog.

BTW, a suggestion to Play team:

Add a new interface say: InjectSupport, and have ControllerSupport, Mail and Job class to extend/implement the InjectSupport tag interface, and change the code of Injector::inject to:

public static void inject(BeanSource source) {
//List classes = Play.classloader.getAssignableClasses(ControllerSupport.class);
List classes = Play.classloader.getAssignableClasses(InjectSupport.class)
for(Class clazz : classes) {
for(Field field : clazz.getDeclaredFields()) {
if(Modifier.isStatic(field.getModifiers()) && field.isAnnotationPresent(Inject.class)) {
Class type = field.getType();
try {
field.set(null, source.getBeanOfType(type));
} catch(RuntimeException e) {
throw e;
} catch(Exception e) {
throw new RuntimeException(e);

This way we are not limited DI to only Controller, Mail and Job classes, we add the flexibility to enable developer to inject any class he/she want using play-guice plugin.

Sep 7, 2010

Strange java.lang.NoClassDefFoundError

In the beginning I was thinking this is a ClassNotFoundException, and spend many time on looking into my runtime classpath settings, compiling from outside Eclipse, but finally I realized it is not. It's some bug in my code. Here is the story:

The program is trying to decode UDP packets. I try to ping the server by simply echo some string to ncat, and the server failed immediately with a whole bunch of stack trace, and it always report java.lang.NoClassDefFoundError: Could not initialize class radiustool.protocol.Packet$Code, actually almost always report the error upon any packets received, except the first time. Here is the stacktrace of the first time:

at radiustool.protocol.Packet$Codec.decode(
at radiustool.server.PacketDecoder.decode(
at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(
at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(
at java.util.concurrent.ThreadPoolExecutor$
Caused by: java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(
at java.lang.Integer.parseInt(
at java.lang.Integer.parseInt(
at radiustool.protocol.Attribute$Type.parseInt(
at radiustool.protocol.Packet$Code$1.setValidators(
at radiustool.protocol.Packet$Code.(
at radiustool.protocol.Packet$Code.(
at radiustool.protocol.Packet$Code$1.(
at radiustool.protocol.Packet$Code.(
... 11 more

So here we have it, one stupid non-needed line in is the root cause. But wait, there are something wrong some where, isn't it? Why an uncaptured RuntimeException cause a NoClassDefFoundError? Can't we throw out exception in a constructor? Okay, let's do a simple test:

public class T1 {

private static class T2 {
public T2(int i) {
if (i%2 == 0) throw new RuntimeException();
System.out.println("T2 initialized with: " + i);

private static enum T3 {
A(0), B(1);

T3(int i) {
if (i % 2 == 0) throw new RuntimeException();
System.out.println("T3 initialized with: " + i);

public static void main(String[] args) {
try {
T2 t2 = new T2(0);
} catch (Exception e) {

try {
T2 t2 = new T2(1);
} catch (Exception e) {

try {
T3 t3 = T3.A;
} catch (Throwable e) {

try {
T3 t3 = T3.B;
} catch (Throwable e) {


And here is the output:

at T1$T2.(
at T1.main(
T2 initialized with: 1
at T1.main(
Caused by: java.lang.RuntimeException
at T1$T3.(
at T1$T3.(
... 1 more
java.lang.NoClassDefFoundError: Could not initialize class T1$T3
at T1.main(

So now everything is clear. it's okay for your to throw runtime exception in the constructor of a normal class, like T2 in the above code, there won't be NoClassDefFoundError the next time you refer to that class, but you need to be very careful in the constructor of a enum, if the system captures an exception in a constructor of an enum, you won't get that class anymore.

In conclusion, NEVER THROW EXCEPTION in the constructor of a enum!!!

Sep 2, 2010

Play-Morphia plugin

Just finish this new play plugin. It aims to seamlessly provide mongodb access to play application. Here are some features it provides which lack from the current play-mongo plugin:

* Compatible with play.db.Model framework
* Support Fixtures.load and CRUD module
* Smart ID field management. Yes you can choose Long type if you like it. You are also free to mark your own ID field
* Support "OR" relationship in query
* Automatic index management

An updated YABE sample is included in the distribution.

This plugin is published at

Jul 25, 2010

Enable syntax highlight in vim for scala

This blog gives the instruction on how to enable color syntax in vim for scala. However when I follow the instruction to operate on my windows box I found it works correctly for my cygwin vim application, but does not work for windows gvim installation. After a few search on google, I found the problem is the rtp(runtimepath) of the different vim instance is different. cygwin vim automatically add ~/.vim in rtp, which stores the files of scala syntax, while windows gvim does not do the work. So the solution becomes obvious: Adding following line into your .vimrc file makes sure ~/.vim always loaded into runtime path, even on windows version:

set rtp^=~/.vim

Mar 28, 2010

Play Excel Module

My second Module for Play! framework now published at

Mar 22, 2010


I have just released a Play! framework module called GreenScript at github.

This module help Play application developer to do javascript/css file dependency management and minizing.

There are mainly three parts in this module:

* a configuration file to define the dependencies of javascript and css files
* several javascript for loading configuration/maintaining dependencies and output javascript files (in compressed form if configured) in a sequence defined by the dependency
* two play template tags to declare javascript and css file in html templates

Mar 20, 2010


I've published scrolldicator (a javascript UI control) at github. And there is a video clip to show what scrolldicator is.

Mar 18, 2010

First bug report of pMask

Mr. Stephan report an error of pMask. He needs to duplicate form input element dynamically, and that happens after input elements are pMasked (initialized using new pMask()). Soon he found the duplicated input lost mask capability and calling to "new pMask()" again will cause malfunction of old inputs while new inputs get worked correctly.

This is fixed quickly. However i found there is a problem running pMask on IE 8 (should not be relevant to this bug). I have a extension to prototype Event object by using "Event.prototype.key() = function() {...}", this statement works fine in Firefox and Chrome, however it cann't pass in IE8. This naughty browser report error: "'Event.prototype' is null or not an object". I am looking for the solution of this problem.

Thinking about Software blog resumed

Now that i've settled down in Australia, it's time to resume this blog. ( is blocked in China, sorry).

About Me

My photo