« June 2006 »
SunMonTueWedThuFriSat
      
1
2
5
7
8
9
10
11
13
14
16
19
20
21
23
24
25
26
29
30
     
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 213

Powered by Roller Weblogger.
« Previous month (May 2006) | Main | Next month (Jul 2006) »
20060731 Monday July 31, 2006

JSR-223 script engine for AWK

Just added JSR-223 script engine for AWK. This is based on Jawk implementation. If you are interested, you can checkout the sources from https://scripting.dev.java.net! Jawk has nice Java support - like calling Java constructors, methods etc.



( Jul 31 2006, 03:48:24 PM IST ) Permalink Comments [1] del.icio.us | furl | simpy | slashdot | technorati | digg

20060728 Friday July 28, 2006

Thou shall know the .class file version!

It is easy to have more than on JDK or JRE version(in particular JRE -- because of browser plugin downloads!) in the same machine. If you compile your Java source(s) with a JDK version and run the same with with an earlier JDK/JRE version, you could get an error that looks like this:


Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version number in .class file

Now, how do I know what is the version of a .class file and what version of JDK I need to run the same? The section 4.1 of VM spec. edition 2 explains the "header" structure of every .class file:


ClassFile {
    	u4 magic;
    	u2 minor_version;
    	u2 major_version;
    	u2 constant_pool_count;
    	cp_info constant_pool[constant_pool_count-1];
    	u2 access_flags;
    	u2 this_class;
    	u2 super_class;
    	u2 interfaces_count;
    	u2 interfaces[interfaces_count];
    	u2 fields_count;
    	field_info fields[fields_count];
    	u2 methods_count;
    	method_info methods[methods_count];
    	u2 attributes_count;
    	attribute_info attributes[attributes_count];
    }

The magic of a .class file is 0xCAFEBABE. The following class takes a class file as input and prints the major, minor version of it and also prints minium JDK/JRE required to run the given class.

File: Version.java

import java.io.*; public class Version { public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java version <.class file>"); System.exit(1); } if (! new File(args[0]).exists()) { System.err.println(args[0] + " does not exist!"); System.exit(2); } DataInputStream dis = new DataInputStream( new FileInputStream(args[0])); int magic = dis.readInt(); if (magic != 0xcafebabe) { System.err.println(args[0] + " is not a .class file"); System.exit(3); } int minor = dis.readShort(); int major = dis.readShort(); System.out.println("class file version is " + major + "." + minor); String version = null; if (major < 48) { version = "1.3.1"; } else if (major == 48) { version = "1.4.2"; } else if (major == 49) { version = "1.5"; } else if (major == 50) { version = "6"; } else { version = "7"; } System.out.println("You need to use JDK " + version + " or above"); } }

For example, after compiling the above class with JDK 1.5 and running it against itself prints the following:

java -cp . Version Version.class
class file version is 49.0
You need to use JDK 1.5 or above



( Jul 28 2006, 07:52:22 PM IST ) Permalink Comments [5] del.icio.us | furl | simpy | slashdot | technorati | digg

Article on "scripting for the Java platform"

John O'Conner has written a nice article on scripting for the Java platform. This is a well written article with sample code. One minor thing: there was a change in javax.script.Invocable interface after the article was written/reviewed. You may have to change the downloaded code -- if you are working with Mustang build 91 or above.



( Jul 28 2006, 10:49:57 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060727 Thursday July 27, 2006

Attended GTLC, installed Solaris Nevada on Laptop and met friends..

I was in India Engineering Center, Bangalore for the last 3 days to attend the Global Technology Leadership Conference. Sun's Distinguished Engineers visited from the US. There were few Sun customers. And there were local tech. leads from Bangalore. It is good to know about various product offerings from Sun and to hear from the customers. I visited Banglore after quite some time (yes, I work from home @ Chennai). It is always a great pleasure to meet friends!

Solaris sustaining friends helped by installing Solaris Nevada on my Dell laptop - the trick was to install without disturbing the other OS in the laptop. Thanks to Venky T.V and friends! (sorry for not being exhaustive)

Met AppServer friends - Sahoo, Binod and Java sustaining friends (Kannan, Thilak...). We discussed many things - this is one thing that you miss with work-from-home - these informal face-to-face meetings/chat are great.



( Jul 27 2006, 12:19:29 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

AppleScript JSR-223 engine

Thomas Künneth has started a java.net project for AppleScript JSR-223 script engine - this project is hosted at https://jasconn.dev.java.net/



( Jul 27 2006, 11:51:24 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060722 Saturday July 22, 2006

More updates to scripting.dev.java.net

Recent updates to scripting.dev.java.net:

  1. Updated Scheme JSR-223 script engine to use the latest version (1.15.1) of SISC (Second Interpreter of Scheme Code) intepreter. SISC supports is a complete implementation of the language. The entire R5RS Scheme standard is supported, no exceptions - including continuations!
  2. Updated OGNL (Object Graph Navigation Language) JSR-223 script engine to use the latest version (2.6.7) of the implementation. This is (lightweight) expression language for getting and setting properties of Java objects. I like the BigInteger and BigDecimal literals and direct operator support on those types.
  3. Fixed Groovy JSR-223 script engine to give an illusion of single engine level scope for functions. Previously, it was not possible to define a Groovy "global" function in one ScriptEngine.eval() call and call the same in subsequent ScriptEngine.eval() calls. This is because internally, each eval'ed code is compiled as a separate ScriptXXX class. i.e., all global functions in the eval'ed code go into a class derived from Script class. To give an illusion of single engine level scope for "global" functions, we create a map of method closures from all ScriptXXX instances created and search there for global functions (using Groovy's MetaClass mechanism). With this change, the engine behaves as if there is a single global functions scope per ScriptEngine instance. Groovy's Meta Object Protocol (MOP) is really powerful indeed.



( Jul 22 2006, 10:09:47 AM IST ) Permalink Comments [2] del.icio.us | furl | simpy | slashdot | technorati | digg

20060718 Tuesday July 18, 2006

NetBeans scripting module at scripting.dev.java.net

Chuk-Munn Lee has written NetBeans scripting modules. These modules let you customize NetBeans using scripting. We've just checked this module into the scripting.dev.java.net project.



( Jul 18 2006, 11:17:17 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060717 Monday July 17, 2006

Binary downloads at scripting.dev.java.net

As you'd know, in the scripting.dev.java.net project JSR-223 script engines for various languages are developed and maintained.

We have recently added binary downloads (jsr223-engines.tar.gz and jsr223-engines.zip) at scripting.dev.java.net. You can download, gunzip/untar or unzip the binary. Note that this just contains JSR-223 engine implementations for various languages. You still need to download underlying opensource implementation (For example of Groovy, JRuby etc.) from the respective language sit. The URL for each language site is mentioned in the README.TXT file for each language.

Please note that the binaries at scripting.dev.java.net are built with the latest build of Mustang (build 91) and so won't work with earlier versions of JDK - (This is because class file version changes with Mustang)



( Jul 17 2006, 08:28:24 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060715 Saturday July 15, 2006

Recent changes in JSR-223

As you may know already, Mustang (Java SE 6) includes JSR-223: Scripting for the Java Platform API. There was a recent change (since Mustang build 91) in javax.script.Invocable interface. Previously, there were two invoke methods in this interface - one for calling script top-level or global functions from Java and another for calling methods on script object. These have been renamed to invokeFunction and invokeMethod respectively.

javax.script.Invocable interface used to have the following methods:

    // call script global function
    invoke(String name, Object...args)
    // call method on a script object
    invoke(Object this, String name, Object...args)

This results in a problem when invoking a function with String arguments. For example, the following call

    Object ret = engine.invoke("functionName", "arg1", "arg2", "arg3");

is ambiguous. javac cannot tell which invoke overload is being called. User gets an error that looks like:

    reference to invoke is ambiguous, both method invoke(java.lang.Object, 
java.lang.String,java.lang.Object...) in javax.script.Invocable and method 
invoke(java.lang.String,java.lang.Object...) in javax.script.Invocable match

Now, these methods have been renamed to

    // call a script global function
    invokeFunction(String name, Object...args)
    // call a method on a script object
    invokeMethod(Object this, String name, Object...args)

The JavaScript engine (co-bundled in Sun's Java SE 6 implementation) and the script engines maintained at http://scripting.dev.java.net have been fixed to track this interface change. If you are maintaining/implementing your own JSR-223 engine, please fix it for this change.

In addition to this, scripting.dev.java.net project has been updated to use
  1. Groovy version 1.6 JSR-06
  2. JRuby version 0.9.0
  3. to track recent changes with JSR-199 (Java compiler API) [for Java script engine]

If you are using http://phobos.dev.java.net, you may want to refer to Roberto Chinnici's blog entry titled Tracking JSR-223 Changes



( Jul 15 2006, 08:33:28 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060712 Wednesday July 12, 2006

Bitten by whitespace

I was making a jar file for testing something. I had given a manifest file and a set of classes by the following command line:


    jar cvfm myjar.jar mymanifest.mf *.class

When I used myjar.jar, the manifest entries I specified in my mymanifest.mf were not working as expected. I opened the jar and checked the added manifest.mf in the jar file -- it did not have attributes defined in mymanifest.mf in it! In fact, my manifest.mf had just one attribute!! It turned out that I was bitten by whitespace -- newline was missing at the end of the attribute. Apparently, manifest file spec. mandates newline at the end of attributes. jar tool did not complain about my manifest file :-( Moral of the story: beware of whitespaces!



( Jul 12 2006, 04:51:34 PM IST ) Permalink Comments [1] del.icio.us | furl | simpy | slashdot | technorati | digg

20060706 Thursday July 06, 2006

More JavaScript debugging tips (Mustang context)

This is continuation of my earlier post on the same topic.

  1. objects have prototypes

    This is just to remind that objects have a prototype object. JavaScript is prototype-delegation based language. If a property or method is not found in an object, it's prototype is searched. So, when you access obj.x, the property "x" may actually be in the prototype of object "obj" (or prototype of prototype and so on). An object's prototype is accessible by a special property of the name __proto__. Note that this is non-standard Rhino specific extension. Rhino allows you to change prototype by assigning to __proto__ property!

  2. scopes are objects

    One more similarity to Lisp! In Lisp, scopes are known as "environments". Scopes are nothing but a map of variable names to variable values. In JavaScript, scopes are objects whose property names are variable names. For example, this keyword in global/toplevel scope refers to the global object. You can walk all global variables by this function:

    
    
    function printGlobals() {
       for (var i in this) {
           println(i + ' = ' + this[i]);
       }
    }
    
    
    
    Scopes are organized in a parent-child chain. The local scope of a function has the global scope as it's parent. Local variable scope of a nested function has enclosing function's local scope as it's parent and so on. Scope objects are also referred as "variable objects" (i.e., object that keeps variables). The "next" link in this chain is accessible by the special property called __parent__. Note that this is non-standard Rhino specific extension. Rhino allows you to change parent by assigning to __parent__ property! In addition to functions and local functions, with statements also add an innermost scope to scope-chains.

    How can we get hold of the "local scope" object of a function? Note that a nested function's parent scope is the local scope of the enclosing function. So, we can introduce an anonymous local function (with no code) to get it's __parent__.

    
    
    function f() {
       var x = 10;
       // introduce an anonymous nested function just to get 
       // it's parent scope -- which is nothing but scope of
       // this function.
       var localScope = (function() {}).__parent__;
       println(x); // prints 10
       println(localScope.x); // prints 10 again!
    }
    
    
    
    With this knowledge we can write generic code to print all local variables of a function:
    
    var printLocals = "{ var _locals = (function(){}).__parent__;       " +
                      "  for (var _i in _locals) {                      " +
                      "     if (/_locals/(_i) || /_i/(_i)) continue;    " +
                      "     println(_i + '=' + _locals[_i].toSource()); " +
                      "  } " +
                      "}";
    
    
    function h() {
       var x = 32;
       var y = { x : 3 };
       // prints all locals (x, y in this function)
       eval(printLocals);
    }
    
    

    Note that I've used eval - I cannot define printLocals as a function -- because to access local scope object of given function (like h() above), I've to define an anonymous function inside the same function! So, I'm eval'ing a string to get hold of the same. But, printLocals is generic -- in the sense that you can eval it any of your function to print all locals of it. Note that although JavaScript is similar to Lisp, macros are not supported. I had to use eval to simulate macro expansion.

    If you combine the fact that scopes are objects and objects have prototypes, we have the following lookup rule for variables:

    1. get the innermost scope object
    2. look for property with the same name as that of the variable
    3. if not found - chase the prototype chain (till null __proto__ is found) and look for it
    4. if not found, then get parent scope and look for property there. (till null __parent__ is found)
    So, each variable lookup is potentially a 2-dimensional search!
  3. Handling Java Exceptions

    JavaScript exception handling involves try..catch statement. But, exceptions typically are JavaScript Error object or subtypes of it (but other types like string can also be thrown!). If you are getting a Java exception, that is also wrapped as a JavaScript Error object. Sometimes, you may want to get the exact Java exception thrown -- may be the Java method you called throws multiple exceptions and you may want to handle those differently. Rhino adds javaException property to Error objects -- this property is initialized if an Error object wraps around a Java exception.

    
    try {
        var obj = new java.lang.Object();
        obj.wait();
    } catch (e) {
        var exp = e.javaException;
        if (exp instanceof java.lang.IllegalMonitorStateException) {
            exp.printStackTrace();
        } else if (exp instanceof java.lang.InterruptedException) {
            // do something differently..
        } else {
            // something else!
        }
    }
    
    
  4. printStackTrace

    In Java debugging, we often use Throwable.printStackTrace() or Thread.dumpStack() to print stack trace. How about similar stack trace for JavaScript? It turns out that Rhino does support stack trace - with script file name, function name and line number!. Rhino adds rhinoException property to Error object. The printStackTrace method on this rhinoException include script functions, line numbers etc.

    File: test.js
    
    function f() {
      g();
    }
    
    function g() {  
      try {
         var c = undefined;
         c.toString();
      } catch (e) {
         e.rhinoException.printStackTrace();
      }
    }
    
    f();
    
    
    The above code prints something like:
    
    D:\>jrunscript  test.ps
    sun.org.mozilla.javascript.internal.EcmaError: TypeError: Cannot call method "toString" of undefined (p.ps#19)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3234)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3224)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.typeError(ScriptRuntime.java:3240)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.typeError2(ScriptRuntime.java:3259)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.undefCallError(ScriptRuntime.java:3278)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime.java:1968)
            at sun.org.mozilla.javascript.internal.Interpreter.interpretLoop(Interpreter.java:2931)
            at script.g(test.ps:19)
            at script.f(test.ps:2)
            at script(test.ps:27)
            at sun.org.mozilla.javascript.internal.Interpreter.interpret(Interpreter.java:2250)
            at sun.org.mozilla.javascript.internal.InterpretedFunction.call(InterpretedFunction.java:149)
            at sun.org.mozilla.javascript.internal.ContextFactory.doTopCall(ContextFactory.java:337)
            at sun.org.mozilla.javascript.internal.ScriptRuntime.doTopCall(ScriptRuntime.java:2757)
            at sun.org.mozilla.javascript.internal.InterpretedFunction.exec(InterpretedFunction.java:160)
            at sun.org.mozilla.javascript.internal.Context.evaluateReader(Context.java:1163)
            at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:106)
            at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:230)
            at com.sun.tools.script.shell.Main.evaluateReader(Main.java:314)
            at com.sun.tools.script.shell.Main.evaluateStream(Main.java:350)
            at com.sun.tools.script.shell.Main.processSource(Main.java:267)
            at com.sun.tools.script.shell.Main.access$100(Main.java:19)
            at com.sun.tools.script.shell.Main$2.run(Main.java:182)
            at com.sun.tools.script.shell.Main.main(Main.java:30)
    
    Note that the red lines above include script function, file name and line number. With this you can write a generic printStackTrace function as
    
    function printStackTrace(exp) {    
        if (exp == undefined) {
            try {
                exp.toString();
            } catch (e) {
                exp = e;
            }
        }
        // note that user could have caught some other
        // "exception"- may be even a string or number -
        // and passed the same as argument. Also, check for
        // rhinoException property before using it
        if (exp instanceof Error && 
            exp.rhinoException != undefined) {
            exp.rhinoException.printStackTrace();
        }
    }
    
    

    You can call above function whereever you want script stack trace - much like java.lang.Thread.dumpStack() call. You can get fancier output by getting the stack trace into a string and then filtering it to print only the lines that begin with at script -- so that you can view only the script frames in the trace. That is left an exercise to the reader :-) [hint: use printStackTrace that accepts java.io.PrintWriter]



( Jul 06 2006, 01:21:06 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060704 Tuesday July 04, 2006

JavaScript debugging tips (for Mustang context)

Mustang (Java SE 6) is co-bundled with Mozilla Rhino based JavaScript engine as an example implementation for javax.script API.

There are 3 use cases within JDK

There is already an experimental web application environment that uses JavaScript - http://phobos.dev.java.net.

So, we may expect that JavaScript will be employed within the JDK context more often. How about debugging support for JavaScript engine in JDK context? For Firefox, there are atleast two debuggers (that I know of!):

  1. Venkman
  2. Firebug

Rhino comes with it's own debugger -- but in Mustang, Rhino's tools are not included. Also, javax.script API does not include debugger API (yet?). For Rhino in Mustang, we have to resort to other ways to debug scripts including good old println/printf style. Few debugging tips and tricks are here...

  1. Use jrunscript in interactive mode for debugging.

    You can use load function to load your script files (or URLs). In the interactive mode, you can call specific script functions or evaluate various expressions.

  2. print or alert debugging!

    Use good old printf/System.out.println/alert/echo style debugging! In Mustang Java, there are built-in print and println functions always defined. If you have scripts that use alert, you can consider defining something like this:

    
       // define alert to be same as println function
       var alert = println;
    
    
    Note that 'print' and 'println' functions print the message to output writer configured in the script context (recall that "context" is a pre-defined variable initialized with the current ScriptContext object). If you configure different output writer (may be, the one that writes messages to a file or socket etc.), you can make all print/println messages to go there.

  3. Use Function.toSource() to view source code of various functions.

    
    // viewing function sources in jrunscript prompt.
    
    // built-in functions are shown as "native code"
    // But, you can get arity (number of arguments)
    // of the function
    js> eval.toSource()js> eval.toSource()
    function eval() { [native code for eval, arity=1] }
    
    // for script functions toSource() shows full source
    js> function add(x, y) { return x + y }
    js> add.toSource()
    function add(x, y) {return x + y;}
    
    // for Java methods we get signature as part of "source"
    js> var v = new java.util.Date()
    js> v.getDay.toSource()
    function getDay() {/*
    int getDay()
    */}
    
    // for overloaded Java methods, toSource() shows signatures
    // for all overloads
    js> var out = java.lang.System.out
    js> out.println.toSource()
    function println() {/*
    void println(boolean)
    void println(char)
    void println(int)
    void println()
    void println(long)
    void println(java.lang.Object)
    void println(java.lang.String)
    void println(char[])
    void println(double)
    void println(float)
    */}
    
    

  4. JavaScript object fields and array elements can be walked by
    
       for(var i in obj) { print(obj[i]); }
    
    
    like loop.

    I frequently print all fields of an object (or elements of array) this way. Note that you will get object's methods (which are function valued properties) as well. To filter these, you can use typeof operator. You can also filter properties using property name pattern/index.

  5. Use JavaScript's support for higher-order functions.

    JavaScript functions can be passed as arguments and returned as values. Functions can be called by apply or call functions. Functions are first-class values that can be stored in variables. You can use these to implement JavaScript AOP. You can use "interceptors" to print debug trace output. For eg. function entry/exit can be printed (along with arguments, if desired). For example, the following is a variation of JavaScript AOP referred in above link..

    
    
    var Aspects = new Object();
    
    // calls "before" interceptor function before calling function
    // name specified by fname. The function is expected to be a property
    // of object 'obj'
    Aspects.addBefore = function(obj, fname, before) {
        var oldFunc = obj[fname];
        var newFunc = function() {        
            return oldFunc.apply(this, before(arguments, oldFunc, this));
        };
        // store oldFunc for restore purpose...
        newFunc.oldFunc = oldFunc;
        obj[fname] = newFunc;
    };
    
    Aspects.restore = function(obj, fname) {
        obj[fname] = obj[fname].oldFunc;
    }
    
    // tracing function entry
    function traceEntry(args, oldFunc, thiz) {
        // print the name of the function
        print("entering " + oldFunc.name);
        // print arguments
        var str = "";
        for (var i = 0; i < args.length; i++) {
            str += args[i] + ", ";
        }
        print("arguments " + str);
        // return argument array - used by oldFunc.
        return args;
    }
    
    
    With the above code in a debug library (say "debug.js"), the client code can write something like:
    
    function add(x, y) { return x + y; }
    
    // just add two arguments
    add(3, 4);
    
    Aspect.addBefore(this, "add", traceEntry);
    // call add -- prints debug output on entry
    add(3, 4);
    
    // restore old "add" function without debug output
    Aspect.restore(this, "add");
    
    
  6. Tracking global variables: It is better to avoid globals as much as possible.

    Use objects instead. It is easy to accidentally create globals in JavaScript. For example,

    
    
    function f() {
       x = m(); // forgot 'var' before x, x is global!
       // rest of the code...
    }
    
    
    
    While it may be possible to spot "unwanted" globals by code inspection, we can do better than that. It is possible to check global variable assignments and accesses using javax.script.Bindings used for global variable storage.
    
    import javax.script.*;
    import java.io.*;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            // create a new ScriptEngineManager
            ScriptEngineManager m = new ScriptEngineManager();
            // get JavaScript engine instance
            ScriptEngine jsEngine = m.getEngineByName("javascript");
            // set a "debug" bindings for global variables
            jsEngine.setBindings(new DebugBindings(),  ScriptContext.ENGINE_SCOPE);
            // eval code from a java.io.Reader object.
            jsEngine.eval(new FileReader(args[0]));
        }
    }
    
    
    The DebugBindings class could look like
    
    
    // a simple Bindings implementation that prints debug output
    // whenever a variable is accessed or assigned.
    import javax.script.*;
    
    public class DebugBindings extends SimpleBindings {
      @Override public Object put(String name, Object value) {
          Object res = super.put(name, value);
          System.out.println("Global assign: " + name);
          return res;
      }
    
      @Override public Object get(Object key) {
          Object res = super.get(key);
          System.out.println("Global access: " + key);
          return res;
      }
    }
    
    
    When running the Test class with the following t.js script file,
    function h() {
       // global variable assign
       x = 32;
    }
    
    h();
    
    we get the following output..
    Global assign: context
    Global assign: print
    Global assign: println
    Global access: javax.script.filename
    Global assign: h
    Global access: h
    Global assign: x
    
    Note that debug output is printed for function "assignments" as well. Note that global functions are global variables with "function" value.

  7. Debugging JavaScript objects

    Because JavaScript is dynamically typed language, we can replace an object with any other object that "looks" like the "original". i.e., the replacement objects should just support same methods, properties -- but can do anything. (If it walks like a duck and quacks like a duck, it must be a duck). You can wrap actual object with a "debuggable" object (whose methods print debug/trace output) -- so long as debug wrapper objects supports same methods, properties. Usually, it is very easy to wrap an object with another object in JavaScript. But, if your object supports properties (a.k.a fields) it becomes tricky to wrap the same - for example, you may want to wrap XMLHttpRequest that has properties. But, you can use JSAdapter and "hook" all property or method access or assignments.



( Jul 04 2006, 06:49:49 PM IST ) Permalink Comments [2] del.icio.us | furl | simpy | slashdot | technorati | digg

20060703 Monday July 03, 2006

Not much to see in football, turn to the other!

Seeing both Brazil and Argentina exit (That too Argentina in a penalty shoot-out!), FIFA is over for me. I turned to the good old (the?) other sport -- 1-0 is way better than 0-0 (square turner in West Indies!!) - but could have been 2-0 or even 3-0!



( Jul 03 2006, 09:13:25 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Copyright (C) 2005, A. Sundararajan's Weblog