reset to working status
authorAlan Knowles <alan@akkbhome.com>
Tue, 6 Jul 2010 13:40:51 +0000 (21:40 +0800)
committerAlan Knowles <alan@akkbhome.com>
Tue, 6 Jul 2010 13:40:51 +0000 (21:40 +0800)
44 files changed:
Introspect/Base.js [new file with mode: 0644]
Introspect/Basic.js [new file with mode: 0644]
Introspect/Callback.js [new file with mode: 0644]
Introspect/Class.js [new file with mode: 0644]
Introspect/Constant.js [new file with mode: 0644]
Introspect/Enum.js [new file with mode: 0644]
Introspect/Field.js [new file with mode: 0644]
Introspect/Interface.js [new file with mode: 0644]
Introspect/Link.js [new file with mode: 0644]
Introspect/Method.js [new file with mode: 0644]
Introspect/NameSpace.js [new file with mode: 0644]
Introspect/Property.js [new file with mode: 0644]
Introspect/Signal.js [new file with mode: 0644]
Introspect/Struct.js [new file with mode: 0644]
Introspect/Union.js [new file with mode: 0644]
Introspect/extensions/xml.js [new file with mode: 0644]
JSDOC/BuildDocs.js [new file with mode: 0644]
JSDOC/CompressWhite.js [new file with mode: 0644]
JSDOC/DocComment.js [new file with mode: 0644]
JSDOC/DocTag.js [new file with mode: 0644]
JSDOC/Identifier.js [new file with mode: 0644]
JSDOC/Options.js [new file with mode: 0644]
JSDOC/Packer.js [new file with mode: 0644]
JSDOC/Parser.js [new file with mode: 0644]
JSDOC/PrettyPrint.js [new file with mode: 0644]
JSDOC/Scope.js [new file with mode: 0644]
JSDOC/ScopeParser.js [new file with mode: 0644]
JSDOC/Symbol.js [new file with mode: 0644]
JSDOC/SymbolSet.js [new file with mode: 0644]
JSDOC/Walker2.js [new file with mode: 0644]
JsTemplate/Link.js [new file with mode: 0644]
JsTemplate/Template.js [new file with mode: 0644]
console.js [new file with mode: 0644]
introspection-doc-generator.doap [new file with mode: 0644]
jsdocbuild.js [new file with mode: 0644]
templates/resources/default.css [new file with mode: 0755]
templates/resources/elbow-end.gif [new file with mode: 0644]
templates/resources/elbow-minus-nl.gif [new file with mode: 0644]
templates/resources/elbow-plus-nl.gif [new file with mode: 0755]
templates/resources/library.png [new file with mode: 0644]
templates/resources/library_gnome.css [new file with mode: 0755]
templates/resources/library_gnome_print.css [new file with mode: 0755]
templates/resources/page.js [new file with mode: 0755]
templates/resources/top-header-gradient.png [new file with mode: 0644]

diff --git a/Introspect/Base.js b/Introspect/Base.js
new file mode 100644 (file)
index 0000000..9876fb5
--- /dev/null
@@ -0,0 +1,172 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+//GObject = imports.gi.GObject;
+
+XObject = imports.XObject.XObject;
+console = imports.console.console;
+
+NameSpace = imports.NameSpace.NameSpace;
+Basic = imports.Basic.Basic;
+
+
+
+
+/**
+ * Base  types methods/interfaces/structs/unions etc.
+ */
+
+
+
+Base = XObject.define(
+   function(ns, name) {
+        // fake should not happen?
+        
+        
+        if (typeof(name) == 'undefined') {
+            var ar = ns.split('.');
+            ns = ar[0];
+            name = ar[1];
+        }
+        this.ns = ns;
+        this.name = name;
+        this.alias = ns + '.' + name;
+        //console.log("CREATE(Base) " + this.alias);
+        this._loaded = false;
+        
+        
+        // reset all of these..
+        this.signals = [];
+        this.methods = [];
+        this.constructors = [];
+        this.functions= [];
+       
+        this.values = []; // for enum;g;
+        this.constants = [];
+        
+        this.properties = [];
+        this.implementInterfaces = []; // obect - which interface it implements.
+        this.implementedBy = []; // interface - which object uses it.
+        this.extendsClasses = []; // what it extends...
+        this.childClasses = []; // what 
+         this.desc = NameSpace.doc(this.alias );
+        
+        
+        var gi = GI.IRepository.get_default();
+        var ver = gi.get_version(ns);
+        var pth = GI.IRepository.get_search_path ();
+        var gir_path = pth[0].replace(/lib\/girepository-1.0/, 'share\/gir-1.0');
+       //console.log(fn);
+        this.gir_file = gir_path + '/'+ ns + '-' + ver + '.gir';
+        this.gir_filename = ns + '-' + ver + '.gir';
+        
+        
+    }, 
+    Basic, 
+    {
+        titleType: 'Unknown',
+        name :  '',
+        ns : '',
+       
+        signals : [],
+        methods : [],
+        constructors : [],
+        functions: [],
+       
+        values : [], // for enum
+        constants : [],
+        
+        properties : [],
+        implementInterfaces : [], // obect - which interface it implements.
+        implementedBy : [], // interface - which object uses it.
+        extendsClasses : [], // what it extends...
+        childClasses : [], // what 
+        
+        
+        
+        
+        getBI : function()  {
+            
+            var gi = GI.IRepository.get_default();
+            return gi.find_by_name(this.ns, this.name);
+        },
+         // on, getwhat, simple list (name), variable to add to.
+        genericBuildList : function( onwhat, type, keylist, saveto)
+        {
+            
+            //console.log(this.alias +" - ADDING :" + type);
+            //if (this[saveto].length) {
+            //    Seed.print( "EROROR = it's alreayd loaded why?");
+                //throw "oops";
+            //   }
+            var bb = this.getBI();
+            var _this = this;
+           //console.log("ADD " + type[0].toUpperCase() + type.substring(1));
+            var clname = type[0].toUpperCase() + type.substring(1);
+            var cls = imports[clname][clname];
+            if (!cls) {
+                console.log("COULD NOT FIND Introspect: " + type[0].toUpperCase() + type.substring(1));
+               }
+                
+            var plural = type + 's';
+            plural = plural == 'propertys' ? 'properties' : plural;
+            
+            
+            for(var i =0; i < GI[onwhat + '_info_get_n_' + plural ](bb); i++) {            
+                var add= new cls(GI[onwhat + '_info_get_' + type ](bb,i), this, saveto, keylist);
+                //console.log("CLS :" + this.alias + " EL: " + add.name);
+            }
+             
+            
+        },
+        // loop through and add stuff from extends..
+        genericExtends :  function(  keylist,  saveto)   
+        {
+            // do not overlay gobject props or methods etc.
+            
+            if (!this.extendsClasses.length) {
+                return;
+            }
+            if (this.extendsClasses[0].alias == 'GObject.Object') {
+                return;
+            }
+                
+            
+            var _this = this;
+            
+            this.extendsClasses[0].load();
+            this.extendsClasses[0][saveto].map(function(prop) {
+                if (keylist.indexOf(prop.name) < 0) {
+                    _this[saveto].push(prop);
+                    keylist.push(prop.name);
+                }
+            },this);
+            
+        },
+        // loop through and add stuff from implements..
+        genericImplements :  function(  keylist,  saveto)   {
+        
+            var _this = this;
+            this.implementInterfaces.map(function(iface) {
+                
+                iface.load();
+                
+                iface[saveto].map( function(prop) {
+                    if (keylist.indexOf(prop.name) < 0) {
+                        _this[saveto].push(prop);
+                        keylist.push(prop.name);
+                    }
+                },this);
+                
+            }, this);
+            
+        },
+                
+            
+        
+});
+
+
diff --git a/Introspect/Basic.js b/Introspect/Basic.js
new file mode 100644 (file)
index 0000000..50f58b9
--- /dev/null
@@ -0,0 +1,148 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+//GObject = imports.gi.GObject;
+
+XObject = imports.XObject.XObject;
+console = imports.console.console;
+
+
+
+/**
+ * Base class for Properties, functions, methods etc.
+ */
+
+
+Basic = XObject.define(
+    function( ) {
+         // never called?
+    },
+    Object,
+    {
+        
+        typeToName : function (type_info) {
+            var ty = GI.type_tag_to_string( GI.type_info_get_tag(type_info));
+            
+            if ((ty == 'void') && GI.type_info_is_pointer(type_info)) {
+                return 'void*'; // it's a fake string?!?!!? - slightly naughty...
+            }
+            if (ty == 'array') {
+                // array of what!?!?
+                var param_type = GI.type_info_get_param_type (type_info, 0);
+                var atype = GI.type_info_get_tag(param_type);
+                if (atype == GI.ITypeTag.UINT8) {
+                    return 'utf8';
+                }
+                
+                            
+                return ty;
+            }
+            if (ty != 'interface') {
+                return ty;
+            }
+            var interface_info = GI.type_info_get_interface (type_info);       
+            var interface_type = GI.base_info_get_type (interface_info);
+            if (interface_type  == GI.IInfoType.CALLBACK) {
+                // callback.. 
+                var Callback = imports.Callback.Callback ;
+                var ret=  new Callback(interface_info, this, false, false);
+                ret.alias = GI.base_info_get_namespace(interface_info) + '.' + GI.base_info_get_name(interface_info);
+                return ret;
+                 
+                
+            }
+
+            return  GI.base_info_get_namespace(interface_info) + '.' + GI.base_info_get_name(interface_info);
+            
+        },
+        
+        directions : [ "in", "out"," inout"],
+        
+        argsToArrays : function(m,  returnArray) 
+        {
+            
+            var outIntoReturn = false;
+            if (returnArray && returnArray.length == 1 && returnArray[0].type == 'void') {
+                outIntoReturn = true;
+            }
+            
+            var outArg = {
+                name : 'out_values',
+                ns : '',
+                type : 'Object',
+                direction : 'out',
+                be_null :  true, // in theory..
+                desc : "Return Object, use an empty Object, and the properties will get set as follows",
+                properties : []
+            };
+            
+            var args = [];
+            var firstOut = -1;
+            for(var a_i  =0; a_i   < GI.callable_info_get_n_args(m); a_i++) {
+                var arg = GI.callable_info_get_arg(m, a_i);
+                
+                var direction = this.directions[GI.arg_info_get_direction(arg)];
+                
+                var add = {
+                    name : GI.base_info_get_name(arg),
+                    ns : GI.base_info_get_namespace(arg),
+                    type : this.typeToName(GI.arg_info_get_type(arg)),
+                    direction : direction,
+                    be_null :  GI.arg_info_may_be_null(arg) || GI.arg_info_is_optional(arg),
+                    desc : GI.base_info_get_attribute(arg, 'doc') || ''
+                };
+                
+                
+                add.alias = add.ns + '.' + add.name;
+                
+                if (direction == 'out') {
+                    firstOut = firstOut  > -1 ? firstOut : a_i;
+                    if (outIntoReturn) {
+                        returnArray.push(add);
+                    } else {
+                        outArg.properties.push(add);
+                    }
+                }
+                
+                
+                args.push(add);
+            }
+            
+            // drop all the 'out args from the end of args..
+            if (returnArray) {
+                    
+                while (true) {
+                    if (!args.length) {
+                        break;
+                    }
+                    var l = args.pop(); // drop!
+                    if (l.direction == 'out') {
+                        // got an out arg..
+                        continue;
+                    }
+                    args.push(l); // put it back in (it's not a out).
+                    break;
+                    
+                }
+            }
+            if (outArg.properties.length) {
+                // put the out arg in there...
+                if (firstOut >= args.length) {
+                    args.push(outArg);
+                } else {
+                    args[firstOut]  = outArg;
+                }
+            }
+            
+             
+            // remove void return....
+            
+            if (returnArray && returnArray.length > 1 && returnArray[0].type == 'void') {
+                returnArray.shift();
+            }
+            
+            return args;
+        }
+});
diff --git a/Introspect/Callback.js b/Introspect/Callback.js
new file mode 100644 (file)
index 0000000..d9a7318
--- /dev/null
@@ -0,0 +1,48 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+//GObject = imports.gi.GObject;
+
+XObject = imports.XObject.XObject;
+console = imports.console.console;
+
+
+NameSpace = imports.NameSpace.NameSpace;
+Basic = imports.Basic.Basic;
+
+
+
+Callback = XObject.define(
+    function(sig, memberOf, saveto, keylist) {
+
+        
+        var params = this.argsToArrays(sig);
+        // add a reference to self...
+        /*params.unshift({
+            name : 'self',
+            type : memberOf.alias,
+            direction : 'in',
+            be_null :  false
+                
+        });
+        */
+        
+        XObject.extend(this,{
+            name : GI.base_info_get_name(sig),
+            params : params,
+            //memberOf : memberOf.alias,
+            exceptions : [],
+            returns :   [ { type :  this.typeToName(GI.callable_info_get_return_type(sig)) } ]            
+            
+        });
+        this.desc =  NameSpace.doc(memberOf.alias + '.' + this.name);
+        //memberOf[saveto].push(this);
+        //keylist.push(this.name);
+        
+    },
+    Basic,
+    {}
+);
+
diff --git a/Introspect/Class.js b/Introspect/Class.js
new file mode 100644 (file)
index 0000000..dba5f90
--- /dev/null
@@ -0,0 +1,176 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+//GObject = imports.gi.GObject;
+XObject = imports.XObject.XObject;
+console = imports.console.console;
+NameSpace = imports.NameSpace.NameSpace;
+
+Base = imports.Base.Base;
+
+
+
+
+/**
+ * Class
+ */
+
+
+
+
+Class = XObject.define(
+    function(ns, name) {
+        Base.call(this, ns, name);
+        this.loadExtends();
+        this.loadImplements();
+        //console.log("CREATED(Class) " + this.alias);
+    },
+    Base, 
+    {
+        titleType : 'Class',
+        
+        loadExtends : function()
+        {
+            var bi = this.getBI();
+            
+            var pi = GI.object_info_get_parent(bi);
+            this.extendsClasses = [];
+            if (!pi) {
+                return;
+            }
+            this.parent = NameSpace.factory(
+                'Class',
+                GI.base_info_get_namespace(pi),
+                GI.base_info_get_name(pi)
+            );
+            
+            this.extendsClasses = [ this.parent ];
+            
+            
+            this.parent.extendsClasses.map(function(p) {
+                this.extendsClasses.push(p);
+            },this);
+            
+            
+            
+        },
+        loadImplements : function()
+        {
+            var bb = this.getBI();
+            this.implementInterfaces = [];
+            
+            var iflist = [];
+            for(var i =0; i < GI.object_info_get_n_interfaces(bb); i++) {
+               
+                var prop = GI.object_info_get_interface(bb,i);
+                 
+                
+                var iface = NameSpace.factory(
+                    'Interface', 
+                    GI.base_info_get_namespace(prop) , GI.base_info_get_name(prop)
+                );
+                
+                
+                if (iflist.indexOf(iface.alias) < 0) {
+                    //console.log("ADDING IFACE " + iface.alias);
+                    iflist.push(iface.alias);
+                    this.implementInterfaces.push(iface);
+                }
+            }
+            // ask the first of the parents.. - which will have it loaded already
+            if (this.extendsClasses.length) {
+                
+                //this.extendsClasses[0].loadImplements();
+                
+                this.extendsClasses[0].implementInterfaces.map( function(si) {
+                    
+                    if (iflist.indexOf(si.alias) < 0) {
+                        //console.log("From extends ("+ si.alias + ") IFACE " + si.alias);
+                        iflist.push(si.alias);
+                        this.implementInterfaces.push(si);
+                    }
+                },this);
+                
+            }
+            //console.dump(iflist);
+            if (this.alias == 'Atk.NoOpObject') {
+            //    throw "exut";
+               }
+           // console.dump(this.implementInterfaces);
+        },
+        
+        
+        
+        
+        load : function()
+        {
+            if (this._loaded) {
+                return; // already loaded..
+            }
+            
+            if (this.parent) { // load up parents first
+                this.parent.load();
+            }
+            this.implementInterfaces.map(function(iface) {
+                iface.load();
+            });
+            
+            
+            //console.log("load(Class) " + this.alias);
+            // my props..
+            var props = [];
+            this.genericBuildList('object', 'property', props, 'properties');
+            this.genericBuildList('object', 'field', props, 'properties');
+
+            this.genericExtends(  props, 'properties');    
+            this.genericImplements( props, 'properties');    
+           
+            var signals = [];
+            this.genericBuildList('object', 'signal', signals, 'signals');
+            this.genericExtends(  signals, 'signals');    
+            this.genericImplements( signals, 'signals');    
+            
+            
+            NameSpace.references[this.alias] = NameSpace.references[this.alias] || [];
+            if (this.alias == 'GObject.Object') {
+                this._loaded = true;
+                return;
+            }
+            
+            
+            this.constructors.push({
+                name : '', // not really...
+                params:   this.properties.length ?  [ { type :  'Object', be_null :  true,  name : 'properties' } ] : [],
+                returns :  [],
+                isConstructor : true,
+                isStatic : false,
+                memberOf : this.alias,
+                exceptions : [],
+                // in theory..
+                desc : ''
+            });
+            
+            
+            var methods = [];
+            this.genericBuildList('object', 'method', methods, 'methods');
+            // dont inherit functiosn or consturctors...
+            
+            this.genericExtends(  methods, 'methods');    
+            this.genericImplements( methods, 'methods');    
+            
+            
+            
+            //console.log("loaded(Class) " + this.alias);
+              
+            this._loaded  = true;
+        }
+         
+         
+        
+        
+        
+});
diff --git a/Introspect/Constant.js b/Introspect/Constant.js
new file mode 100644 (file)
index 0000000..bad3f6d
--- /dev/null
@@ -0,0 +1,54 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Basic        = imports.Basic.Basic;
+
+
+/**
+ * Constant
+ */
+
+
+Constant = XObject.define(
+    function(prop, memberOf, saveto, keylist) {
+          
+        this.name  =  GI.base_info_get_name(prop);
+        var tif    = GI.constant_info_get_type(prop);
+        var ty = GI.type_tag_to_string( GI.type_info_get_tag(tif));
+        this.type  = this.typeToName(GI.constant_info_get_type(prop));
+        
+        ///this.flags =  GI.property_info_get_flags(prop),
+        
+        
+        this.value= 'UNKNOWN';
+        
+        
+        if (ty != 'interface') {
+            
+            var argm = new GI.Argument();
+            GI.constant_info_get_value ( prop ,argm);
+            if (ty != 'utf8') {
+                this.value = argm.v_long;
+            } else {
+                this.value = argm.v_string;
+            }
+        } 
+        
+        this.desc = NameSpace.doc(memberOf.alias + '.' + this.name)
+        
+        memberOf[saveto].push(this);
+        keylist.push(this.name);
+    },
+    Basic,
+    { }
+);
diff --git a/Introspect/Enum.js b/Introspect/Enum.js
new file mode 100644 (file)
index 0000000..1dddc21
--- /dev/null
@@ -0,0 +1,59 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Base        = imports.Base.Base;
+
+  
+
+
+
+
+Enum = XObject.define(
+    function(ns, name) {
+        Base.call(this, ns, name);
+    },
+    Base, 
+    {
+        titleType: 'Enum',
+         _loaded : false,
+        load : function()
+        {
+            if (this._loaded) {
+                return; // already loaded..
+            }
+            
+            this.desc = NameSpace.doc(this.alias);
+            var bi = this.getBI();
+                 
+            for(var i =0; i < GI.enum_info_get_n_values(bi); i++) {
+               
+                var prop = GI.enum_info_get_value(bi,i);
+                 
+              
+                this.values.push({
+                    name :  GI.base_info_get_name(prop).toUpperCase() ,
+                    type :   GI.type_tag_to_string(GI.enum_info_get_storage_type(bi)),
+                    value:   GI.value_info_get_value(prop) ,
+                    memberOf : this.alias
+                });
+            }
+            
+            this._loaded = true;
+             
+             
+            
+            
+        }
+});
+
\ No newline at end of file
diff --git a/Introspect/Field.js b/Introspect/Field.js
new file mode 100644 (file)
index 0000000..ee59e3a
--- /dev/null
@@ -0,0 +1,35 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Basic        = imports.Basic.Basic;
+
+
+/**
+ * Field
+ */
+
+Field = XObject.define(
+    function(prop, memberOf, saveto, keylist) {
+          
+       this.name  =  GI.base_info_get_name(prop) ,
+        this.type  = this.typeToName(GI.field_info_get_type(prop)),
+        this.flags =  GI.field_info_get_flags(prop),
+        this.memberOf = memberOf.alias
+        memberOf[saveto].push(this);
+        keylist.push(this.name);
+
+    },
+    Basic,
+    {}
+);
diff --git a/Introspect/Interface.js b/Introspect/Interface.js
new file mode 100644 (file)
index 0000000..a83a5ac
--- /dev/null
@@ -0,0 +1,54 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Base        = imports.Base.Base;
+
+
+
+/**
+ * Interface
+ */
+
+Interface = XObject.define(
+    function(ns, name) {
+        Base.call(this, ns, name);
+       
+    },
+
+    Base, 
+    {
+         titleType: 'Interface',
+        _loaded : false,
+        load : function()
+        {
+            if (this._loaded) {
+                return; // already loaded..
+            }
+            // my props..
+            var props = [];
+            this.genericBuildList('interface', 'property', props, 'properties');
+           
+           
+            var signals = [];
+            this.genericBuildList('interface', 'signal', signals, 'signals');
+          
+            
+            var methods = [];
+            this.genericBuildList('interface', 'method', methods, 'methods');
+            
+            
+            NameSpace.ifaceList[this.alias] = NameSpace.ifaceList[this.alias] || [];
+            this.implementedBy = NameSpace.ifaceList[this.alias];
+            
+              
+           
+            this._loaded  = true;
+        },
+         
+
+});
diff --git a/Introspect/Link.js b/Introspect/Link.js
new file mode 100644 (file)
index 0000000..fb7d5a1
--- /dev/null
@@ -0,0 +1,386 @@
+//<script type="text/javascript">
+
+console = imports.console.console;
+
+XObject = imports.XObject.XObject
+
+
+/** Handle the creation of HTML links to documented symbols.
+       @constructor
+    * 
+    *  
+    * 
+*/
+
+Link = XObject.define(
+    function() {
+        this.alias = "";
+        this.src = "";
+        this.file = "";
+        this.text = "";
+        this.innerName = "";
+        this.classLink = false;
+        this.targetName = "";
+        
+        // statics..
+        Link.symbolsDir = Link.symbolsDir || '';
+        Link.base = Link.base || '';
+        Link.ext= Link.ext || '';
+        Link.srcDir= Link.srcDir || '';
+            
+        
+    },
+    Object,  {
+        
+        alias : "",
+        src : "",
+        file : "",
+        text : "",
+        innerName : "",
+        classLink : false,
+        targetName : "",
+        
+        
+        
+        toString : function() {
+            var linkString;
+            var thisLink = this;
+            
+            if (this.none) {
+                return 'none';
+            }
+            if (this.alias) {
+                
+                if (typeof(this.builtins[this.alias]) != 'undefined') {
+                    this.text = this.alias;
+                    return thisLink._makeExternLink(this.builtins[this.alias]);
+                }
+                
+                
+                return thisLink._makeSymbolLink(this.alias);
+                
+                /*
+                
+                linkString = this.alias.replace(/(^|[^a-z$0-9_#.:-])([|a-z$0-9_#.:-]+)($|[^a-z$0-9_#.:-])/i,
+                    function(match, prematch, symbolName, postmatch) {
+                        var symbolNames = symbolName.split("|");
+                        var links = [];
+                        for (var i = 0, l = symbolNames.length; i < l; i++) {
+                            thisLink.alias = symbolNames[i];
+                            links.push(thisLink._makeSymbolLink(symbolNames[i]));
+                        }
+                        return prematch+links.join("|")+postmatch;
+                    }
+                );
+                */
+            }
+            else if (this.extern) {
+                linkString = thisLink._makeExternLink(this.extern);
+            }
+            else if (this.src) {
+                linkString = thisLink._makeSrcLink(this.src);
+            }
+            else if (this.file) {
+                linkString = thisLink._makeFileLink(this.file);
+            }
+
+            return linkString;
+        },
+        
+        builtins : {
+            'Object' : 'https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Object',
+            //'Object...' : 'http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object',
+            'Array' : 'https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array',
+            'Function' : 'https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function',
+            'String' : 'https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/String',
+            'Number' : 'https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Number',
+            'Boolean' : 'https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Boolean',
+            'HTMLElement' : 'http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037'
+        },
+        
+        
+        toGnome: function(alias) 
+        {
+            this.file = "#";
+            var pr = alias.split('.');
+            var aa = alias;
+            var site = 'library.gnome.org';
+            var extra = '';
+            switch(pr[0]) {
+                case 'GIRepository':
+                   this.extern = 'http://live.gnome.org/GObjectIntrospection';
+                   aa = pr[0];
+                   break;
+                case 'Gio':   
+                case 'GLib':   
+                case 'GObject':   
+                    aa = pr.length > 1 ? 'G' + pr[1] : pr[0];
+                    break;
+                case 'GdkPixbuf':   
+                    aa = pr.length > 1 ? 'Gdk' + pr[1] : pr[0];
+                    break;
+                case 'GtkSource':   
+                    aa = pr.length > 1 ? pr[0] + pr[1] : 'GtkSourceView';
+                    break;
+                    
+                case 'Gst': 
+                    aa = pr.length > 1 ? pr[0] + pr[1] : 'GStreamer';
+                    break;
+                
+                case 'Pango':
+                    extra = ' GTK-Doc';
+                    break;
+                case 'GstController': 
+                case 'GstApp': 
+                case 'GstAudio': 
+                case 'GstBase': 
+                case 'GstCheck': 
+                case 'GstFft': 
+                case 'GstInterfaces': 
+                case 'GstNet': 
+                case 'GstNetbuffer': 
+                case 'GstPbutils': 
+                case 'GstRiff': 
+                case 'GstRtp': 
+                case 'GstRtsp': 
+                case 'GstSdp': 
+                case 'GstTag': 
+                case 'GstVideo': 
+                
+                    aa = pr.length > 1 ? 'Gst' + pr[1] : pr[0];
+                    break;
+                    
+                case 'Epiphany':     
+                    aa = pr.length > 1 ?  pr[1] : pr[0];
+                    break;
+                case 'WebKit':
+                    site = 'webkitgtk.org';
+                
+                default:
+                    
+                    aa = alias.replace('.', '');
+                    
+                    break;
+             
+            }
+            if (!this.extern) {
+                this.extern = 'http://www.google.com/search?hl=en&amp;' + 
+                        'q=site%3A' + site  + '+' + aa + extra +
+                        '&amp;btnI=I%27m+Feeling+Lucky&amp;meta=&amp;aq=f&amp;oq=';
+            }
+            
+            this.text =  aa;
+            return this;
+        },
+        
+        target : function(targetName) {
+            if (typeof(targetName) != 'undefined') this.targetName = targetName;
+            return this;
+        },
+        inner : function(inner) {
+            if (typeof(inner) != 'undefined') this.innerName = inner;
+            return this;
+        },
+        withText:  function(text) {
+            if (typeof(text) != 'undefined') this.text = text;
+            return this;
+        },
+        toSrc :function(filename) {
+            if (typeof(filename) != 'undefined') this.src = filename;
+            return this;
+        },
+        
+        toSymbolLong : function(alias)
+        {
+            this.show_full = true;
+            return this.toSymbol(alias)
+        },
+        toSymbol : function(alias) {
+            
+            
+            switch(alias) {
+                case 'boolean' : this.alias = 'Boolean'; return this;
+                case 'int' : this.alias = 'Number'; return this;
+                case 'uint' : this.alias = 'Number'; return this;
+                
+                case 'long' : this.alias = 'Number'; return this;
+                case 'ulong' : this.alias = 'Number'; return this;
+                
+                
+                case 'uint8' : this.alias = 'Number'; return this;
+                case 'int8' : this.alias = 'Number'; return this;
+                
+                case 'uint16' : this.alias = 'Number'; return this;
+                case 'uint16' : this.alias = 'Number'; return this;
+                
+                case 'int32' : this.alias = 'Number'; return this;
+                case 'uint32' : this.alias = 'Number'; return this;
+                
+                case 'uint64' : this.alias = 'Number'; return this;
+                case 'int64' : this.alias = 'Number'; return this;
+                
+                
+                case 'GType' : this.alias = 'Number'; return this;
+                case 'size' : this.alias = 'Number'; return this;
+                case 'ssize' : this.alias = 'Number'; return this;
+                
+                case 'float' : this.alias = 'Number'; return this;
+                case 'double' : this.alias = 'Number'; return this;
+                case 'time_t' : this.alias = 'Number'; return this;
+                // fixme - should find out more details..
+                case 'array' : this.alias = 'Array'; return this;
+                case 'gslist' : this.alias = 'Array'; return this;
+                case 'glist' : this.alias = 'Array'; return this; // homefully.
+                case 'ghash' : this.alias = 'Object'; return this; // homefully.
+                
+                
+                case 'error' : this.alias = 'Object'; return this; // homefully.
+                case 'filename' : this.alias = 'String'; return this; // hopefully..
+                case 'utf8' : this.alias = 'String'; return this;
+                
+                case 'void' : this.none = true; return this;
+                
+                
+            }
+            
+            
+            if (typeof(alias) != 'undefined') {
+                this.alias = new String(alias);
+            }
+            return this;
+        },
+        toClass : function(alias) {
+            this.classLink = true;
+            return this.toSymbol(alias);
+        },
+        toFile : function(file) {
+            if (typeof(file) != 'undefined') this.file = file;
+            return this;
+        },
+        
+        
+      
+
+        /** prefixed for hashes */
+
+
+        /** Appended to the front of relative link paths. */
+
+
+        symbolNameToLinkName : function(symbol) {
+            var linker = "";
+            if (symbol.isStatic) linker = ".";
+            else if (symbol.isInner) linker = "-";
+            
+            return linker+symbol.name;
+        },
+
+        
+
+
+        /** Create a link to a snother symbol. */
+        _makeSymbolLink :  function(alias) 
+        {
+            var target = '';
+            var txt = this.show_full ? alias : alias.split('.').pop();
+             return "<a href=\"./"+alias+".html\""+target+">"+txt+"</a>";    
+            
+            /*
+            // look for '/' in alias..
+            if (/\//.test(alias)) {
+                var bits = alias.split('/');
+                var ret = "";
+                for(var i=0; i < bits.length; i++) {
+                    if (i > 0) {
+                        ret +="/";
+                    }
+                    ret += this._makeSymbolLink(bits[i]);
+                }
+                return ret;
+                
+            }
+            
+            
+            */
+            
+            var linkBase = Link.base + Link.symbolsDir;
+            //var linkTo = Link.symbolSet.getSymbol(alias);
+            linkTo = "FIXME";
+            var linkPath;
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+            
+            // is it an internal link?
+            if (alias.charAt(0) == "#") {
+                linkPath = alias;
+                fullLinkPath = alias;
+            
+            // if there is no symbol by that name just return the name unaltered
+            } else if (!linkTo) {
+                
+                if (typeof(this.builtins[alias]) != 'undefined') {
+                    return "<a href=\""+ this.builtins[alias]+"\""+target+">"+alias+"</a>";
+                 }
+                
+                return this.text || alias;
+            
+            
+            // it's a symbol in another file
+            } else {
+
+                if (!linkTo.isConstructor && !linkTo.isNamespace) { // it's a method or property
+                    linkPath = escape(linkTo.memberOf) || "_global_";
+                    linkPath += Link.ext + "#" + this.symbolNameToLinkName(linkTo);
+                }
+                else {
+                    linkPath = escape(linkTo.alias);
+                    linkPath += Link.ext + (this.classLink? "":"#" +  "constructor");
+                }
+                //linkPath = linkBase + linkPath;
+                fullLinkPath = linkBase + linkPath;
+            }
+            
+            var linkText = this.text || alias;
+            
+            var link = {linkPath: linkPath, linkText: linkText, fullLinkPath: fullLinkPath};
+            
+            //if (typeof PluginManager != "undefined") {
+            //    JSDOC.PluginManager.run("onSymbolLink", link);
+            //}
+            
+            return "<a href=\""+link.fullLinkPath+"\""+target+">"+link.linkText+"</a>";
+        },
+
+
+        /** Create a link to a source file. */
+         _makeSrcLink : function(srcFilePath) {
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+                
+            // transform filepath into a filename
+            var srcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, "."); // was _
+            var lsrcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, ".");
+            var outFilePath = Link.base + Link.srcDir + srcFile.replace(/.js$/, '') + Link.ext;
+            
+            if (!this.text) this.text = FilePath.fileName(srcFilePath);
+            return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
+        },
+
+        /** Create a link to a source file. */
+         _makeFileLink : function(filePath) {
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+                
+            var outFilePath =  Link.base + filePath;
+
+            if (!this.text) this.text = filePath;
+            return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
+        },
+        
+        /** Create a link to a source file. */
+         _makeExternLink : function(filePath) {
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+                
+            if (!this.text) this.text = filePath;
+            return "<a href=\""+filePath+"\""+target+">"+this.text+"</a>";
+        }
+        
+});
\ No newline at end of file
diff --git a/Introspect/Method.js b/Introspect/Method.js
new file mode 100644 (file)
index 0000000..2c44879
--- /dev/null
@@ -0,0 +1,150 @@
+//<script type="text/javascript">
+
+GI      = imports.gi.GIRepository;
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Basic        = imports.Basic.Basic;
+
+  
+/**
+ * Methods, functions or consturctors
+ */
+
+
+
+
+Method = XObject.define(
+    function(m, memberOf, saveto, keylist) {
+        this.propertyType  = 'Method';
+        
+        var flags = GI.function_info_get_flags (m);
+        var n = GI.base_info_get_name(m);
+        var n_original = n + '';
+        // posibly add: sink, 
+        if (n.match(/_(ref|unref)$/) || n.match(/^(ref|unref|weakref|weakunref)$/)) {
+            return false; // skip these!
+        }
+        
+        if (n == 'new') {
+            n = 'c_new';
+        }
+
+        
+        var retval = [ { 
+                name : 0, 
+                type :  this.typeToName(GI.callable_info_get_return_type(m)),
+                desc : NameSpace.doc(memberOf.alias + '.' + n_original + '.return-value')
+        } ];
+        
+        
+        
+        var args = this.argsToArrays(m, retval);
+        
+        
+        if ((n == 'c_new') && !args.length && memberOf.constructors.length) {
+            
+            memberOf.constructors[0].doc = NameSpace.doc(memberOf.alias + '.' + n_original);
+            
+            return false; // skip.
+        }
+        
+
+        
+        
+        
+        //console.log(GI.base_info_get_name(m));
+       // console.dump(GI.base_info_get_attribute(m, 'doc') );
+       
+         // this is a bit messy, as we probably loose the doc's on new..
+       
+        
+        XObject.extend(this, {
+            name : n,
+            params: args,
+            returns :  retval,
+            isConstructor : flags & GI.IFunctionInfoFlags.IS_CONSTRUCTOR,
+            isStatic : !(flags & GI.IFunctionInfoFlags.IS_METHOD),
+            memberOf : memberOf.alias,
+            exceptions : [],
+            desc : NameSpace.doc(memberOf.alias + '.' + n_original)
+        });
+        // add descriptions to the arguments..
+        this.params.map(function(p) {
+            
+            
+            p.desc = NameSpace.doc(memberOf.alias + '.' + n_original + '.' + p.name);
+            //Seed.print(memberOf.alias + '.' + n_original + '.' + p.name + ':' +  p.desc);
+            
+        });
+        
+        
+            // collect references...
+        var addedto = [ memberOf.alias ]; // do not add to self...
+       
+         for(var i =0; i < args.length;i++) {
+            var ty = args[i].type;
+            if (typeof(ty) != 'string' || ty.indexOf('.') < 0) {
+                continue;
+            }
+            if (addedto.indexOf(ty) > -1) {
+                continue;
+            }
+            
+            
+            
+            NameSpace.references[ty] = NameSpace.references[ty] || [];
+            NameSpace.references[ty].push(this);
+            addedto.push(ty);
+        }
+        
+        
+         // decide what to add to...
+         
+        if (this.isConstructor) {
+            
+            if (this.name.match(/^new_/)) {
+                this.name = this.name.substring(4);
+            }
+            
+            
+            memberOf.constructors.push(this);
+            return;
+        }
+        // return values  = only applicable to non-constructors..
+        for(var i =0; i < retval.length;i++) {
+            var ty = retval[i].type;
+            if (typeof(ty) != 'string' || ty.indexOf('.') < 0) {
+                continue;
+            }
+            if (addedto.indexOf(ty) > -1) {
+                continue;
+            }
+            
+            
+            
+            NameSpace.references[ty] = NameSpace.references[ty] || [];
+            NameSpace.references[ty].push(this);
+            addedto.push(ty);
+        }
+        
+        
+        if (this.isStatic) {
+            
+            memberOf.functions.push(this);
+            return;
+        }
+            
+            
+        memberOf.methods.push(this);
+        keylist.push(this.name);
+            
+        
+            
+    },
+    Basic, 
+    { }
+);
\ No newline at end of file
diff --git a/Introspect/NameSpace.js b/Introspect/NameSpace.js
new file mode 100644 (file)
index 0000000..a169d1b
--- /dev/null
@@ -0,0 +1,293 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+GLib    = imports.gi.GLib;
+xml     = imports.libxml;
+
+
+XObject = imports.XObject.XObject;
+
+console = imports.console.console;
+
+
+NameSpace = {
+   
+    references : { }, 
+    
+    namespaces : function(ns) 
+    {
+        // this should be a class of it's own...
+        this.references[ns] = []; // technically not needed - but fills in files..
+        // get this from GI... (it's the path..)
+        var ret = [];
+       
+        function scanGir(dir) 
+        {
+            if (!GLib.file_test(dir, GLib.FileTest.EXISTS)) {
+                return;
+            }
+            var gdir = GLib.dir_open(dir,0);
+            
+            while (true) {
+                
+                var fn = gdir.read_name ? gdir.read_name () : GLib.dir_read_name(gdir);
+           //      console.log('trying ' +  fn);
+                if (!fn) {
+                    gdir.close ? gdir.close() : GLib.dir_close(gdir);
+                    return;;
+                }
+                if (!fn.match(/.typelib$/)) {
+                    continue;
+                }
+                var par = fn.split('-').shift();
+                 //console.log('trying ' +  par);
+                if (ret.indexOf(par) > -1) {
+                     continue;
+                }
+                ret.push(par);
+                
+                
+            } 
+        }
+        var gi = GI.IRepository.get_default();
+        var pth = GI.IRepository.get_search_path ();
+        
+        scanGir(pth[0]);
+        ret.sort();
+        console.dump(ret);
+        return ret;
+        
+    },
+        
+        
+    ns:  function(ns) {
+        var gi = GI.IRepository.get_default();
+        ret = {
+            titleType: 'Namespace',
+            ns: ns,
+            name : ns,
+            alias : ns,
+            objects : [],
+            functions : [],
+            enums : [],
+            structs: [],
+            constants : [],
+            unions : [],
+            
+            // so ns looks like class..
+          
+            extendsClasses : [], // what it extends...
+            childClasses : [], // what uses it..
+            properties : [],
+            constructors : [],
+            methods : [],
+            values : [], /// really constants.
+            signals : [],
+            interfaces: [],
+        };
+     
+        for (var i=0; i <  gi.get_n_infos (ns); i++ ) {
+            var info = gi.get_info (ns, i);
+            
+            var info_type = GI.base_info_get_type (info);
+            switch(info_type) {
+                case  GI.IInfoType.OBJECT:
+                    ret.objects.push(GI.base_info_get_name(info));
+                    this.clsGatherInterfaces(ns , GI.base_info_get_name(info));
+                    continue;
+                 case  GI.IInfoType.INTERFACE:
+                    ret.interfaces.push(GI.base_info_get_name(info));
+                    continue;
+                case  GI.IInfoType.FUNCTION:
+                    new imports.Method.Method(info, ret, 'functions', []);    
+                    continue;
+                
+                case  GI.IInfoType.CALLBACK:
+                   // new Introspect.Callback(info, ret, 'callbacks', []);
+                    continue;
+                
+                case  GI.IInfoType.ENUM:
+                case  GI.IInfoType.FLAGS:
+                    ret.enums.push(GI.base_info_get_name(info));
+                    continue;
+                case  GI.IInfoType.STRUCT:
+                    if (GI.struct_info_is_gtype_struct (info)) {
+                        continue;
+                    }
+
+                    ret.structs.push(GI.base_info_get_name(info));
+                    continue;
+                case  GI.IInfoType.UNION:
+                    ret.unions.push(GI.base_info_get_name(info));
+                    continue;
+                case  GI.IInfoType.CONSTANT:
+                    new imports.Constant.Constant(info, ret, 'values', []);
+                    
+                    continue;
+                
+                
+                default:
+                    continue;
+            }
+        }
+        
+                
+        var gi = GI.IRepository.get_default();
+        var ver = gi.get_version(ns);
+        var pth = GI.IRepository.get_search_path ();
+        var gir_path = pth[0].replace(/lib\/girepository-1.0/, 'share\/gir-1.0');
+       //console.log(fn);
+        ret.gir_file = gir_path + '/'+ ns + '-' + ver + '.gir';
+        ret.gir_filename = ns + '-' + ver + '.gir';
+        
+        //console.dump(this.ifaceList);
+        return ret;
+
+    },
+    
+  
+    // store all the interfaces, so we can show a list of them later...
+    // called when you list the namespace
+    clsGatherInterfaces : function(ns, cls)
+    {
+        var gi = GI.IRepository.get_default();
+        var bb = gi.find_by_name(ns, cls);
+        var fullname = ns+'.'+cls;
+        this.ifaceList = this.ifaceList || { };
+         
+        
+        for(var i =0; i < GI.object_info_get_n_interfaces(bb); i++) {
+           
+            var prop = GI.object_info_get_interface(bb,i);
+           
+            var add =  GI.base_info_get_namespace(prop) +'.' + GI.base_info_get_name(prop);
+            this.ifaceList[add] = this.ifaceList[add] || [];
+            if (this.ifaceList[add].indexOf(fullname) < 0) {
+                this.ifaceList[add].push(fullname);
+            }
+             
+        }
+        
+       
+        
+    },
+    
+           
+        
+   
+    doc : function(what) {
+        var ns = what.split('.').shift();
+        this.commentLoad(ns);
+        return typeof(this.comments[ns][what]) == 'undefined' ?  '' : this.comments[ns][what];
+        
+    },
+    
+    
+    
+    comments : {},
+    
+    commentLoad : function(ns)
+    {
+        
+        if (typeof(this.comments[ns]) != 'undefined') {
+            return;
+        }
+        
+        console.log("LOAD DOCS: " + ns);
+        var gi = GI.IRepository.get_default();
+        var ver = gi.get_version(ns);
+        if (!ver) {
+            this.comments[ns] = {};
+            return;
+        }
+        var ret = { };
+        
+        // no idea why this is broken on my build system.
+        var  getAttribute = function(n, name){
+            var properties = n.properties;
+            while (properties){
+                if (properties.name == name)
+                    return properties.children.content;
+                properties = properties.next
+            }
+            return null;
+        }
+                
+        
+        function walk (element, path) {
+            
+            
+            if (!element) {
+                return;
+            }
+            
+            var n =  getAttribute(element, 'name') ;
+            //console.log("WALK" + n);
+            if (element.name == 'signal') {
+                path += '.signal';
+            }
+            
+            if (n) {
+                path += path.length ? '.' : '';
+                path += n;
+            }
+            if (element.name == 'return-value') {
+                path += '.return-value';
+            }
+            
+            var d =   getAttribute(element,'doc');
+            if (d) {
+             //   Seed.print(path + ':' + d);
+                ret[path] = d;
+            }
+            
+            var child = element.children;
+
+            while (child){
+                //console.log(child.tag);
+                if (child.type == "element"){
+                    walk (child, path);
+                }
+                child = child.next;
+            }
+        }
+        
+        var pth = GI.IRepository.get_search_path ();
+        
+        
+        var gir_path = pth[0].replace(/lib\/girepository-1.0/, 'share\/gir-1.0');
+       
+        
+        //console.log(fn);
+        var  fn = gir_path + '/'+ ns + '-' + ver + '.gir';
+       // console.log(fn);
+        
+        if (!GLib.file_test(fn, GLib.FileTest.EXISTS)) {
+            console.log('missing docc file ' + fn);
+            this.comments[ns] = {};
+            
+            return;
+        }
+        var doc = xml.parseFile(fn);
+        //console.log("xmldoc?" + doc);
+        walk (doc.root, '');
+        //console.dump(ret);
+        this.comments[ns] = ret;
+
+    },
+    registry : { },
+    factory : function(type, ns, name) {
+        if (typeof (this.registry[ns +'.' + name]) == 'undefined') {
+            this.registry[ns +'.' + name] = new imports[type][type](ns,name);
+            this.registry[ns +'.' + name].load();
+        }
+        
+        return this.registry[ns +'.' + name];
+    }
+        
+};
+
+
+
diff --git a/Introspect/Property.js b/Introspect/Property.js
new file mode 100644 (file)
index 0000000..832152f
--- /dev/null
@@ -0,0 +1,41 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Basic        = imports.Basic.Basic;
+
+   
+
+
+/**
+ * Property
+ */
+
+Property = XObject.define(
+    function(prop, memberOf, saveto, keylist) {
+        this.propertyType = 'Property';
+        var n_original = GI.base_info_get_name(prop);
+        this.name  =  n_original.replace(/\-/g, '_') ,
+        this.type  = this.typeToName(GI.property_info_get_type(prop)),
+        this.flags =  GI.property_info_get_flags(prop),
+        this.memberOf = memberOf.alias
+        memberOf[saveto].push(this);
+        keylist.push(this.name);
+        this.desc = NameSpace.doc(this.memberOf + '.' + n_original);
+        
+
+        if (typeof(this.type) == 'string' && this.type.indexOf('.') > -1) {
+        
+            NameSpace.references[this.type] = NameSpace.references[this.type] || [];
+            NameSpace.references[this.type].push(this);
+        }
+        
+    },
+    Basic
+);
diff --git a/Introspect/Signal.js b/Introspect/Signal.js
new file mode 100644 (file)
index 0000000..9524512
--- /dev/null
@@ -0,0 +1,68 @@
+//<script type="text/javascript">
+//Gtk = imports.gi.Gtk;
+GI      = imports.gi.GIRepository;
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Basic        = imports.Basic.Basic;
+
+  
+
+Signal = XObject.define(
+    function(sig, memberOf, saveto, keylist) {
+
+        this.propertyType  = 'Signal';
+        
+        var params = this.argsToArrays(sig);
+        // add a reference to self...
+        params.unshift({
+            name : 'self',
+            type : memberOf.alias,
+            direction : 'in',
+            be_null :  false
+                
+        });
+        var n_original  = GI.base_info_get_name(sig);
+        
+        XObject.extend(this,{
+            name : n_original.replace(/-/g,'_'),
+            params : params,
+            memberOf : memberOf.alias,
+            exceptions : [],
+            returns :   [ { type :  this.typeToName(GI.callable_info_get_return_type(sig)) } ],
+            desc : NameSpace.doc(memberOf.alias + '.signal.' + n_original)
+        });
+        memberOf[saveto].push(this);
+        keylist.push(this.name);
+        
+        var addedto = [ memberOf.alias ]; // do not add to self...
+       
+        for(var i =1; i < params.length;i++) {
+            var ty = params[i].type;
+            if (typeof(ty) != 'string' || ty.indexOf('.') < 0) {
+                continue;
+            }
+            if (addedto.indexOf(ty) > -1) {
+                continue;
+            }
+            
+            
+            
+            NameSpace.references[ty] = NameSpace.references[ty] || [];
+            NameSpace.references[ty].push(this);
+            addedto.push(ty);
+        }
+        
+        
+        
+        
+        
+    },
+    Basic
+);
+
+
+
diff --git a/Introspect/Struct.js b/Introspect/Struct.js
new file mode 100644 (file)
index 0000000..a3a72dc
--- /dev/null
@@ -0,0 +1,64 @@
+//<script type="text/javascript">
+
+GI      = imports.gi.GIRepository;
+
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+NameSpace   = imports.NameSpace.NameSpace;
+
+Base        = imports.Base.Base;
+
+/**
+ * Struct
+ */
+
+Struct = XObject.define(
+    function(ns, name) {
+        Base.call(this, ns, name);
+       
+    },
+
+    Base, 
+    {
+        titleType: 'Struct',
+        
+        _loaded : false,
+        load : function()
+        {
+            if (this._loaded) {
+                return; // already loaded..
+            }
+            // my props..
+            var props = [];
+            this.genericBuildList('struct', 'field', props, 'properties');
+            
+            var methods = [];
+            
+            
+            if (GI.struct_info_get_size (this.getBI()) > 0 ) {
+               
+            
+                
+                this.constructors.push({
+                    name : '',
+                    params: [],
+                    returns :  [],
+                    isConstructor : true,
+                    isStatic : false,
+                    memberOf : this.alias,
+                    exceptions : [],
+                    desc : ''
+                });
+            }
+            
+            this.genericBuildList('struct', 'method', methods, 'methods');
+              
+            this._loaded  = true;
+        },
+         
+
+});
\ No newline at end of file
diff --git a/Introspect/Union.js b/Introspect/Union.js
new file mode 100644 (file)
index 0000000..723a756
--- /dev/null
@@ -0,0 +1,58 @@
+//<script type="text/javascript">
+
+GI      = imports.gi.GIRepository;
+
+
+
+XObject     = imports.XObject.XObject;
+console     = imports.console.console;
+Base        = imports.Base.Base;
+
+  
+   
+
+/**
+ * Union
+ */
+Union = XObject.define(
+    function(ns, name) {
+        Base.call(this, ns, name);
+       
+    }, 
+    Base, 
+    {
+        titleType: 'Union',
+        _loaded : false,
+        load : function()
+        {
+            if (this._loaded) {
+                return; // already loaded..
+            }
+            // my props..
+            var props = [];
+            this.genericBuildList('union', 'field', props, 'properties');
+            
+            if (GI.union_info_get_size (this.getBI()) > 0 ) { 
+                
+                this.constructors.push({
+                    name : '',
+                    params: [],
+                    returns :  [],
+                    isConstructor : true,
+                    isStatic : false,
+                    memberOf : this.alias,
+                    exceptions : [],
+                    desc : ''
+                });
+            }
+            var methods = [];
+            this.genericBuildList('union', 'method', methods, 'methods');
+              
+            this._loaded  = true;
+        }
+         
+
+});
\ No newline at end of file
diff --git a/Introspect/extensions/xml.js b/Introspect/extensions/xml.js
new file mode 100644 (file)
index 0000000..f4249f2
--- /dev/null
@@ -0,0 +1,90 @@
+//<script type="text/javascript"> 
+/**
+* @class xml.XMLNode
+* Xml node 
+* @noconstructor
+* 
+* @cfg {String} name Name of Node ???
+* @cfg {XMLNode} children First child (use next property to iterate children
+* @cfg {XMLNode} parent Parent node of this one
+* @cfg {XMLNode} next Next sibling
+* @cfg {XMLNode} prev Previous sibling
+* @cfg {String} Text contents of Node
+* @cfg {XMLNode} last Last Sibling? or last child - FIXME
+* @cfg {String} type - Type of node : element, attribute, text
+* @cfg {XMLAttribute} properties First Attribute of node
+*/
+XMLNode = function() {}
+
+Roo.apply(XMLNode.prototype, {
+    
+});
+
+
+/**
+* @class xml.XMLDocument
+* Xml document 
+* @noconstructor
+* 
+* @cfg {String} name Name of Node ???
+* @cfg {XMLNode} children First child (use next property to iterate children
+* @cfg {XMLNode} parent Parent node of this one
+* @cfg {XMLNode} next Next sibling
+* @cfg {XMLNode} prev Previous sibling
+* @cfg {String} Text contents of Node
+* @cfg {XMLNode} last Last Sibling? or last child - FIXME
+* @cfg {String} type - Type of node : element, attribute, text
+* @cfg {XMLAttribute} properties First Attribute of node
+* @cfg {XMLNode} root Root node of document.
+*/
+
+
+XMLDocument  = function () { };
+
+Roo.extend(XMLDocument, XMLNode, {
+    root : { }, 
+});
+
+
+/**
+* Create a new xpath context ?
+* @param {Object} .....
+* @return {XMLNode} returns obj
+* @member XMLDocument xpathNewContext
+*/
+
+XMLDocument.xpathNewContext = function() { }
+
+
+
+
+   
+XMLAttribute  = function () { };
+   
+Roo.extend(XMLAttribute, XMLNode, {   
+
+});
+
+XMLXPathContext  = function() { };
+Roo.apply(XMLXPathContext.prototype, {
+    value : '',
+});
+
+XMLXPathContext.xpathEval = function () {} 
+XMLXPathContext.xpathRegisterNs = function () {} 
+
+
+XMLXPathObj = function() { };
+Roo.apply(XMLXPathObj.prototype, {
+    value : '',
+});
+
+
+
+parseFile = function () { }
+parseString = function () { }
+_nodeProto = { }
+   
+  
\ No newline at end of file
diff --git a/JSDOC/BuildDocs.js b/JSDOC/BuildDocs.js
new file mode 100644 (file)
index 0000000..ae3ecd1
--- /dev/null
@@ -0,0 +1,383 @@
+//<script type="text/javascript">
+/**
+       This is the main container for the JSDOC application.
+       @namespace
+*/
+Gio = imports.gi.Gio;
+
+XObject = imports.XObject.XObject;
+File = imports.File.File;
+
+Template = imports.JsTemplate.Template.Template;
+Link = imports.JsTemplate.Link.Link; // ?? fixme!??
+
+Parser   = imports.Parser.Parser;
+TextStream = imports.TextStream.TextStream;
+TokenReader = imports.TokenReader.TokenReader;
+TokenStream = imports.TokenStream.TokenStream;
+Symbol = imports.Symbol.Symbol;
+/******************    INCLUDES ARE ALL AT THE BOTTOM OF THIS FILE!!!!! *******************/
+
+// should not realy be here -- or anywhere...??
+
+
+Options = false; // refer to this everywhere!
+
+
+BuildDocs = {
+    
+    VERSION : "2.0.0",
+    
+    
+    srcFiles : [],
+    
+    
+    build : function (opts)
+    {
+        Options = opts; 
+        Options.init();
+        
+        Options.LOG.inform("JsDoc Toolkit main() running at "+new Date()+".");
+        //Options.LOG.inform("With options: ");
+        
+        if (Options.cacheDirectory.length && !File.isDirectory(Options.cacheDirectory)) {   
+            File.mkdir(Options.cacheDirectory)
+        }
+        
+        Options.srcFiles = this._getSrcFiles();
+        this._parseSrcFiles();
+        this.symbolSet = Parser.symbols;
+        
+        // this currently uses the concept of publish.js...
+        
+        this.publish();
+         
+        
+        
+    },
+    
+    
+    _getSrcFiles : function() 
+    {
+        this.srcFiles = [];
+        var _this = this;
+        var ext = ["js"];
+        if (Options.ext) {
+            ext = Options.ext.split(",").map(function($) {return $.toLowerCase()});
+        }
+        
+        for (var i = 0; i < Options.src.length; i++) {
+            // add to sourcefiles..
+            
+            File.list(Options.src[i] ).forEach(function($) {
+                if (Options['exclude-src'].indexOf($) > -1) {
+                    return;
+                }
+                var thisExt = $.split(".").pop().toLowerCase();
+                if (ext.indexOf(thisExt) < 0) {
+                    return;
+                }
+                _this.srcFiles.push(Options.src[i] + '/' + $);
+            });
+                
+        }
+        //Seed.print(JSON.stringify(this.srcFiles, null,4));Seed.quit();
+        return this.srcFiles;
+    },
+
+    _parseSrcFiles : function() 
+    {
+        Parser.init();
+        
+        for (var i = 0, l = this.srcFiles.length; i < l; i++) {
+            
+            var srcFile = this.srcFiles[i];
+            
+            
+            var cacheFile = Options.cacheDirectory + srcFile.replace(/\//g, '_') + ".cache";
+            
+            //println(cacheFile);
+            // disabled at present!@!!
+            
+            if (false && !Options.disablecache  && File.exists(cacheFile)) {
+                // check filetime?
+                
+                var c_mt = File.getTimes(cacheFile);
+                var o_mt = File.getTimes(srcFile);
+                //println(c_mt.toSource());
+               // println(o_mt.toSource());
+               
+                // this check does not appear to work according to the doc's - need to check it out.
+               
+                if (c_mt[0] > o_mt[0]) { // cached time  > original time!
+                    // use the cached mtimes..
+                    var syms =  JSON.parse(File.read(cacheFile));
+                    
+                    throw "Conversion of cache not done yet!";
+                    
+                    for (var sy in syms) {
+                        //println("ADD:" + sy );
+                       Parser.symbols.addSymbol(syms[sy]);
+                    }
+                    continue;
+                }
+            }
+            
+            var src = ''
+            try {
+                Options.LOG.inform("reading : " + srcFile);
+                src = File.read(srcFile);
+            }
+            catch(e) {
+                Options.LOG.warn("Can't read source file '"+srcFile+"': "+e.message);
+                continue;
+            }
+
+            var txs = new TextStream(src);
+            
+            var tr = new TokenReader({ keepComments : true, keepWhite : true });
+            
+            var ts = new TokenStream(tr.tokenize(txs));
+        
+            Parser.parse(ts, srcFile);
+              
+            //var outstr = JSON.stringify(
+            //    Parser.filesSymbols[srcFile]._index
+            //);
+            //File.write(cacheFile, outstr);
+             
+                
+    //         }
+        }
+        
+        
+        
+        Parser.finish();
+    },
+    
+     
+        
+    publish  : function() {
+        Options.LOG.inform("Publishing");
+         
+        // link!!!
+        
+        
+        Options.LOG.inform("Making directories");
+        if (!File.isDirectory(Options.target))
+            File.mkdir(Options.target);
+        if (!File.isDirectory(Options.target+"/symbols"))
+            File.mkdir(Options.target+"/symbols");
+        if (!File.isDirectory(Options.target+"/symbols/src"))
+            File.mkdir(Options.target+"/symbols/src");
+        
+        if (!File.isDirectory(Options.target +"/json")) {
+            File.mkdir(Options.target +"/json");
+        }
+        
+        Options.LOG.inform("Copying files from static: " +Options.templateDir);
+        // copy everything in 'static' into 
+        File.list(Options.templateDir + '/static').forEach(function (f) {
+            Options.LOG.inform("Copy " + Options.templateDir + '/static/' + f + ' to  ' + Options.target + '/' + f);
+            File.copyFile(Options.templateDir + '/static/' + f, Options.target + '/' + f,  Gio.FileCopyFlags.OVERWRITE);
+        });
+        
+        
+        Options.LOG.inform("Setting up templates");
+        // used to check the details of things being linked to
+        Link.symbolSet = this.symbolSet;
+        Link.base = "../";
+        
+        var classTemplate = new Template({
+             templateFile : Options.templateDir  + "/class.tmpl",
+             Link : Link
+        });
+        var classesTemplate = new Template({
+            templateFile : Options.templateDir +"/allclasses.tmpl",
+            Link : Link
+        });
+        var classesindexTemplate = new Template({
+            templateFile : Options.templateDir +"/index.tmpl",
+            Link : Link
+        });
+        var fileindexTemplate = new Template({   
+            templateFile : Options.templateDir +"/allfiles.tmpl",
+            Link: Link
+        });
+
+        
+        classTemplate.symbolSet = this.symbolSet;
+        
+        
+        function hasNoParent($) {
+            return ($.memberOf == "")
+        }
+        function isaFile($) {
+            return ($.is("FILE"))
+        }
+        function isaClass($) { 
+            return ($.is("CONSTRUCTOR") || $.isNamespace); 
+        }
+        
+        var symbols = this.symbolSet.toArray();
+        
+        var files = Options.srcFiles;
+        
+        for (var i = 0, l = files.length; i < l; i++) {
+            var file = files[i];
+            var targetDir = Options.target + "/symbols/src/";
+            this.makeSrcFile(file, targetDir);
+        }
+        
+        var classes = symbols.filter(isaClass).sort(makeSortby("alias"));
+         
+       var classesIndex = classesTemplate.process(classes); // kept in memory
+        
+        
+        
+        for (var i = 0, l = classes.length; i < l; i++) {
+            var symbol = classes[i];
+            var output = "";
+            
+            File.write(Options.target+"/symbols/" +symbol.alias+'.' + Options.publishExt ,
+                    classTemplate.process(symbol));
+            
+            print("write " + Options.target+"/symbols/" +symbol.alias+'.' + Options.publishExt);
+            
+            // dump out a 
+            
+            this.publishJSON(Options.target+"/json/",  symbol.alias+'.json', symbol)
+            
+            
+            
+        }
+        
+        // regenrate the index with different relative links
+        Link.base = "";
+        var classesIndex = classesTemplate.process(classes);
+        
+          
+        
+        File.write(Options.target +  "/index."+ Options.publishExt, 
+            classesindexTemplate.process(classes)
+        );
+        
+        // blank everything???? classesindexTemplate = classesIndex = classes = null;
+        
+        
+        var documentedFiles = symbols.filter(function ($) {
+            return ($.is("FILE"))
+        });
+        
+        var allFiles = [];
+        
+        for (var i = 0; i < files.length; i++) {
+            allFiles.push(new  Symbol(files[i], [], "FILE", new JSDOC.DocComment("/** */")));
+        }
+        
+        for (var i = 0; i < documentedFiles.length; i++) {
+            var offset = files.indexOf(documentedFiles[i].alias);
+            allFiles[offset] = documentedFiles[i];
+        }
+            
+        allFiles = allFiles.sort(makeSortby("name"));
+        File.write(Options.target , "/files."+Options.publishExt, 
+            fileindexTemplate.process(allFiles)
+        );
+        
+    },
+
+    publishJSON : function(file, data)
+    {
+        // what we need to output to be usefull...
+        // a) props..
+        var cfgProperties = [];
+        if (!data.comment.getTag('singleton').length) {
+            cfgProperties = data.configToArray();
+            cfgProperties = cfgProperties.sort(makeSortby("name"));
+            
+        }
+        var props = []; 
+        //println(cfgProperties.toSource());
+        var p ='';
+        for(var i =0; i < cfgProperties.length;i++) {
+            p = cfgProperties[i];
+            props.push( {
+                name : p.name,
+                type : p.type,
+                desc : p.desc,
+                memberOf : p.memberOf == data.alias ? '' : p.memberOf
+            });
+        }
+        
+         
+        var ownEvents = data.methods.filter( function(e){
+                return e.isEvent && !e.comment.getTag('hide').length;
+            }).sort(makeSortby("name"));
+             
+        
+        var events = [];
+        var m;
+        for(var i =0; i < ownEvents.length;i++) {
+            m = ownEvents[i];
+            events.push( {
+                name : m.name.substring(1),
+                sig : makeFuncSkel(m.params),
+                type : 'function',
+                desc : m.desc
+            });
+        }
+        //println(props.toSource());
+        // we need to output:
+        //classname => {
+        //    propname => 
+        //        type=>
+        //        desc=>
+        //    }
+
+        var ret = {
+            props : props,
+            events: events
+        };
+        File.write(file, JSON.stringify(ret, null, 2 ));
+        
+        
+        // b) methods
+        // c) events
+        
+        
+    },
+    makeSrcFile: function(sourceFile) 
+    {
+        
+        
+        name = sourceFile.substring(Options.baseDir.length+1);
+        name = name.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
+        
+        name = name.replace(/\:/g, "_"); //??
+        
+        Options.LOG.inform("Write Source file : " + Options.target+"/symbols/src/" + name);
+        var pretty = imports.PrettyPrint.toPretty(File.read(sourceFile));
+        File.write(Options.target+"/symbols/src/" + name, 
+            '<html><head>' +
+            '<title>' + sourceFile + '</title>' +
+            '<link rel="stylesheet" type="text/css" href="../../../highlight-js.css"/>' + 
+            '</head><body class="highlightpage">' +
+            pretty +
+            '</body></html>');
+    }
+     
+    
+};
+  
+
+
+
+
+
+
+
+
+
diff --git a/JSDOC/CompressWhite.js b/JSDOC/CompressWhite.js
new file mode 100644 (file)
index 0000000..6b08e16
--- /dev/null
@@ -0,0 +1,284 @@
+ // <script type="text/javascript">
+/**
+ * 
+ * pack a javascript file, and return a shorter version!
+ * 
+ * a bit picky at present with ; and crlf reading...
+ * @arg ts {TokenStream} 
+   @arg packer {Packer} 
+ */
+CompressWhite =  function (ts, packer)
+{
+    
+    ts.rewind();
+    //var str = File.read(fn);
+    var rep_var = 1;
+    
+    while (true) {
+        var tok = ts.next();
+        if (!tok) {
+            break;
+        }
+        if (tok.type == "WHIT") {
+            continue;
+            //if (tok._isDoc) {
+            //    continue;
+            //}
+            // just spaces, not \n!
+            //if (tok.data.indexOf("\n") < 0) {
+            //    continue;
+           // }
+            
+            
+        }
+        if (tok.data == "}")  {
+            
+            if (ts.lookTok(1).type == 'NAME' && ts.look(1,true).name == "NEWLINE") {
+            
+                ts.look(0).outData = ts.look(0).data+"\n";
+            }
+            // restore.. 
+            
+            continue;
+        }
+        // add semi-colon's where linebreaks are used... - not foolproof yet.!
+        if (tok.type == "NAME")  {
+            //var tokident = ts.look(-1).data + tok.data + ts.look(1).data +  ts.look(2).data;
+            // a = new function() {} 
+            if (ts.lookTok(1).data == '=' && ts.lookTok(2).name == 'NEW'  && 
+                ts.lookTok(3).name == 'FUNCTION') {
+                // freeze time.. 
+                var cu = ts.cursor;
+                
+                ts.balance("(");
+                
+                
+                ts.balance("{");
+                // if next is not ';' -> make it so...
+                
+                if (ts.lookTok(1).data != ';'  && ts.lookTok(1).data != '}' && ts.lookTok(1,true).name == "NEWLINE") {
+                    ts.look(0).outData = ts.cur().data +";";
+                }
+                // restore.. 
+                ts.cursor = cu;
+                continue;
+            }
+            // a = function() { ...
+               
+            if (ts.lookTok(1).data == '=' &&  ts.lookTok(2).name == "FUNCTION") {
+                // freeze time.. 
+                //println("got = function() ");
+                var cu = ts.cursor;
+                
+                ts.balance("(");
+                ts.balance("{");
+                // if next is not ';' -> make it so...
+                // although this var a=function(){},v,c; causes 
+                if (ts.lookTok(1).data != ';' && ts.lookTok(1).data != '}' && ts.lookTok(1,true).name == "NEWLINE") {
+                    ts.look(0).outData = ts.look(0).data+";";
+                }
+                // restore.. 
+                ts.cursor = cu;
+                continue;
+            }
+            // next item is a name..
+            if ((ts.lookTok(1).type == 'NAME' || ts.lookTok(1).type == 'KEYW' ) &&  ts.look(1,true).name == "NEWLINE") {
+                // preserve linebraek
+                ts.look(0).outData = ts.look(0).data+"\n";
+            }
+            // method call followed by name..
+            if (ts.lookTok(1).data == "(")  {
+                var cu = ts.cursor;
+                
+                ts.balance("(");
+                 // although this var a=function(){},v,c; causes 
+                
+                if (ts.lookTok(1).type == 'NAME' && ts.look(1,true).name == "NEWLINE") {
+                
+                    ts.look(0).outData = ts.look(0).data+"\n";
+                }
+                // restore.. 
+                ts.cursor = cu;
+                continue;
+            }
+            
+            
+            // function a () { ... };
+                /*
+            if (ts.look(-1).isTypeN(Script.TOKfunction) &&  ts.look(1).isTypeN(Script.TOKlparen)) {
+                // freeze time.. 
+                //println("got = function() ");
+                var cu = ts.cursor;
+                
+                ts.balance("lparen");
+                ts.balance("lbrace");
+                // if next is not ';' -> make it so...
+                // although this var a=function(){},v,c; causes 
+                if (!ts.look(1).isData(';') && !ts.look(1).isData('}') && ts.look(1,true).isLineBreak()) {
+                    ts.cur().outData = ts.cur().data+";";
+                }
+                // restore.. 
+                ts.cursor = cu;
+                continue;
+            }
+            */
+            
+            // a = { ....
+                
+            if (ts.lookTok(1).data == '=' &&  ts.lookTok(2).data == '{') {
+                // freeze time.. 
+                //println("----------*** 3 *** --------------");
+                var cu = ts.cursor;
+                
+                if (!ts.balance("{") ){
+                    throw "could not find end lbrace!!!";
+                }
+                // if next is not ';' -> make it so...
+
+                if (ts.lookTok(1).data != ';' && ts.lookTok(1).data != '}' && ts.look(1,true).name=="NEWLINE") {
+                    ts.look(0).outData = ts.look(0).data +";";
+                }
+                // restore.. 
+                ts.cursor = cu;
+                continue;
+            }
+            
+            // any more??
+        }
+        
+        
+        
+         
+        //println("got Token: " + tok.type);
+        
+        
+        
+        switch(tok.data.toUpperCase()) {
+            // things that need space appending
+            case "FUNCTION":
+            case "BREAK":
+            case "CONTINUE":
+                // if next item is a identifier..
+                if (ts.lookTok(1).type == "NAME" || ts.lookTok(1).data.match(/^[a-z]+$/i) ) { // as include is a keyword for us!!
+                   tok.outData =  tok.data + " ";
+                }
+                continue;
+                
+                
+            case "RETURN": // if next item is not a semi; (or }
+                if (ts.lookTok(1).data == ';' || ts.lookTok(1).data == '}') {
+                    continue;
+                }
+                tok.outData =  tok.data + " ";
+                
+                continue;
+            
+                
+            case "ELSE": // if next item is not a semi; (or }
+                if (!ts.lookTok(1).name == "IF") {
+                    continue;
+                }
+                
+                tok.outData =  tok.data + " ";
+                continue;
+            
+            case "++": // if previous was a plus or next is a + add a space..
+            case "--": // if previous was a - or next is a - add a space..
+            
+                var p = (tok.data == "--" ? '-' : '+'); 
+            
+                if (ts.lookTok(1).data == p) {
+                    tok.outData =  tok.data + " ";
+                }
+                if (ts.lookTok(-1).data == p) {
+                    tok.outData =  " " +  tok.data;
+                    
+                }
+                continue;
+            
+            case "IN": // before and after?? 
+            case "INSTANCEOF":
+                
+                tok.outData = " " + tok.data + " ";
+                continue;
+            
+            case "VAR": // always after..
+            case "NEW":
+            case "DELETE":
+            case "THROW":
+            case "CASE":
+            
+            case "VOID":
+                tok.outData =  tok.data + " ";
+                
+                continue
+                
+            case "TYPEOF": // what about typeof(
+                if (ts.lookTok(1).data != '(') {
+                    tok.outData =  tok.data + " ";
+                }
+                continue;
+             case ";":
+                //remove semicolon before brace -- 
+                //if(ts.look(1).isTypeN(Script.TOKrbrace)) {
+                //    tok.outData = '';
+               // }
+                continue;
+           
+            default:
+                continue;
+        }
+    }
+    
+    ts.rewind();
+    
+    // NOW OUTPUT THE THING.
+    //var f = new File(minfile, File.NEW);
+    
+    var out = '';
+    var outoff = 0;
+    out.length = ts.slen; // prealloc.
+    out = '';
+    while (true) {
+        var tok = ts.nextTok();
+           
+        if (!tok) {
+            break;
+        }
+        
+        
+        if (tok.type == "NAME"  && tok.identifier && tok.identifier.mungedValue && tok.identifier.mungedValue.length) {
+            //f.write(tok.identifier.mungedValue);
+            out += tok.identifier.mungedValue;
+            continue;
+        }
+        
+        // at this point we can apply a text translation kit...
+        
+        if ((tok.type == 'STRN') && (tok.name== 'DOUBLE_QUOTE')) {
+            if (packer && packer.stringHandler) {
+                out += packer.stringHandler(tok);
+                continue;
+            }
+        }
+     
+        out += tok.outData !== false ? tok.outData : tok.data;
+        
+        if ((tok.outData == ';') && (out.length - outoff > 255)) {
+            outoff = out.length;
+            out += "\n";
+        }
+    }
+    //f.close();
+    /*
+    // remove the last ';' !!!
+    if (out.substring(out.length-1) == ';') {
+        return out.substring(0,out.length-1);
+       }
+    */
+    return out;
+    
+}
+    
+    
\ No newline at end of file
diff --git a/JSDOC/DocComment.js b/JSDOC/DocComment.js
new file mode 100644 (file)
index 0000000..a21d863
--- /dev/null
@@ -0,0 +1,214 @@
+//<Script type="text/javascript">
+
+XObject = imports.XObject.XObject;
+
+DocTag = imports.DocTag.DocTag;
+
+/**
+ * Create a new DocComment. This takes a raw documentation comment,
+ * and wraps it in useful accessors.
+ * @class Represents a documentation comment object.
+ * 
+ */ 
+
+DocComment = XObject.define(
+
+    function(/**String*/comment) {
+        this.isUserComment = true;
+        this.src           = "";
+        this.meta          = "";
+        this.tagTexts      = [];
+        this.tags          = [];
+        if (typeof comment != "undefined") {
+            this.parse(comment);
+        }
+    }, 
+    Object, // extends
+    {
+             
+    
+        
+        /**
+        * @requires JSDOC.DocTag
+        */
+        parse : function(/**String*/comment) {
+            if (comment == "") {
+                comment = "/** @desc */";
+                this.isUserComment = false;
+                
+            }
+            
+            this.src = DocComment.unwrapComment(comment);
+            
+            //println(this.src);
+            
+            
+            this.meta = "";
+            if (this.src.indexOf("#") == 0) {
+                this.src.match(/#(.+[+-])([\s\S]*)$/);
+                if (RegExp.$1) this.meta = RegExp.$1;
+                if (RegExp.$2) this.src = RegExp.$2;
+            }
+            this.hasTags = true;
+            if (!/^\s*@\s*\S+/m.test(this.src)) {
+                this.isUserComment = false;
+                this.hasTags = false;
+                
+                //return;
+            }
+            this.fixDesc();
+            
+            //if (typeof JSDOC.PluginManager != "undefined") {
+            //    JSDOC.PluginManager.run("onDocCommentSrc", this);
+            //}
+            
+            this.src = DocComment.shared+"\n"+this.src;
+            this.tags = [];
+            this.tagTexts = [];
+            
+            
+           
+            this.tagTexts = 
+                this.src
+                .split(/(^|[\r\n])\s*@/)
+                .filter(function($){return $.match(/\S/)});
+            
+            //println(this.tagTexts.toSource());
+            // fix tagText
+            
+            
+            
+            /**
+                The tags found in the comment.
+                @type JSDOC.DocTag[]
+             */
+             
+            this.tags = this.tagTexts.map(function($){return new DocTag($)});
+            
+            //println(this.tags.toSource());
+            this.tagTexts = []; // we dont need to store this..
+            
+            
+            //if (typeof JSDOC.PluginManager != "undefined") {
+            //     JSDOC.PluginManager.run("onDocCommentTags", this);
+            //}
+        },
+         
+
+        /**
+            If no @desc tag is provided, this function will add it.
+         */
+        fixDesc : function() {
+            if (this.meta && this.meta != "@+") return;
+            
+            
+            
+            // does not have any @ lines..
+            // -- skip comments without @!!
+            if (!/^\s*@\s*\S+/.test(this.src)) {
+                this.src = "@desc "+this.src;
+                // TAGS that are not \n prefixed!! ...
+                this.src = this.src.replace(/@\s*type/g, '\n@type'); 
+            
+                return;
+            }
+            // kdludge for stuff...
+            //this.src = this.src.replace(/@\s*type/g, '\n@type'); 
+            
+            // only apply @desc fix to classes..
+            if (!/\s*@(class|event|property)/m.test(this.src) ) {
+                return;
+            }
+            // if no desc - add it on the first line that is not a @
+            var lines = this.src.split("\n");
+            var nsrc = '';
+            var gotf = false;
+            
+            for(var i =0; i < lines.length;i++) {
+                var line = lines[i];
+                if (gotf) {
+                    nsrc += line + "\n";
+                    continue;
+                }
+                if (/^\s*[@\s]/.test(line)) { // line with @
+                    nsrc += line + "\n";
+                    continue;
+                }
+                gotf = true;
+                nsrc += '@desc ' + line + "\n";
+                
+            }
+             
+            this.src = nsrc;
+            
+            
+            
+        },
+      
+    /**
+        Provides a printable version of the comment.
+        @type String
+     */
+        toString : function() {
+            return this.src;
+        },
+
+    /*~t
+        assert("testing JSDOC.DocComment#fixDesc");
+        var com = new JSDOC.DocComment();
+        com.src = "foo";
+        assertEqual(""+com, "foo", "stringifying a comment returns the unwrapped src.");
+    */
+
+    /**
+        Given the title of a tag, returns all tags that have that title.
+        @type JSDOC.DocTag[]
+     */
+     /*
+     
+        toQDump : function(t)
+        {
+            //println(t.toSource());
+            var r =  JSDOC.toQDump(t, 'JSDOC.DocComment.fromDump({', '})', {}); // send it an empty object..
+            //println(r);
+            return r;
+        } ,
+        */
+     
+        getTag : function(/**String*/tagTitle) {
+            return this.tags.filter(function($){return (typeof($['title']) != 'undefined') && ($.title == tagTitle)});
+        }
+        
+});
+
+
+/// static methods..
+
+XObject.extend(DocComment, 
+    {
+        
+        /**
+         * Used to store the currently shared tag text.
+         */
+        shared : "",
+        
+        /**
+         * Remove slash-star comment wrapper from a raw comment string.
+         *  @type String
+         */
+        unwrapComment : function(/**String*/comment) {
+            if (!comment) return "";
+            var unwrapped = comment.replace(/(^\/\*\*|\*\/$)/g, "").replace(/^\s*\* ?/gm, "");
+            return unwrapped;
+        },
+
+        fromDump : function(t)
+        {
+            var ns = new DocComment();
+            for (var i in t) {
+                ns[i] = t[i];
+            }
+            return ns;
+        }
+});
\ No newline at end of file
diff --git a/JSDOC/DocTag.js b/JSDOC/DocTag.js
new file mode 100644 (file)
index 0000000..9524f35
--- /dev/null
@@ -0,0 +1,180 @@
+//<script  type="text/javascript">
+XObject = imports.XObject.XObject;
+
+Options = imports.BuildDocs.Options;
+
+/**
+ * DocTag - represents a single A=b tag.
+ * @class DocTag
+ */
+DocTag = XObject.define(
+    function(src) {
+        this.title        = "";
+        this.type         = "";
+        this.name         = "";
+        this.isOptional   = false;
+        this.defaultValue = "";
+        this.desc         = "";
+        if (typeof src != "undefined") {
+            this.parse(src);
+        }
+    }, 
+    Object,
+    {
+        
+        title: '',
+        type: '',
+        name : '',
+        isOptional : false,
+        defaultValue : '',
+        desc : '',
+        /* qdump needed for cahcing?
+        toQDump  :function(t)
+        {
+            return JSDOC.toQDump(t, 'JSDOC.DocTag.fromDump({', '})', new JSDOC.DocTag());
+        } ,
+        */
+
+
+        /**
+            Populate the properties of this from the given tag src.
+            @param {string} src
+         */
+        parse : function(src) {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+
+            try {
+                src = this.nibbleTitle(src);
+                //if (JSDOC.PluginManager) {
+                //    JSDOC.PluginManager.run("onDocTagSynonym", this);
+               // }
+                
+                src = this.nibbleType(src);
+                
+                // only some tags are allowed to have names.
+                if (this.title == "param" || this.title == "property" || this.title == "cfg") { // @config is deprecated
+                    src = this.nibbleName(src);
+                }
+            }
+            catch(e) {
+                if (Options.LOG) Options.warn(e);
+                else throw e;
+            }
+            this.desc = src; // whatever is left
+            
+            // example tags need to have whitespace preserved
+            if (this.title != "example") this.desc = this.desc.trim();
+            
+            //if (JSDOC.PluginManager) {
+            //    JSDOC.PluginManager.run("onDocTag", this);
+            //}
+        },
+
+        /**
+            Automatically called when this is stringified.
+         */
+        toString : function() {
+            return this.desc;
+        },
+         
+
+        /**
+            Find and shift off the title of a tag.
+            @param {string} src
+            @return src
+         */
+        nibbleTitle : function(src) {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+            
+            var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
+
+            if (parts && parts[1]) this.title = parts[1];
+            if (parts && parts[2]) src = parts[2];
+            else src = "";
+            
+            return src;
+        },
+         
+        /**
+            Find and shift off the type of a tag.
+            @requires frame/String.js
+            @param {string} src
+            @return src
+         */
+        nibbleType : function(src) 
+        {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+            
+            if (src.match(/^\s*\{/)) {
+                var typeRange = src.balance("{", "}");
+                if (typeRange[1] == -1) {
+                    throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src;
+                }
+                this.type = src.substring(typeRange[0]+1, typeRange[1]).trim();
+                this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or |
+                src = src.substring(typeRange[1]+1);
+            }
+            
+            return src;
+        },
+         
+
+        /**
+            Find and shift off the name of a tag.
+            @requires frame/String.js
+            @param {string} src
+            @return src
+         */
+        nibbleName : function(src) {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+            
+            src = src.trim();
+            
+            // is optional?
+            if (src.charAt(0) == "[") {
+                var nameRange = src.balance("[", "]");
+                if (nameRange[1] == -1) {
+                    throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src;
+                }
+                this.name = src.substring(nameRange[0]+1, nameRange[1]).trim();
+                this.isOptional = true;
+                
+                src = src.substring(nameRange[1]+1);
+                
+                // has default value?
+                var nameAndValue = this.name.split("=");
+                if (nameAndValue.length) {
+                    this.name = nameAndValue.shift().trim();
+                    this.defaultValue = nameAndValue.join("=");
+                }
+            }
+            else {
+                var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/);
+                if (parts) {
+                    if (parts[1]) this.name = parts[1];
+                    if (parts[2]) src = parts[2].trim();
+                    else src = "";
+                }
+            }  
+
+            return src;
+        }
+});
+
+// cached support?
+DocTag.fromDump = function(t)
+{
+    var ns = new DocTag();
+    for (var i in t) {
+        if (typeof(ns[i]) == "undefined") {
+            println("ERR:no default for DocTag:"+ i);
+        }
+       ns[i] = t[i];
+    }
+    return ns;
+}
diff --git a/JSDOC/Identifier.js b/JSDOC/Identifier.js
new file mode 100644 (file)
index 0000000..7cc82bd
--- /dev/null
@@ -0,0 +1,25 @@
+//<Script type="text/javascript">
+
+/**
+ * @class  Identifier
+ * holds details about identifiers and their replacement values
+ * used by the packer..
+ * 
+ */
+
+
+function Identifier(name, scope) {
+   // print("NEW IDENT: " + name);
+    this.name = name;
+    this.scope = scope;
+    this.identifiers = {};
+    
+}
+Identifier.prototype = {
+    name: '',
+    refcount: 1,
+    mungedValue : '', // should be at least 1?!?!
+    scope : false,  // script of fn scope..
+    toMunge : true
+};
diff --git a/JSDOC/Options.js b/JSDOC/Options.js
new file mode 100644 (file)
index 0000000..971c098
--- /dev/null
@@ -0,0 +1,240 @@
+//<script type="text/javascript">
+/**
+ * Options management...
+ */
+XObject = imports.XObject.XObject;
+File = imports.File.File;
+
+Options = {
+
+    // generic stuff...
+    "--help"          : 'Show help',   // was h
+    "help": false,   // was h;se
+    
+    
+    // configurable settings.. - 
+    "usage" : "Usage seed jsdocbuild.js OPTIONS \n",
+    
+    
+    // options get defined like this..
+    "--src"           :  "source directory (either absolute - starts with "/" or relative " + 
+                        "- without, in which case it's added to baseDir",
+    "--exclude-src"       : 'Ex',   
+    "--baseDir"       :  'Base Directory (root directory of code)',
+    "--target"        :  'Target Directory (where html files go)',
+    "--cacheDirectory": 'Cached Files Directory',
+    "--conf"          : 'Read From a Configuration file',       // was c. - configuration file.. - parsed with JSON.parse
+    "--templateDir"      : 'Template Directory',   // was t.
+    // "recurse": false,   // was r. - not supported..
+    "--ext"           :  'Extension of code files to read (normally js)',   // was x.
+    "--publishExt"    : 'Extension of html files to write (normally html)',
+    //"private": '',   // was p
+    //"allfunctions": '',   // was a
+    //"encoding": '',   // was e.
+    //"nocode": '',  // was n
+    //"out": '',   // was o.
+    //"suppress": '',  // was s ??? used?
+    "--outputSource" : 'Output the Source code to symbols/src/* (boolean)',
+    //"testmode": '',  // was t
+    
+    "--verbose"       : 'Show verbose messages',   // was v
+    //"disablecache": '',   // was C -- not needed? - see if cacheDirectory was set..
+    //"define" : [],   // was D.
+    //"handler" : [],  // was H -- not supported..
+
+    
+    // and now the defaults.. (which type can be infered from..)
+    "src" : [],
+    "exclude-src" : [],
+    "baseDir" :  '',  // base directory - 
+    "target" : '',   // was d. ?? source directory (needed to put temporary files..)
+    "cacheDirectory" : '',
+    "conf" : '',       // was c. - configuration file.. - parsed with JSON.parse
+    "templateDir": '',   // was t.
+    // "recurse": false,   // was r. - not supported..
+    "ext": 'js',   // was x.
+    "publishExt" : 'html',
+    "private": '',   // was p
+    "allfunctions": '',   // was a
+    "encoding": '',   // was e.
+    "nocode": '',  // was n
+    "out": '',   // was o.
+    "suppress": '',  // was s ??? used?
+    "outputSource" : true,
+    "testmode": '',  // was t
+    
+    "verbose": '',   // was v
+    "disablecache": '',   // was C
+    "define" : [],   // was D.
+    "handler" : [],  // was H -- not supported..
+    LOG : {
+        warn : function(str) {
+            print("Warn: " +str );
+        },
+        inform : function(str) {
+            print("Inform: " +str );
+        },
+        close : function() { },
+        flush : function() { },
+        out: false,
+        warnings : [],
+        verbose : false    
+    },
+    init : function()
+    {
+        
+        if (this.help) {
+            this.showHelp();
+          
+        }
+        
+        // the reset of this is specific to JSDOC - and can not be moved to a generic handler..
+        
+         
+        this.LOG.verbose = this.verbose;
+        
+        if (!this.baseDir) { // should we set this to cwd?
+            throw {
+                name: "ArgumentError", 
+                message: "No baseDir specified" 
+            };
+        }
+        
+        // this is most likely to come from the command line..
+        if (this.conf) {
+            var conf = this.conf[0] == '/' ? this.conf : this.baseDir + '/' + this.conf;
+        
+            XObject.extend(this, JSON.parse(File.read(conf)));;
+        }
+        // help ?? -- usage..
+       
+        if (!this.src.length) {
+            throw {
+                name: "ArgumentError", 
+                message: "No source directories specified" 
+            };
+        }
+        // append full path to source directories.
+        var _this= this;
+        var src = this.src;
+        this.src = [];
+        src.forEach(function(v, i) {
+            if (!v.length || v[0] != '/') {
+                v = _this.baseDir + (v.length ?  '/' + v : '');
+            }
+            if (!File.isDirectory(v)) {
+                throw {
+                    name: "ArgumentError", 
+                    message: "invalid Source Directory : " +  v
+                };
+            }
+            _this.src.push(v);
+        });
+        
+        
+        if (!this.templateDir) {
+            throw {
+                name: "ArgumentError", 
+                message: "No templateDir Directory specified" 
+            };
+        }
+        if (this.templateDir[0] !='/') {
+            this.templateDir = this.baseDir + '/' + this.templateDir;
+        }
+        
+        
+        if (!this.target) {
+            throw {
+                name: "ArgumentError", 
+                message: "No directory specified" 
+            };
+        }
+      
+        
+        // should cacheDirectory be a subdirectory of target??
+        // if not set..
+        //if (!this.cacheDirectory) {
+        //    throw {
+        //        name: "ArgumentError", 
+        //        message: "No cacheDirectory specified" 
+        //    };
+        // }
+        
+    },
+    /** 
+     *  this might be nice as a standard bit of code..
+     */
+       
+    parseArgv : function() 
+    {
+        
+        var args = Array.prototype.slice.call(Seed.argv);
+        args.shift(); //seed
+        args.shift(); // pack.js
+        
+        for(var i =0; i < args.length;i++) {
+            if (args[i].substring(0,2) != '--') {
+                
+                throw {
+                    name: "ArgumentError", 
+                    message: "Unknown argument: " + args[i] 
+                };
+            }
+            var a = args[i].substring(2);
+            if (typeof(this[args[i]]) == 'undefined') {
+                throw {
+                    name: "ArgumentError", 
+                    message: "Unknown argument: " + args[i] 
+                };
+            }
+            // type!!?!?
+            if (typeof(this[a]) == 'string') {
+                this[a] = args[i+1];
+                i++;
+                continue;
+            }
+            if (typeof(this[a]) == 'boolean') {
+                if (['false', 'true'].indexOf(args[i+1]) < 0) {
+                    throw {
+                        name: "ArgumentError", 
+                        message: "Unknown value for : " + args[i] + ' : ' +  args[i+1] 
+                    };
+                }
+                this[a] = args[i+1] == 'true';
+                i++;
+                continue;
+            }
+            if (typeof(this[a]) == 'object') { // tecnically an array.
+                i++;
+                while(i < args.length)
+                {
+                    if (args[i].substring(0,2) != '--'){
+                        
+                        break;
+                    }
+                    this[a].push(args[i]);
+                }
+                i--;
+            }
+            throw {
+                name: "ArgumentError", 
+                message: "Do not know how to handle: " + a
+            };  
+        }
+        
+        
+    },
+    
+    
+    showHelp: function()
+    {
+        print(this.usage);
+        for(var i in this) {
+            if (i.substring(0,2) != '--') {
+                continue;
+            }
+            print( i + '  ARG  : ' + this[i]);
+            throw "DONE";
+        }
+    }
+}
\ No newline at end of file
diff --git a/JSDOC/Packer.js b/JSDOC/Packer.js
new file mode 100644 (file)
index 0000000..d04e630
--- /dev/null
@@ -0,0 +1,449 @@
+// <script type="text/javascript">
+XObject         = imports.XObject.XObject;
+File            = imports.File.File;
+
+TextStream      = imports['JSDOC/TextStream.js'].TextStream;
+TokenReader     = imports['JSDOC/TokenReader.js'].TokenReader;
+ScopeParser     = imports['JSDOC/ScopeParser.js'].ScopeParser;
+TokenStream     = imports['JSDOC/TokenStream.js'].TokenStream;
+CompressWhite   = imports['JSDOC/CompressWhite.js'].CompressWhite;
+
+GLib = imports.gi.GLib;
+/**
+ * @namespace JSDOC
+ * @class  Packer
+ * Create a new packer
+ * 
+ * Use with pack.js 
+ * 
+ * 
+ * Usage:
+ * <code>
+ *
+Packer = imports['JSDOC/Packer.js'].Packer;
+var x = new  Packer({
+    
+    files : [ "/location/of/file1.js", "/location/of/file2.js", ... ],
+    target : "/tmp/output.js",
+    debugTarget : "/tmp/output.debug.js", // merged file without compression.
+    translateJSON: "/tmp/translate.json",
+    
+    
+);
+x.packFiles(
+    "/location/of/temp_batch_dir", 
+    "/location/of/output-compacted-file.js",
+    "/location/of/output-debug-merged-file.js"
+);
+    
+ *</code> 
+ *
+ * Notes for improving compacting:
+ *  if you add a jsdoc comment 
+ * <code>
+ * /**
+ *   eval:var:avarname
+ *   eval:var:bvarname
+ *   ....
+ * </code>
+ * directly before an eval statement, it will compress all the code around the eval, 
+ * and not rename the variables 'avarname'
+ * 
+ * Dont try running this on a merged uncompressed large file - it's used to be horrifically slow. not sure about now..
+ * Best to use lot's of small classes, and use it to merge, as it will cache the compaction
+ * 
+ * 
+ * 
+ * Notes for translation
+ *  - translation relies on you using double quotes for strings if they need translating
+ *  - single quoted strings are ignored.
+ * 
+ * Generation of indexFiles
+ *   - translateIndex = the indexfile
+ * 
+ * 
+ * 
+ * 
+
+ */
+Packer = function(cfg)
+{
+    
+    XObject.extend(this, cfg);
+    
+    if (this.srcfile) {
+        this.loadSourceFile();
+    }
+    
+    if (!this.files) {
+        throw "No Files";
+    }
+    
+    
+    this.timer =  new Date() * 1;
+    this.packAll();
+    
+}
+Packer.prototype = {
+    /**
+     * @prop srcfiles {String} file containing a list of files/or classes to use.
+     */
+    srcfiles : false,
+    
+    /**
+     * @prop files {Array} list of files to compress (must be full path)
+     */
+    files : false,
+    /**
+     * @prop target {String} target to write files to - must be full path.
+     */
+    target : '',
+    /**
+     * @prop debugTarget {String} target to write files debug version to (uncompacted)- must be full path.
+     */
+    debugTarget : '', // merged file without compression.
+    /**
+     * @prop tmpDir {String} (optional) where to put the temporary files. 
+     *      if you set this, then files will not be cleaned up
+     */
+    tmpDir : '/tmp',
+    
+    translateJSON : '', // json based list of strings in all files.
+   
+    /**
+     * @prop cleanup {Boolean} (optional) clean up temp files after done - 
+     *    Defaults to false if you set tmpDir, otherwise true.
+     */
+    cleanup : true,  
+    
+    /**
+     * @prop prefix {String} (optional) prefix of directory to be stripped of when
+     *    Calculating md5 of filename 
+     */
+    prefix : '',  
+    out : '', // if no target is specified - then this will contain the result
+    
+    
+    loadSourceFile : function()
+    {
+        var lines = File.read(this.srcfile).split("\n");
+        var _this = this;
+        lines.forEach(function(f) {
+            
+            if (/^\s*\//.test(f) || !/[a-z]+/i.test(f)) { // skip comments..
+                return;
+            }
+            if (/\.js$/.test(f)) {
+                _this.files.push( f);
+                // js file..
+                return;
+            }
+            
+            //println("ADD"+ f.replace(/\./g, '/'));
+            var add = f.replace(/\./g, '/').replace(/\s+/g,'')+'.js';
+            if (_this.files.indexOf(f) > -1) {
+                return;
+            }
+            _this.files.push( add );
+            
+        })
+    },
+    
+    
+    packAll : function()  // do the packing (run from constructor)
+    {
+        
+        //this.transOrigFile= bpath + '/../lang.en.js'; // needs better naming...
+        //File.write(this.transfile, "");
+        if (this.target) {
+            File.write(this.target, "");
+        }
+        
+        if (this.debugTarget) {
+            File.write(this.debugTarget, "");
+        }
+        
+        for(var i=0; i < this.files.length; i++)  {
+            var file = this.files[i];
+            
+            print("reading " +file );
+            if (!File.isFile(file)) {
+                print("SKIP (is not a file) " + file);
+                continue;
+            }
+           
+            if (this.debugTarget) {
+                File.append(this.debugTarget, File.read(file));
+            }
+            // it's a good idea to check with 0 compression to see if the code can parse!!
+            
+            // debug file..
+            //File.append(dout, str +"\n"); 
+            
+       
+            
+            var minfile = this.tmpDir + '/' +file.replace(/\//g, '.');
+            
+            
+            // let's see if we have a min file already?
+            // this might happen if tmpDir is set .. 
+            if (true && File.exists(minfile)) {
+                var mt = File.mtime(minfile);
+                var ot = File.mtime(file);
+                print("compare : " + mt + "=>" + ot);
+                if (mt >= ot) {
+                    continue;
+                    /*
+                    // then the min'files time is > than original..
+                    var str = File.read(minfile);
+                    print("using MIN FILE  "+ minfile);
+                    if (str.length) {
+                        File.append(outpath, str + "\n");
+                    }
+                    
+                    continue;
+                    */
+                }
+                
+            }
+            
+            print("COMPRESSING ");
+            //var codeComp = pack(str, 10, 0, 0);
+            if (File.exists(minfile)) {
+                File.remove(minfile);
+            }
+            var str = File.read(file);
+            var str = this.pack(str, file, minfile);
+            if (str.length) {
+                File.write(minfile, str);
+            }
+            
+             
+          
+        }  
+        if (this.translateJSON) {
+            
+               
+            print("MERGING LANGUAGE");
+            var out = "if (typeof(_T) == 'undefined') { _T={};}\n"
+            if (this.target) {
+                File.write(this.target, out);
+            } else {
+                this.out += out;
+            }
+            
+            
+            
+            File.write(this.translateJSON, "");
+            for(var i=0; i < this.files.length; i++)  {
+                var file = this.files[i];
+                var transfile= this.tmpDir + '/' +file.replace(/\//g, '.') +'.lang.trans';
+                var transmd5 = this.tmpDir  + '/' +file.replace(/\//g, '.') +'.lang';
+                if (File.exists(transmd5)) {
+                    var str = File.read(transmd5);
+                    if (str.length) {
+                        if (this.target) {
+                            File.append(this.target, str + "\n");
+                        } else {
+                            this.out += str + "\n";
+                        }
+                        
+                    }
+                    if (this.cleanup) {
+                        File.remove(transmd5);
+                    }
+                }
+                if (File.exists(transfile)) {
+                    var str = File.read(transfile);
+                    if (str.length) {
+                        File.append(this.translateJSON, str);
+                    }
+                    if (this.cleanup) {
+                        File.remove(transfile);
+                    }
+                }
+                
+               
+            }
+        }
+        
+        print("MERGING SOURCE");
+        
+        for(var i=0; i < this.files.length; i++)  {
+            var file = this.files[i];
+            var minfile = this.tmpDir + '/' + file.replace(/\//g, '.');
+            
+            
+            if (!File.exists(minfile)) {
+                continue;
+            }
+            var str = File.read(minfile);
+            print("using MIN FILE  "+ minfile);
+            if (str.length) {
+                if (this.target) {
+                    File.append(this.target, str + "\n");   
+                } else {
+                    this.out += str + "\n";
+                }
+                
+            }
+            if (this.cleanup) {
+                File.remove(minfile);
+            }
+            
+        }
+        
+         
+    
+    
+    },
+    /**
+     * Core packing routine  for a file
+     * 
+     * @param str - str source text..
+     * @param fn - filename (for reference?)
+     * @param minfile - min file location...
+     * 
+     */
+    
+    pack : function (str,fn,minfile)
+    {
+    
+        var tr = new  TokenReader(  { keepDocs :true, keepWhite : true,  keepComments : true, sepIdents : true });
+        this.timerPrint("START" + fn);
+        
+        // we can load translation map here...
+        
+        var toks = tr.tokenize(new TextStream(str)); // dont merge xxx + . + yyyy etc.
+        
+        // at this point we can write a language file...
+        if (this.translateJSON) {
+            
+            this.writeTranslateFile(fn, minfile, toks);
+        }
+        
+        this.activeFile = fn;
+        
+        // and replace if we are generating a different language..
+        
+        this.timerPrint("Tokenized");
+        //return;//
+        var sp = new ScopeParser(new TokenStream(toks));
+        this.timerPrint("Converted to Parser");
+        sp.packer = this;
+        sp.buildSymbolTree();
+        this.timerPrint("Built Sym tree");
+        sp.mungeSymboltree();
+        this.timerPrint("Munged Sym tree");
+        print(sp.warnings.join("\n"));
+        var out = CompressWhite(sp.ts, this);
+        this.timerPrint("Compressed");
+        return out;
+        
+        
+         
+    },
+    
+    timerPrint: function (str) {
+        var ntime = new Date() * 1;
+        var tdif =  ntime -this.timer;
+        this.timer = ntime;
+        print('['+tdif+']'+str);
+    },
+    
+    /**
+     * 
+     * Translation concept...
+     * -> replace text strings with _T....
+     * -> this file will need inserting at the start of the application....
+     * -> we need to generate 2 files, 
+     * -> a reference used to do the translation, and the _T file..
+     * 
+     */
+    
+    writeTranslateFile : function(fn, minfile, toks) 
+    {
+        
+        var map = {};
+        var _this = this;
+        toks.forEach(function (t) {
+            if (t.type == 'STRN' && t.name == 'DOUBLE_QUOTE') {
+                var sval = t.data.substring(1,t.data.length-1);
+                var ffn = fn.substring(_this.prefix.length);
+                map[sval] = _this.md5(ffn + '-' + sval);
+            }
+        })
+        
+        var transfile = minfile + '.lang.trans';
+        var transmd5 = minfile + '.lang';
+        print("writeTranslateFile "  + transfile);
+        var i = 0;
+        var v = '';
+        if (File.exists(transfile)) {
+            File.remove(transfile);
+        }
+        if (File.exists(transmd5)) {
+            File.remove(transmd5);
+        }
+        for(v in map) { i++; break };
+        if (!i ) {
+            return; // no strings in file...
+        }
+        var ffn = fn.substring(this.prefix.length);
+         
+         
+        File.write(transfile, "\n'" + ffn  + "' : {");
+        var l = '';
+        var _tout = {}
+         
+        File.write(transmd5, '');
+        for(v in map) {
+            File.append(transfile, l + "\n\t \"" + v + '" : "' + v + '"');
+            l = ',';
+            // strings are raw... - as the where encoded to start with!!!
+            File.append(transmd5, '_T["' + this.md5(ffn + '-' + v) + '"]="'+v+"\";\n");
+        }
+        File.append(transfile, "\n},"); // always one trailing..
+        
+         
+    },
+    md5 : function (string)
+    {
+        
+        return GLib.compute_checksum_for_string(GLib.ChecksumType.MD5, string, string.length);
+        
+    },
+    stringHandler : function(tok)
+    {
+        //print("STRING HANDLER");
+       // callback when outputing compressed file, 
+       var data = tok.data;
+        if (!this.translateJSON) {
+         //   print("TURNED OFF");
+            return data;
+        }
+        if (tok.name == 'SINGLE_QUOTE') {
+            return data;
+        }
+        
+        var sval = data.substring(1,data.length-1);
+        // we do not clean up... quoting here!??!!?!?!?!?
+        
+        
+        // blank with tabs or spaces..
+        //if (!sval.replace(new RegExp("(\\\\n|\\\\t| )+",'g'), '').length) {
+       //     return tok.outData;
+       // }
+        
+        var sval = tok.data.substring(1,data.length-1);
+        var fn = this.activeFile.substring(this.prefix.length);
+        
+        
+        return '_T["' + this.md5(fn + '-' + sval) + '"]';
+        
+        
+    }
+    
+    
+};
diff --git a/JSDOC/Parser.js b/JSDOC/Parser.js
new file mode 100644 (file)
index 0000000..8b88a93
--- /dev/null
@@ -0,0 +1,190 @@
+//<script type="text/javascript">
+
+Walker2      = imports.Walker2.Walker2;
+Symbol      = imports.Symbol.Symbol;
+SymbolSet      = imports.SymbolSet.SymbolSet;
+DocComment  = imports.DocComment.DocComment;
+Options     = imports.BuildDocs.Options;
+/**
+ * Parser is a static  instance..
+ * 
+ * 
+ */
+Parser = {
+       conf: { 
+        loaded: false 
+    },
+    
+    walker : false, // will be JSDOC.Walker()
+    symbols : false, //will be JSDOC.SymbolSet()
+    
+    filesSymbols : { },
+    
+    /** 
+    * global init once 
+    * 
+    */
+         
+    init: function() {
+        if (this.conf.loaded) {
+            return;
+        }
+        print("init parser conf!?");
+        this.conf = {
+            loaded : true,
+            //ignoreCode:                 Options.n,
+            ignoreAnonymous:           true, // factory: true
+            treatUnderscoredAsPrivate: true, // factory: true
+            explain:                   false // factory: false
+        };
+         
+               this.symbols = new  SymbolSet();
+               //this.walker = new JSDOC.Walker();
+        //JSDOC.Parser.filesSymbols = {};
+       },
+
+
+
+    /**
+     * Parse a token stream.
+     * @param {JSDOC.TokenStream} token stream
+     * @param {String} filename 
+         
+     */
+    
+    
+    parse : function(ts, srcFile) 
+    {
+        this.init();
+        
+        
+        // not a nice way to set stuff...
+        
+        Symbol.srcFile = (srcFile || "");
+        DocComment.shared = ""; // shared comments don't cross file boundaries
+        
+       
+        
+        
+        
+        this.filesSymbols[Symbol.srcFile] = new SymbolSet();
+        
+        this.walker = new  Walker2(ts);
+        this.walker.buildSymbolTree()
+        //this.walker.walk(ts); // adds to our symbols
+       // throw "done sym tree";
+        
+        // filter symbols by option
+        for (p in this.symbols._index) {
+            var symbol = this.symbols.getSymbol(p);
+            
+            if (!symbol) continue;
+            
+            if (symbol.is("FILE") || symbol.is("GLOBAL")) {
+                continue;
+            }
+            //else if (!Options.a && !symbol.comment.isUserComment) {
+                //print("Deleting Symbols (no a / user comment): " + symbol.alias);
+                //this.symbols.deleteSymbol(symbol.alias);
+                //this.filesSymbols[Symbol.srcFile].deleteSymbol(symbol.alias);
+            //}
+            
+            if (/#$/.test(symbol.alias)) { // we don't document prototypes - this should not happen..
+                // rename the symbol ??
+                /*if (!this.symbols.getSymbol(symbol.alias.substring(0,symbol.alias.length-1))) {
+                    // rename it..
+                    print("Renaming Symbol (got  a #): " + symbol.alias);
+                    var n = '' + symbol.alias;
+                    this.symbols.renameSymbol( n ,n.substring(0,n-1));
+                    this.filesSymbols[Symbol.srcFile].renameSymbol( n ,n.substring(0,n-1));
+                    continue;
+                }
+                */
+                print("Deleting Symbols (got  a #): " + symbol.alias);
+                
+                this.symbols.deleteSymbol(symbol.alias);
+                this.filesSymbols[Symbol.srcFile].deleteSymbol(symbol.alias);
+            
+            }
+        }
+        //print(prettyDump(toQDump(this.filesSymbols[Symbol.srcFile]._index,'{','}')));
+        //print("AfterParse: " + this.symbols.keys().toSource().split(",").join(",\n   "));
+        return this.symbols.toArray();
+    },
+
+       
+       addSymbol: function(symbol) 
+    {
+         print("PARSER addSYMBOL : " + symbol.alias);
+        
+               // if a symbol alias is documented more than once the last one with the user docs wins
+               if (this.symbols.hasSymbol(symbol.alias)) {
+                       var oldSymbol = this.symbols.getSymbol(symbol.alias);
+            
+                       if (oldSymbol.comment.isUserComment && !oldSymbol.comment.hasTags) {
+                               if (symbol.comment.isUserComment) { // old and new are both documented
+                                       Options.LOG.warn("The symbol '"+symbol.alias+"' is documented more than once.");
+                               }
+                               else { // old is documented but new isn't
+                                       return;
+                               }
+                       }
+               }
+               
+               // we don't document anonymous things
+               if (this.conf.ignoreAnonymous && symbol.name.match(/\$anonymous\b/)) return;
+
+               // uderscored things may be treated as if they were marked private, this cascades
+               if (this.conf.treatUnderscoredAsPrivate && symbol.name.match(/[.#-]_[^.#-]+$/)) {
+                       symbol.isPrivate = true;
+               }
+               
+               // -p flag is required to document private things
+               if ((symbol.isInner || symbol.isPrivate) && !Options.p) return;
+               
+               // ignored things are not documented, this doesn't cascade
+               if (symbol.isIgnored) return;
+        // add it to the file's list... (for dumping later..)
+        if (Symbol.srcFile) {
+            this.filesSymbols[Symbol.srcFile].addSymbol(symbol);
+        }
+               
+               this.symbols.addSymbol(symbol);
+       },
+       
+       addBuiltin: function(name) {
+  
+               var builtin = new Symbol(name, [], "CONSTRUCTOR", new DocComment(""));
+               builtin.isNamespace = false;
+               builtin.srcFile = "";
+               builtin.isPrivate = false;
+        this.addSymbol(builtin);
+               return builtin;
+       },
+       
+               
+       finish: function() {
+               this.symbols.relate();          
+               
+               // make a litle report about what was found
+               if (this.conf.explain) {
+                       var symbols = this.symbols.toArray();
+                       var srcFile = "";
+                       for (var i = 0, l = symbols.length; i < l; i++) {
+                               var symbol = symbols[i];
+                               if (srcFile != symbol.srcFile) {
+                                       srcFile = symbol.srcFile;
+                                       print("\n"+srcFile+"\n-------------------");
+                               }
+                               print(i+":\n  alias => "+symbol.alias + "\n  name => "+symbol.name+ "\n  isa => "+symbol.isa + "\n  memberOf => " + symbol.memberOf + "\n  isStatic => " + symbol.isStatic + ",  isInner => " + symbol.isInner);
+                       }
+                       print("-------------------\n");
+               }
+       }
+    
+    
+    
+
+}
\ No newline at end of file
diff --git a/JSDOC/PrettyPrint.js b/JSDOC/PrettyPrint.js
new file mode 100644 (file)
index 0000000..eb2d94c
--- /dev/null
@@ -0,0 +1,80 @@
+
+// <script type="text/javascript">
+
+TokenReader = imports.TokenReader.TokenReader;
+ScopeParser= imports.ScopeParser.ScopeParser;
+TokenStream = imports.TokenStream.TokenStream;
+TextStream = imports.TextStream.TextStream;
+
+function  escapeHTML(str) { 
+    return str.replace(/&/g,'&amp;').
+            replace(/>/g,'&gt;'). 
+            replace(/</g,'&lt;'). 
+            replace(/"/g,'&quot;');
+};
+
+function toPretty(str)
+{
+    
+    var txs = new TextStream(str);
+    var tr = new TokenReader({ keepComments : true, keepWhite : true });
+    var toks = tr.tokenize(txs)
+    
+    var sp = new ScopeParser(new TokenStream(toks));
+    sp.buildSymbolTree();
+   // sp.mungeSymboltree();
+    var r = '';
+    r += sp.warnings.join("<BR>");
+    r == "<BR>";
+    
+    
+    
+    
+    var cs = ''; // current style..
+    
+    function toStyle(tok)
+    {
+        if (tok.is("WHIT") || tok.is("COMM") ) {
+            if (tok.data.indexOf("/") > -1) {
+                return 'comment';
+            }
+            return cs; // keep the same..
+        }
+        if (tok.is('STRN')) {
+            return 'string';
+        }
+        // other 'vary things??
+        if (tok.is('NAME') || tok.data == '.' || tok.name == 'THIS') {
+            return 'var';
+        }
+        if (/^[a-z]+/i.test(tok.data)) {
+            return 'keyword';
+        }
+        return 'syntax'
+    }
+    // loop through and print it...?
+    
+    
+    for (var i = 0;i < toks.length; i++) {
+        var ns = toStyle(toks[i]);
+        if (ns != cs) {
+            // change of style
+            if (cs.length) r +='</span>';
+            r +='<span class="jsdoc-'+ns+'">';
+            cs = ns;
+        }
+        if (toks[i].identifier) {
+            
+            r += '<span class="with-ident2">' +
+                escapeHTML(toks[i].data) + '</span>';
+                continue;
+                
+        }
+        r += escapeHTML(toks[i].data).replace(/\n/g, "<BR/>\n");
+    }
+    if (cs.length) r +='</span>';
+    return '<code class="jsdoc-pretty">'+r+'</code>';
+    
+        
+}
diff --git a/JSDOC/Scope.js b/JSDOC/Scope.js
new file mode 100644 (file)
index 0000000..84e86da
--- /dev/null
@@ -0,0 +1,316 @@
+//<Script type="text/javascript">
+
+/**
+* Scope stuff
+* 
+* // FIXME - I need this to do next() without doccomments..
+*/
+
+Identifier = imports['JSDOC/Identifier.js'].Identifier
+XObject = imports.XObject.XObject; 
+
+
+function Scope(braceN, parent, startTokN, lastIdent)
+{
+    if (lastIdent.length) {
+       //  println("NEW SCOPE: " + lastIdent);
+    }
+    
+    this.braceN = braceN
+    this.parent = parent;
+    this.id = startTokN;
+    this.identifiers = { };
+    this.subScopes = [];
+    this.hints = { };
+    this.ident = lastIdent;
+    
+    
+    //println("ADD SCOPE(" + this.id + ") TO "+ (parent ? this.parent.id : 'TOP') + "<BR/>");
+    
+    if (parent) {
+        this.parent.subScopes.push(this);
+    } 
+    
+}
+
+
+
+
+
+
+
+Scope.prototype = {
+    
+    id : 0,
+    braceN : -1,
+    parent : false,
+    subScopes : false,
+    identifiers : false,  // map of identifiers to {Identifier} objects
+    hints: false, 
+    mungeM : true, 
+    ident: '',
+    
+    munged : false,
+    protectedVars : {}, // only used by to parent..
+    declareIdentifier : function(symbol, token) {
+        
+        //println("ADD IDENT(" + this.id + "):<B>" + symbol+"</B><BR/>");
+        
+        if (typeof(this.identifiers[symbol])== 'undefined') {
+            
+            this.identifiers[symbol] =  new Identifier(symbol, this);
+            
+        }
+        if (typeof(token) != 'undefined') { // shoudl this happen?
+            token.identifier = this.identifiers[symbol];
+            
+        }
+        if (this.braceN < 0) {
+                // then it's global... 
+                this.identifiers[symbol].toMunge  = false;
+        }
+        this.addToParentScope(symbol);
+        return this.identifiers[symbol];
+    },
+    getIdentifier : function(symbol) {
+        return (typeof(this.identifiers[symbol])== 'undefined') ? false : this.identifiers[symbol];
+    },
+    
+    addHint : function(varName, varType) {
+        this.hint[varName] = varType;
+    },
+    preventMunging : function() {
+        this.mungeM = false;
+    },
+
+    usedsymcache : false,
+    
+    getUsedSymbols : function() {
+        
+        var result = [];
+       // if (this.usedsymcache !== false) {
+        //    return this.usedsymcache;
+        //}
+        
+        var idents = this.identifiers;
+        for(var i in idents) { 
+            //println('<b>'+i+'</b>='+typeof(idents[i]) +'<br/>');
+            var identifier = this.identifiers[i];
+            var mungedValue = identifier.mungedValue
+            if (!mungedValue.length) {
+                //println(identifier.toSource());
+                mungedValue = identifier.name;
+            }
+            result.push(mungedValue);
+        }
+        //println("Symbols for ("+ this.id +"): <B>" + result.join(',') + "</B><BR/>");
+        //this.usedsymcache = result;
+        return result;
+    },
+
+    getAllUsedSymbols :function() {
+        var result = this.getUsedSymbols();
+        var scope = this.parent;
+        while (scope !== false) {
+            //println("addused:"+scope.id);
+            result = result.concat(scope.getUsedSymbols());
+            scope = scope.parent;
+        }
+         //println("Done - addused");
+        return result;
+    },
+    /** - we need to register short vairalbes so they never get munged into.. */
+    addToParentScope: function(ident) 
+    {
+        if (ident.length > 2) {
+            return;
+        }
+        var scope = this.parent;
+        while (scope !== false) {
+            //println("addused:"+scope.id);
+            if (!scope.parent) {
+                scope.protectedVars[ident] = true;
+            }
+            scope = scope.parent;
+        }
+        
+    },
+    isProtectedVar: function(ident)
+    {
+        if (ident.length > 2) {
+            return false;
+        }
+        var scope = this.parent;
+        while (scope !== false) {
+            //println("addused:"+scope.id);
+            if (!scope.parent) {
+                if (typeof(scope.protectedVars[ident])  != 'undefined') return true;
+            }
+            scope = scope.parent;
+        }
+        return false;
+    },
+    
+    /**
+     * set's all the munged values on the identifiers.
+     * 
+     * 
+     */
+
+    munge :function() 
+    {
+
+        if (!this.mungeM) {
+            // Stop right here if this scope was flagged as unsafe for munging.
+           // println("MUNGE: SKIP -  Scope" + this.id+"</BR>");
+            return;
+        }
+        if (this.munged) {
+            return;
+        }
+        
+
+        
+        
+        var pickFromSet = 1;
+
+        // Do not munge symbols in the global scope!
+        if (this.parent) {
+            
+            var all = [];
+            for (var ii in this.identifiers) {
+                all.push(ii);
+            }
+            //print("MUNGE: " + all.join(', '));
+            
+            //println("MUNGE: Building FreeSyms:" + this.id+"</BR>");
+            
+            var freeSymbols = [];
+            var sy = this.getAllUsedSymbols();
+            
+            var addSyms=function(batch)
+            {
+                for(var i =0;i<batch.length;i++) {
+                    if (sy.indexOf(batch[i]) > -1) {
+                        continue;
+                    }
+                    freeSymbols.push(batch[i]);
+                }
+            }
+             
+            addSyms(Scope.ones); 
+             
+            var repsym = '';
+            //println(freeSymbols.toSource());
+            
+            //println("MUNGE: Replacing " + this.id+"</BR>");
+            for (var i in  this.identifiers) {
+                
+                // is the identifer in the global scope!?!!?
+                
+                
+                if (!this.identifiers[i].toMunge) {
+                    //print("SKIP toMunge==false : " + i)
+                    continue;
+                }
+                
+                if (this.isProtectedVar(i)) {
+                    //print("SKIP PROTECTED: " + i)
+                    continue; // 
+                }
+                
+                
+                
+                //if (this.identifiers[i].constructor !=  Identifier) {
+                //    print("SKIP NOT IDENTIFIER : " + i)
+                //    continue;
+               // }
+               // println("IDENT:" +i+'</BR>');
+                
+                if (!repsym.length) {
+                    if (!freeSymbols.length) {
+                        addSyms(JSDOC.Scope.twos); 
+                    }
+                    repsym = freeSymbols.shift(); // pop off beginngin???
+                }
+                
+                var identifier = this.identifiers[i]; 
+                //println(typeof(identifier.name));
+                var mungedValue = identifier.name; 
+                
+                //println([     repsym,mungedValue ]);
+                
+                if (this.mungeM && repsym.length < mungedValue.length) {
+                    //print("REPLACE:"+ mungedValue +" with " + repsym );    
+                    mungedValue = repsym;
+                    repsym = '';
+                }
+                
+                identifier.mungedValue =  mungedValue;
+            }
+            //println("MUNGE: Done " + this.id+"</BR>");
+        }
+        this.munged = true;
+        //println("Doing sub scopes");
+        for (var j = 0; j < this.subScopes.length; j++) {
+            var ss = this.subScopes[j];
+            ss.munge();
+        }
+    }
+
+};
+
+
+
+
+
+XObject.extend(Scope, {
+    
+    builtin : ["NaN","top"],
+    skips : [  'as', 'is', 'do', 'if', 'in', 'for', 'int', 'new', 'try', 'use', 'var', "NaN","top"],
+     
+    ones : [],
+    twos : [],
+    threes : [],
+    init : function () {
+        /* cache it later?
+        if (File.exists('/tmp/var_list_ones.js')) {
+            eval("JSDOC.Scope.ones = " + File.read('/tmp/var_list_ones.js'));
+            eval("JSDOC.Scope.twos = " + File.read('/tmp/var_twos_ones.js'));
+            eval("JSDOC.Scope.threes = " + File.read('/tmp/var_threes_ones.js'));
+        }
+        */
+        this.ones = 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'.split(',');
+        var a = this.ones;
+        var n = a.concat( '0,1,2,3,4,5,6,7,8,9'.split(','));
+        for(var i = 0; i < a.length; i++) {
+            for(var j = 0; j < n.length; j++) {
+                var tw = a[i] + n[j];
+                if (this.skips.indexOf(tw) < 0) {
+                    this.twos.push(tw);
+                }
+                    
+                /*
+                for(var k = 0; k < n.length; k++) {
+                    var thr = a[i] + n[j] + n[k];
+                    //println("thr="+ thr + ":iOf="+this.skips.indexOf(thr) );
+                    if (this.skips.indexOf(thr)  < 0) {
+                        //println("+"+thr);
+                        this.threes.push(thr);
+                       }
+                    
+                }
+                */
+            }
+        }
+        //println("done creating var list");
+        //println("threes="+ this.threes.toSource());
+        //throw "DONE";
+        
+       
+    }
+})
+// init the scope constants..
+Scope.init();
\ No newline at end of file
diff --git a/JSDOC/ScopeParser.js b/JSDOC/ScopeParser.js
new file mode 100644 (file)
index 0000000..1b315b0
--- /dev/null
@@ -0,0 +1,859 @@
+//<Script type="text/javascript">
+
+Scope = imports['JSDOC/Scope.js'].Scope;
+
+/**
+* Scope stuff
+* 
+* // FIXME - I need this to do next() without doccomments..
+*/
+
+ScopeParser = function(ts) {
+    this.ts = ts; // {TokenStream}
+    this.warnings = [];
+    this.scopes = [];
+    this.indexedScopes = {};
+    this.timer = new Date() * 1;
+    this.debug = false;
+}
+
+// list of keywords that should not be used in object literals.
+ScopeParser.idents = [
+       "break",         
+        "case",                 
+        "continue",    
+        "default",     
+        "delete",      
+        "do",           
+       "else",         
+       "export",       
+       "false",        
+       "for",          
+       "function",     
+       "if",           
+       "import",       
+       "in",           
+       "new",          
+       "null",         
+       "return",       
+       "switch",       
+       "this",         
+       "true",         
+       "typeof",       
+       "var",          
+       "void",         
+       "while",        
+       "with",         
+
+       "catch",        
+       "class",        
+       "const",        
+       "debugger",     
+       "enum",         
+       "extends",      
+       "finally",      
+       "super",        
+        "throw",        
+        "try",         
+
+        "abstract",    
+        "boolean",     
+        "byte",                
+        "char",                
+        "double",      
+        "final",       
+        "float",       
+        "goto",                
+        "implements", 
+        "instanceof",
+        "int",          
+        "interface",    
+        "long",                 
+        "native",      
+        "package",     
+        "private",     
+        "protected",    
+        "public",       
+        "short",       
+        "static",      
+        "synchronized",         
+        "throws",       
+        "transient",    
+               "include",       
+               "undefined"
+];
+
+
+ScopeParser.prototype = {
+    timer: 0,
+    timerPrint: function (str) {
+        var ntime = new Date() * 1;
+        var tdif =  ntime -this.timer;
+        this.timer = ntime;
+        var pref = '';
+        if (tdif > 100) { //slower ones..
+            pref = '***';
+        }
+        println(pref+'['+tdif+']'+str);
+        
+    },
+    warn: function(s) {
+        //print('****************' + s);
+        this.warnings.push(s);
+        //println("WARNING:" + htmlescape(s) + "<BR>");
+    },
+    // defaults should not be initialized here =- otherwise they get duped on new, rather than initalized..
+    warnings : false,
+    ts : false,
+    scopes : false,
+    global : false,
+    mode : "", //"BUILDING_SYMBOL_TREE",
+    braceNesting : 0,
+    indexedScopes : false,
+    munge: true,
+
+
+
+
+
+    buildSymbolTree : function()
+    {
+        //println("<PRE>");
+        
+        this.ts.rewind();
+        this.braceNesting = 0;
+        this.scopes = [];
+        
+        
+        
+        
+        this.globalScope = new  Scope(-1, false, -1, '');
+        indexedScopes = { 0 : this.globalScope };
+        
+        this.mode = 'BUILDING_SYMBOL_TREE';
+        this.parseScope(this.globalScope);
+        
+        //print("---------------END PASS 1 ---------------- ");
+        
+    },
+    mungeSymboltree : function()
+    {
+
+        if (!this.munge) {
+            return;
+        }
+
+        // One problem with obfuscation resides in the use of undeclared
+        // and un-namespaced global symbols that are 3 characters or less
+        // in length. Here is an example:
+        //
+        //     var declaredGlobalVar;
+        //
+        //     function declaredGlobalFn() {
+        //         var localvar;
+        //         localvar = abc; // abc is an undeclared global symbol
+        //     }
+        //
+        // In the example above, there is a slim chance that localvar may be
+        // munged to 'abc', conflicting with the undeclared global symbol
+        // abc, creating a potential bug. The following code detects such
+        // global symbols. This must be done AFTER the entire file has been
+        // parsed, and BEFORE munging the symbol tree. Note that declaring
+        // extra symbols in the global scope won't hurt.
+        //
+        // Note: Since we go through all the tokens to do this, we also use
+        // the opportunity to count how many times each identifier is used.
+
+        this.ts.rewind();
+        this.braceNesting = 0;
+        this.scopes= [];
+        this.mode = 'PASS2_SYMBOL_TREE';
+        
+        //println("MUNGING?");
+        
+        this.parseScope(this.globalScope);
+        this.globalScope.munge();
+    },
+
+
+    log : function(str)
+    {
+        print ("                    ".substring(0, this.braceNesting*2) + str);
+        
+        //println("<B>LOG:</B>" + htmlescape(str) + "<BR/>\n");
+    },
+    logR : function(str)
+    {
+            //println("<B>LOG:</B>" + str + "<BR/>");
+    },
+
+
+
+
+
+
+    parseScope : function(scope) // parse a token stream..
+    {
+        //this.timerPrint("parseScope EnterScope"); 
+        //this.log(">>> ENTER SCOPE" + this.scopes.length);
+        var symbol;
+        var token;
+        
+        var identifier;
+
+        var expressionBraceNesting = this.braceNesting;
+        
+        var parensNesting = 0;
+        
+        var isObjectLitAr = [ false ];
+        var isInObjectLitAr;
+        this.scopes.push(scope);
+        token = this.ts.lookTok(1);
+        while (token) {
+          //  this.timerPrint("parseScope AFTER lookT: " + token.toString()); 
+             
+            //this.log(token.data);
+            if (token.type == 'NAME') {
+            //    print('*' + token.data);
+            }
+            switch(token.type + '.' + token.name) {
+                case "KEYW.VAR":
+                case "KEYW.CONST": // not really relivant as it's only mozzy that does this.
+                    
+                    //this.log("parseScope GOT VAR/CONST : " + token.toString()); 
+                    while (true) {
+                        token = this.ts.nextTok();
+                        !this.debug|| print( token.toString());
+                      
+                        if (!token) { // can return false at EOF!
+                            break;
+                        }
+                        if (token.name == "VAR" || token.data == ',') { // kludge..
+                            continue;
+                        }
+                        //this.logR("parseScope GOT VAR  : <B>" + token.toString() + "</B>"); 
+                        if (token.type !="NAME") {
+                            for(var i = Math.max(this.ts.cursor-10,0); i < this.ts.cursor+1; i++) {
+                                print(this.ts.tokens[i].toString());
+                            }
+                            
+                            print( "var without ident");
+                            Seed.quit()
+                        }
+                        
+
+                        if (this.mode == "BUILDING_SYMBOL_TREE") {
+                            identifier = scope.getIdentifier(token.data) ;
+                            
+                            if (identifier == false) {
+                                scope.declareIdentifier(token.data, token);
+                            } else {
+                                token.identifier = identifier;
+                                this.warn("(SCOPE) The variable " + token.data  + ' (line:' + token.line + ")  has already been declared in the same scope...");
+                            }
+                        }
+
+                        token = this.ts.nextTok();
+                        !this.debug|| print(token.toString());
+                        /*
+                        assert token.getType() == Token.SEMI ||
+                                token.getType() == Token.ASSIGN ||
+                                token.getType() == Token.COMMA ||
+                                token.getType() == Token.IN;
+                        */
+                        if (token.name == "IN") {
+                            break;
+                        } else {
+                            //var bn = this.braceNesting;
+                            this.parseExpression();
+                            //this.braceNesting = bn;
+                            //this.logR("parseScope DONE  : <B>ParseExpression</B> - tok is:" + this.ts.lookT(0).toString()); 
+                            
+                            token = this.ts.lookTok(1);
+                            !this.debug|| print("AFTER EXP: " + token.toString());
+                            if (token.data == ';') {
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                case "KEYW.FUNCTION":
+                    //println("<i>"+token.data+"</i>");
+                     var bn = this.braceNesting;
+                    this.parseFunctionDeclaration();
+                     this.braceNesting = bn;
+                    break;
+
+                case "PUNC.LEFT_CURLY": // {
+                    //println("<i>"+token.data+"</i>");
+                    isObjectLitAr.push(false);
+                    this.braceNesting++;
+                    
+                    //print(">>>>>> OBJLIT PUSH(false)" + this.braceNesting);
+                    break;
+
+                case "PUNC.RIGHT_CURLY": // }
+                    //println("<i>"+token.data+"</i>");
+                    this.braceNesting--;
+                    isObjectLitAr.pop();
+                    //print(">>>>>> OBJLIT POP"+ this.braceNesting);
+                        //assert braceNesting >= scope.getBra ceNesting();
+                    
+                    if (this.braceNesting < expressionBraceNesting) {
+                        var ls = this.scopes.pop();
+                        ls.getUsedSymbols();
+                        // eat symbol if we are currently at { 
+                        if (this.ts.look(0).data == '{') {
+                            this.ts.nextTok();
+                        }
+                        
+                        //print("<<<<<<<EXIT SCOPE" +this.scopes.length);
+                        return;
+                    }
+                    break;
+
+                case "KEYW.WITH":
+                    //println("<i>"+token.data+"</i>");   
+                    if (this.mode == "BUILDING_SYMBOL_TREE") {
+                        // Inside a 'with' block, it is impossible to figure out
+                        // statically whether a symbol is a local variable or an
+                        // object member. As a consequence, the only thing we can
+                        // do is turn the obfuscation off for the highest scope
+                        // containing the 'with' block.
+                        this.protectScopeFromObfuscation(scope);
+                        this.warn("Using 'with' is not recommended." + (this.munge ? " Moreover, using 'with' reduces the level of compression!" : ""), true);
+                    }
+                    break;
+
+                case "KEYW.CATCH":
+                    //println("<i>"+token.data+"</i>");
+                    this.parseCatch();
+                    break;
+                /*
+                case Token.SPECIALCOMMENT:
+                        if (mode == BUILDING_SYMBOL_TREE) {
+                            protectScopeFromObfuscation(scope);
+                            this.warn("Using JScript conditional comments is not recommended." + (munge ? " Moreover, using JScript conditional comments reduces the level of compression." : ""), true);
+                        }
+                        break;
+                */
+                
+                case "STRN.DOUBLE_QUOTE": // used for object lit detection..
+                case "STRN.SINGLE_QUOTE":
+                    //println("<i>"+token.data+"</i>");
+                    if (this.ts.lookTok(-1).data == '{' && this.ts.lookTok(1).data == ':') {
+                        // then we are in an object lit.. -> we need to flag the brace as such...
+                        isObjectLitAr.pop();
+                        isObjectLitAr.push(true);
+                        //print(">>>>>> OBJLIT REPUSH(true)");
+                    }
+                    isInObjectLitAr = isObjectLitAr[isObjectLitAr.length-1];
+                    
+                    if (isInObjectLitAr &&  this.ts.lookTok(1).data == ':' &&
+                        ( this.ts.lookTok(-1).data == '{'  ||  this.ts.lookTok(-1).data == ':' )) {
+                        // see if we can replace..
+                        // remove the quotes..
+                        // should do a bit more checking!!!! (what about wierd char's in the string..
+                        var str = token.data.substring(1,token.data.length-1);
+                        if (/^[a-z_]+$/i.test(str) && ScopeParser.idents.indexOf(str) < 0) {
+                            token.outData = str;
+                        }
+                        
+                         
+                        
+                    }
+                    
+                    
+                    
+                    break;
+                
+                case "NAME.NAME":
+                
+                    //print("DEAL WITH NAME:");
+                    // got identifier..
+                    
+                    // look for  { ** : <- indicates obj literal.. ** this could occur with numbers ..
+                    if ((this.ts.lookTok(-1).data == "{") && (this.ts.lookTok(1).data == ":")) {
+                        isObjectLitAr.pop();
+                        isObjectLitAr.push(true);
+                        //print(">>>>>> OBJLIT REPUSH(true)");
+                        //println("<i>"+token.data+"</i>");
+                        break;
+                    }
+                   // print("DEAL WITH obj lit:");
+                    isInObjectLitAr = isObjectLitAr[isObjectLitAr.length-1];
+                    
+                    if (isInObjectLitAr && (this.ts.lookTok(1).data == ":") && (this.ts.lookTok(-1).data == ",")) {
+                        // skip, it's an object lit key..
+                        //println("<i>"+token.data+"</i>");
+                        break;
+                    }
+                    
+                    
+                    // skip anyting with "." before it..!!
+                     
+                    if (this.ts.lookTok(-1).data == ".") {
+                        // skip, it's an object prop.
+                        //println("<i>"+token.data+"</i>");
+                        break;
+                    }
+                    symbol = token.data;
+                    if (this.mode == 'PASS2_SYMBOL_TREE') {
+                        
+                        //println("GOT IDENT: -2 : " + this.ts.lookT(-2).toString() + " <BR> ..... -1 :  " +  this.ts.lookT(-1).toString() + " <BR> "); 
+                        
+                        //print ("MUNGE?" + symbol);
+                        
+                        //println("GOT IDENT: <B>" + symbol + "</B><BR/>");
+                             
+                            //println("GOT IDENT (2): <B>" + symbol + "</B><BR/>");
+                        identifier = this.getIdentifier(symbol, scope);
+                        
+                        if (identifier == false) {
+// BUG!find out where builtin is defined...
+                            if (symbol.length <= 3 &&  Scope.builtin.indexOf(symbol) < 0) {
+                                // Here, we found an undeclared and un-namespaced symbol that is
+                                // 3 characters or less in length. Declare it in the global scope.
+                                // We don't need to declare longer symbols since they won't cause
+                                // any conflict with other munged symbols.
+                                this.globalScope.declareIdentifier(symbol, token);
+                                this.warn("Found an undeclared symbol: " + symbol + ' (line:' + token.line + ')', true);
+                            }
+                            
+                            //println("GOT IDENT IGNORE(3): <B>" + symbol + "</B><BR/>");
+                        } else {
+                            token.identifier = identifier;
+                            identifier.refcount++;
+                        }
+                    }   
+                    
+                    break;
+                    //println("<B>SID</B>");
+                default:
+                    if (token.type != 'KEYW') {
+                        break;
+                    }
+                   // print("Check eval:");
+                
+                    symbol = token.data;
+                    
+                     if (this.mode == 'BUILDING_SYMBOL_TREE') {
+
+                        if (symbol == "eval") {
+                            // look back one and see if we can find a comment!!!
+                            if (this.ts.look(-1).type == "COMM") {
+                                // look for eval:var:noreplace\n
+                                var _t = this;
+                                this.ts.look(-1).data.replace(/eval:var:([a-z_]+)/ig, function(m, a) {
+                                    
+                                    var hi = _t.getIdentifier(a, scope);
+                                   // println("PROTECT "+a+" from munge" + (hi ? "FOUND" : "MISSING"));
+                                    if (hi) {
+                                     //   println("PROTECT "+a+" from munge");
+                                        hi.toMunge = false;
+                                    }
+                                    
+                                });
+                                
+                                
+                            } else {
+                                
+                            
+                                this.protectScopeFromObfuscation(scope);
+                                this.warn("Using 'eval' is not recommended. (use  eval:var:noreplace in comments to optimize) " + (this.munge ? " Moreover, using 'eval' reduces the level of compression!" : ""), true);
+                            }
+
+                        }
+
+                    }
+                    break;
+                
+                
+            } // end switch
+            
+            
+            //this.timerPrint("parseScope TOK : " + token.toString()); 
+            token = this.ts.nextTok();
+            //if (this.ts.nextT()) break;
+            
+        }
+        //print("<<<<<<<EXIT SCOPE ERR?" +this.scopes.length);
+    },
+
+
+    parseExpression : function() {
+
+        // Parse the expression until we encounter a comma or a semi-colon
+        // in the same brace nesting, bracket nesting and paren nesting.
+        // Parse functions if any...
+        //println("<i>EXP</i><BR/>");
+        !this.debug || print("PARSE EXPR");
+        var symbol;
+        var token;
+        var currentScope;
+        var identifier;
+
+        var expressionBraceNesting = this.braceNesting;
+        var bracketNesting = 0;
+        var parensNesting = 0;
+        var isInObjectLitAr;
+        var isObjectLitAr = [ false ];
+        while (token = this.ts.lookTok()) {
+     
+
+            
+            currentScope = this.scopes[this.scopes.length-1];
+            
+            //println("<i>"+token.data+"</i>");
+            //this.log("EXP:" + token.data);
+            switch (token.type) {
+                case 'PUNC':
+                    switch(token.data) {
+                         
+                        case ';':
+                        case ',':
+                            if (this.braceNesting == expressionBraceNesting &&
+                                    bracketNesting == 0 &&
+                                    parensNesting == 0) {
+                                
+                                return;
+                            }
+                            break;
+
+                       
+
+                        case '{': //Token.LC:
+                            isObjectLitAr.push(false);
+                            
+                            this.braceNesting++;
+                            ///print(">>>>> EXP PUSH(false)"+this.braceNesting);
+                            break;
+
+                        case '}': //Token.RC:
+                            this.braceNesting--;
+                            isObjectLitAr.pop();
+                            //print(">>>>> EXP POP" + this.braceNesting);    
+                           // assert braceNesting >= expressionBraceNesting;
+                            break;
+
+                        case '[': //Token.LB:
+                            bracketNesting++;
+                            break;
+
+                        case ']': //Token.RB:
+                            bracketNesting--;
+                            break;
+
+                        case '(': //Token.LP:
+                            parensNesting++;
+                            break;
+
+                        case ')': //Token.RP:
+                            parensNesting--;
+                            break;
+                    }
+                    break;
+                    
+                case 'STRN': // used for object lit detection..
+                    if (this.ts.lookTok(-1).data == "{" && this.ts.lookTok(1).data == ":" ) {
+                        // then we are in an object lit.. -> we need to flag the brace as such...
+                        isObjectLitAr.pop();
+                        isObjectLitAr.push(true);
+                        //print(">>>>> EXP PUSH(true)");
+                    }
+                    
+                    
+                     
+                    isInObjectLitAr = isObjectLitAr[isObjectLitAr.length-1];
+                    if (isInObjectLitAr &&  this.ts.lookTok(1).data == ":"  &&
+                        ( this.ts.lookTok(-1).data == "{"  ||  this.ts.lookTok(-1).data == "," )) {
+                        // see if we can replace..
+                        // remove the quotes..
+                        var str = token.data.substring(1,token.data.length-1);
+                        if (/^[a-z_]+$/i.test(str) && ScopeParser.idents.indexOf(str) < 0) {
+                            token.outData = str;
+                        }
+                        
+                         
+                        
+                    }
+                    
+                    break;
+                
+                      
+             
+                case 'NAME':
+               
+                    symbol = token.data;
+                  
+                    if (this.ts.look(0).data == "{"  && this.ts.lookTok(2).data == ":") {
+                        // then we are in an object lit.. -> we need to flag the brace as such...
+                        isObjectLitAr.pop();
+                        isObjectLitAr.push(true);
+                         //print(">>>>> EXP  PUSH(true)");
+                        break;
+                    }
+                    isInObjectLitAr = isObjectLitAr[isObjectLitAr.length-1];
+                    if (isInObjectLitAr && this.ts.lookTok(0).data == "," && this.ts.lookTok(2).data == ":") {
+                        break;
+                    }
+                    //print(this.ts.lookTok(0).data);
+                    if (this.ts.lookTok(0).data == ".") {
+                        //skip '.'
+                        break;
+                    }
+                    
+                     if (this.mode == 'PASS2_SYMBOL_TREE') {
+
+                        identifier = this.getIdentifier(symbol, currentScope);
+                        //println("<B>??</B>");
+                        if (identifier == false) {
+
+                            if (symbol.length <= 3 &&  Scope.builtin.indexOf(symbol) < 0) {
+                                // Here, we found an undeclared and un-namespaced symbol that is
+                                // 3 characters or less in length. Declare it in the global scope.
+                                // We don't need to declare longer symbols since they won't cause
+                                // any conflict with other munged symbols.
+                                this.globalScope.declareIdentifier(symbol, token);
+                                this.warn("Found an undeclared symbol: " + symbol + ' (line:' + token.line + ')', true);
+                            } else {
+                                //println("undeclared")
+                            }
+                            
+                            
+                        } else {
+                            //println("<B>++</B>");
+                            token.identifier = identifier;
+                            identifier.refcount++;
+                        }
+                        
+                    }
+                    break;
+                    
+                    
+                    
+                    
+                    //println("<B>EID</B>");
+                 case 'KEYW':   
+                 
+                    if (token.name == "FUNCTION") {
+                        
+                        this.parseFunctionDeclaration();
+                        break;
+                    }
+               
+                    
+             
+                    symbol = token.data;
+                    if (this.mode == 'BUILDING_SYMBOL_TREE') {
+
+                        if (symbol == "eval") {
+                            if (this.ts.look(-1).type == 'COMM') {
+                                // look for eval:var:noreplace\n
+                                var _t = this;
+                                this.ts.look(-1).data.replace(/eval:var:([a-z]+)/ig, function(m, a) {
+                                    var hi = _t.getIdentifier(a, currentScope);
+                                   //println("PROTECT "+a+" from munge" + (hi ? "FOUND" : "MISSING"));
+                                    if (hi) {
+                                      //  println("PROTECT "+a+" from munge");
+                                        hi.toMunge = false;
+                                    }
+                                    
+                                    
+                                });
+                                
+                            } else {
+                                this.protectScopeFromObfuscation(currentScope);
+                                this.warn("Using 'eval' is not recommended." + (this.munge ? " Moreover, using 'eval' reduces the level of compression!" : ""), true);
+                            }
+                            
+
+                        }
+                        break;
+                    } 
+                   
+            }
+            if (!this.ts.nextTok()) break;
+        }
+    },
+
+
+    parseCatch : function() {
+
+        var symbol;
+        var token;
+        var currentScope;
+        var identifier;
+
+        //token = getToken(-1);
+        //assert token.getType() == Token.CATCH;
+        token = this.ts.nextTok();
+        //assert token.getType() == Token.LP; (
+        token = this.ts.nextTok();
+        //assert token.getType() == Token.NAME;
+        
+        symbol = token.data;
+        currentScope = this.scopes[this.scopes.length-1];
+
+        if (this.mode == 'BUILDING_SYMBOL_TREE') {
+            // We must declare the exception identifier in the containing function
+            // scope to avoid errors related to the obfuscation process. No need to
+            // display a warning if the symbol was already declared here...
+            currentScope.declareIdentifier(symbol, token);
+        } else {
+            //?? why inc the refcount?? - that should be set when building the tree???
+            identifier = this.getIdentifier(symbol, currentScope);
+            identifier.refcount++;
+        }
+
+        token = this.ts.nextTok();
+        //assert token.getType() == Token.RP; // )
+    },
+    
+    parseFunctionDeclaration : function() 
+    {
+       // print("PARSE FUNCTION");
+        var symbol;
+        var token;
+        var currentScope  = false; 
+        var fnScope = false;
+        var identifier;
+        //this.logR("<B>PARSING FUNCTION</B>");
+        currentScope = this.scopes[this.scopes.length-1];
+
+        token = this.ts.nextTok();
+        if (token.type == "NAME") {
+            if (this.mode == 'BUILDING_SYMBOL_TREE') {
+                // Get the name of the function and declare it in the current scope.
+                symbol = token.data;
+                if (currentScope.getIdentifier(symbol) != false) {
+                    this.warn("The function " + symbol + " has already been declared in the same scope...", true);
+                }
+                currentScope.declareIdentifier(symbol,token);
+            }
+            token =  this.ts.nextTok();
+        }
+
+        //assert token.getType() == Token.LP;
+        if (this.mode == 'BUILDING_SYMBOL_TREE') {
+            fnScope = new Scope(this.braceNesting, currentScope, token.n, '');
+            
+            //println("STORING SCOPE" + this.ts.cursor);
+            
+            this.indexedScopes[this.ts.cursor] = fnScope;
+            
+        } else {
+            //qln("FETCHING SCOPE" + this.ts.cursor);
+            fnScope = this.indexedScopes[this.ts.cursor];
+          
+        }
+        
+        // Parse function arguments.
+        var argpos = 0;
+        while (this.ts.lookTok().data != ')') { //(token = consumeToken()).getType() != Token.RP) {
+            token = this.ts.nextTok();
+           // print ("FUNC ARGS: " + token.toString())
+            //assert token.getType() == Token.NAME ||
+            //        token.getType() == Token.COMMA;
+            if (token.type == 'NAME' && this.mode == 'BUILDING_SYMBOL_TREE') {
+                symbol = token.data;
+                identifier = fnScope.declareIdentifier(symbol,token);
+                if (symbol == "$super" && argpos == 0) {
+                    // Exception for Prototype 1.6...
+                    identifier.preventMunging();
+                }
+                argpos++;
+            }
+        }
+
+        token = this.ts.nextTok();
+        // assert token.getType() == Token.LC;
+        this.braceNesting++;
+
+        token = this.ts.nextTok();
+        if (token.type == "STRN" && this.ts.lookTok(1).data == ';') {
+            /*
+            
+            NOT SUPPORTED YET!?!!?!
+            
+            // This is a hint. Hints are empty statements that look like
+            // "localvar1:nomunge, localvar2:nomunge"; They allow developers
+            // to prevent specific symbols from getting obfuscated (some heretic
+            // implementations, such as Prototype 1.6, require specific variable
+            // names, such as $super for example, in order to work appropriately.
+            // Note: right now, only "nomunge" is supported in the right hand side
+            // of a hint. However, in the future, the right hand side may contain
+            // other values.
+            consumeToken();
+            String hints = token.getValue();
+            // Remove the leading and trailing quotes...
+            hints = hints.substring(1, hints.length() - 1).trim();
+            StringTokenizer st1 = new StringTokenizer(hints, ",");
+            while (st1.hasMoreTokens()) {
+                String hint = st1.nextToken();
+                int idx = hint.indexOf(':');
+                if (idx <= 0 || idx >= hint.length() - 1) {
+                    if (mode == BUILDING_SYMBOL_TREE) {
+                        // No need to report the error twice, hence the test...
+                        this.warn("Invalid hint syntax: " + hint, true);
+                    }
+                    break;
+                }
+                String variableName = hint.substring(0, idx).trim();
+                String variableType = hint.substring(idx + 1).trim();
+                if (mode == BUILDING_SYMBOL_TREE) {
+                    fnScope.addHint(variableName, variableType);
+                } else if (mode == CHECKING_SYMBOL_TREE) {
+                    identifier = fnScope.getIdentifier(variableName);
+                    if (identifier != null) {
+                        if (variableType.equals("nomunge")) {
+                            identifier.preventMunging();
+                        } else {
+                            this.warn("Unsupported hint value: " + hint, true);
+                        }
+                    } else {
+                        this.warn("Hint refers to an unknown identifier: " + hint, true);
+                    }
+                }
+            }
+            */
+        }
+
+        this.parseScope(fnScope);
+        // now pop it off the stack!!!
+       
+        
+        
+    },
+    
+    protectScopeFromObfuscation : function(scope) {
+            //assert scope != null;
+        
+        if (scope == this.globalScope) {
+            // The global scope does not get obfuscated,
+            // so we don't need to worry about it...
+            return;
+        }
+
+        // Find the highest local scope containing the specified scope.
+        while (scope && scope.parent != this.globalScope) {
+            scope = scope.parent;
+        }
+
+        //assert scope.getParentScope() == globalScope;
+        scope.preventMunging();
+    },
+    
+    getIdentifier: function(symbol, scope) {
+        var identifier;
+        while (scope != false) {
+            identifier = scope.getIdentifier(symbol);
+            //println("ScopeParser.getIdentgetUsedSymbols("+symbol+")=" + scope.getUsedSymbols().join(','));
+            if (identifier) {
+                return identifier;
+            }
+            scope = scope.parent;
+        }
+        return false;
+    }
+};
\ No newline at end of file
diff --git a/JSDOC/Symbol.js b/JSDOC/Symbol.js
new file mode 100644 (file)
index 0000000..9649444
--- /dev/null
@@ -0,0 +1,742 @@
+//<script type="text/javascript">
+
+XObject         = imports.XObject.XObject;
+
+SymbolSet       = imports.SymbolSet.SymbolSet;
+Parser          = imports.Parser.Parser;
+DocComment      = imports.DocComment.DocComment;
+
+/**
+       Create a new Symbol.
+       @class Represents a symbol in the source code.
+ */
+Symbol = XObject.define(
+    function() {
+        this.init();
+        if (arguments.length) this.populate.apply(this, arguments);
+        
+    },
+    Object,
+    {
+        
+            
+        /*
+        toQDump : function(t)
+        {
+            return toQDump(t, 'Symbol.fromDump({', '})', {});//new Symbol());
+        },
+        */
+        init : function() 
+        {
+            this.name = "";
+            this.defaultValue = "";
+            this.params = [];
+            this.$args = [];
+            this.addOn = "";
+            this.alias = "";
+            this.augments = [];
+            this.author = "";
+            this.classDesc = "";
+            this.comment = { isUserComment: false };
+            //this.defaultValue = null;
+            this.deprecated = "";
+            this.desc = "";
+            this.events = [];
+            this.example = "";
+            this.exceptions = [];
+            this.inherits = [];
+            this.inheritsFrom = [];
+            this.isa = "OBJECT"; // OBJECT//FUNCTION
+            this.isEvent = false;
+            this.isConstant = false;
+            this.isIgnored = false;
+            this.isInner = false;
+            this.isNamespace = false;
+            this.isPrivate = false;
+            this.isStatic = false;
+            this.memberOf = "";
+            this.methods = [];
+            this._name = "";
+            this._params = [];
+            this.properties = [];
+            this.requires = [];
+            this.returns = [];
+            this.see = [];
+            this.since = "";
+            this.srcFile = {};
+            this.type = "";
+            this.version = "";
+            this.childClasses = [];
+            this.cfgs = {};
+               
+        },
+
+        serialize : function() {
+            var keys = [];
+            for (var p in this) {
+                keys.push (p);
+            }
+            keys = keys.sort();
+            
+            var out = "";
+            for (var i in keys) {
+                if (typeof this[keys[i]] == "function") continue;
+                out += "     " +keys[i]+" => "+
+                    (   
+                        (typeof(this[keys[i]]) != "object") ?  
+                            this[keys[i]] :
+                            "[" +typeof(this[keys[i]])+"]"
+                    ) + 
+                    ",\n";
+            }
+            return "\n{\n" + out + "}\n";
+        },
+
+        clone : function() {
+            var clone = new Symbol();
+            clone.populate.apply(clone, this.$args); // repopulate using the original arguments
+            clone.srcFile = this.srcFile; // not the current srcFile, the one when the original was made
+            return clone;
+        },
+
+
+
+
+        //__defineSetter__("name",
+        setName  : function(n) { 
+                n = n.replace(/^_global_[.#-]/, ""); 
+                n = n.replace(/\.prototype\.?/g, '#'); 
+                 n = n.replace(/#$/g, ''); 
+                this._name = n;
+                this.name = n; // real!
+            },
+        //);
+        //__defineGetter__("name",
+        getName : function() { return this._name; },
+        //);
+        //__defineSetter__("params", 
+        setParams  :function(v) {
+                for (var i = 0, l = v.length; i < l; i++) {
+                    if (v[i].constructor != DocTag) { // may be a generic object parsed from signature, like {type:..., name:...}
+                        var ty = v[i].hasOwnProperty('type') ? v[i].type : '';
+                        this._params[i] = new DocTag(
+                            "param"+((ty)?" {"+ty+"}":"")+" "+v[i].name);
+                    }
+                    else {
+                        this._params[i] = v[i];
+                    }
+                }
+                this.params = this._params;
+            },
+        //);
+
+
+        //__defineGetter__("params",
+        getParams : function() { return this._params; },
+        //);
+
+        populate : function(
+                /** String */ name,
+                /** Object[] */ params,
+                /** String */ isa,
+                /** DocComment */ comment
+        ) {
+            this.$args = arguments;
+            //println("Symbol created: " + isa + ":" + name);
+            this.setName(name);
+            this.alias = this.getName();
+            this.setParams(params);
+            this.isa = (isa == "VIRTUAL")? "OBJECT":isa;
+            this.comment = comment || new DocComment("");
+            this.srcFile = Symbol.srcFile;
+            
+           
+            
+            if (this.is("FILE") && !this.alias) this.alias = this.srcFile;
+
+            this.setTags();
+            
+            //if (typeof PluginManager != "undefined") {
+            //    PluginManager.run("onSymbol", this);
+            //}
+        },
+
+        setTags : function() {
+            // @author
+            var authors = this.comment.getTag("author");
+            if (authors.length) {
+                this.author = authors.map(function($){return $.desc;}).join(", ");
+            }
+            
+            /*~t
+                assert("testing Symbol");
+                
+                requires("../lib/JSDOC/DocComment.js");
+                requires("../frame/String.js");
+                requires("../lib/JSDOC/DocTag.js");
+
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@author Joe Smith*"+"/"));
+                assertEqual(sym.author, "Joe Smith", "@author tag, author is found.");
+            */
+            // @desc
+            var mth = this.comment.getTag("method");
+            if (mth.length) {
+                this.isa = "FUNCTION";
+            }
+            // @desc
+            var descs = this.comment.getTag("desc");
+            if (descs.length) {
+                this.desc = descs.map(function($){return $.desc;}).join("\n"); // multiple descriptions are concatenated into one
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@desc This is a description.*"+"/"));
+                assertEqual(sym.desc, "This is a description.", "@desc tag, description is found.");
+            */
+            
+            // @overview
+            if (this.is("FILE")) {
+                if (!this.alias) this.alias = this.srcFile;
+                
+                var overviews = this.comment.getTag("overview");
+                if (overviews.length) {
+                    this.desc = [this.desc].concat(overviews.map(function($){return $.desc;})).join("\n");
+                }
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@overview This is an overview.*"+"/"));
+                assertEqual(sym.desc, "\nThis is an overview.", "@overview tag, description is found.");
+            */
+            
+            // @since
+            var sinces = this.comment.getTag("since");
+            if (sinces.length) {
+                this.since = sinces.map(function($){return $.desc;}).join(", ");
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@since 1.01*"+"/"));
+                assertEqual(sym.since, "1.01", "@since tag, description is found.");
+            */
+            
+            // @constant
+            if (this.comment.getTag("constant").length) {
+                this.isConstant = true;
+                this.isa = 'OBJECT';
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@constant*"+"/"));
+                assertEqual(sym.isConstant, true, "@constant tag, isConstant set.");
+            */
+            
+            // @version
+            var versions = this.comment.getTag("version");
+            if (versions.length) {
+                this.version = versions.map(function($){return $.desc;}).join(", ");
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@version 2.0x*"+"/"));
+                assertEqual(sym.version, "2.0x", "@version tag, version is found.");
+            */
+            
+            // @deprecated
+            var deprecateds = this.comment.getTag("deprecated");
+            if (deprecateds.length) {
+                this.deprecated = deprecateds.map(function($){return $.desc;}).join("\n");
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@deprecated Use other method.*"+"/"));
+                assertEqual(sym.deprecated, "Use other method.", "@deprecated tag, desc is found.");
+            */
+            
+            // @example
+            var examples = this.comment.getTag("example");
+            if (examples.length) {
+                this.example = examples[0];
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@example This\n  is an example.*"+"/"));
+                assertEqual(sym.example, "This\n  is an example.", "@deprecated tag, desc is found.");
+            */
+            
+            // @see
+            var sees = this.comment.getTag("see");
+            if (sees.length) {
+                var thisSee = this.see;
+                sees.map(function($){thisSee.push($.desc);});
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@see The other thing.*"+"/"));
+                assertEqual(sym.see, "The other thing.", "@see tag, desc is found.");
+            */
+            
+            // @class
+            var classes = this.comment.getTag("class");
+            if (classes.length) {
+                this.isa = "CONSTRUCTOR";
+                this.classDesc = classes[0].desc; // desc can't apply to the constructor as there is none.
+                if (!this.classDesc) {
+                    this.classDesc = this.desc;
+                   }
+                
+                
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@class This describes the class.*"+"/"));
+                assertEqual(sym.isa, "CONSTRUCTOR", "@class tag, makes symbol a constructor.");
+                assertEqual(sym.classDesc, "This describes the class.", "@class tag, class description is found.");
+            */
+            
+            // @namespace
+            var namespaces = this.comment.getTag("namespace");
+            if (namespaces.length) {
+                this.classDesc = namespaces[0].desc+"\n"+this.desc; // desc can't apply to the constructor as there is none.
+                this.isNamespace = true;
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@namespace This describes the namespace.*"+"/"));
+                assertEqual(sym.classDesc, "This describes the namespace.\n", "@namespace tag, class description is found.");
+            */
+            
+            // @param
+            var params = this.comment.getTag("param");
+            if (params.length) {
+                // user-defined params overwrite those with same name defined by the parser
+                var thisParams = this.getParams();
+
+                if (thisParams.length == 0) { // none exist yet, so just bung all these user-defined params straight in
+                    this.setParams(params);
+                }
+                else { // need to overlay these user-defined params on to existing parser-defined params
+                    for (var i = 0, l = params.length; i < l; i++) {
+                        if (thisParams[i]) {
+                            if (params[i].type) thisParams[i].type = params[i].type;
+                            thisParams[i].name = params[i].name;
+                            thisParams[i].desc = params[i].desc;
+                            thisParams[i].isOptional = params[i].isOptional;
+                            thisParams[i].defaultValue = params[i].defaultValue;
+                        }
+                        else thisParams[i] = params[i];
+                    }
+                }
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new DocComment("/**Description.*"+"/"));
+                assertEqual(sym.params.length, 1, "parser defined param is found.");
+                
+                sym = new Symbol("foo", [], "FUNCTION", new DocComment("/**Description.\n@param {array} pages*"+"/"));
+                assertEqual(sym.params.length, 1, "user defined param is found.");
+                assertEqual(sym.params[0].type, "array", "user defined param type is found.");
+                assertEqual(sym.params[0].name, "pages", "user defined param name is found.");
+                
+                sym = new Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new DocComment("/**Description.\n@param {string} uid*"+"/"));
+                assertEqual(sym.params.length, 1, "user defined param overwrites parser defined param.");
+                assertEqual(sym.params[0].type, "string", "user defined param type overwrites parser defined param type.");
+                assertEqual(sym.params[0].name, "uid", "user defined param name overwrites parser defined param name.");
+            
+                sym = new Symbol("foo", [{type: "array", name: "pages"}, {type: "number", name: "count"}], "FUNCTION", new DocComment("/**Description.\n@param {string} uid*"+"/"));
+                assertEqual(sym.params.length, 2, "user defined params  overlay parser defined params.");
+                assertEqual(sym.params[1].type, "number", "user defined param type overlays parser defined param type.");
+                assertEqual(sym.params[1].name, "count", "user defined param name overlays parser defined param name.");
+
+                sym = new Symbol("foo", [], "FUNCTION", new DocComment("/**Description.\n@param {array} pages The pages description.*"+"/"));
+                assertEqual(sym.params.length, 1, "user defined param with description is found.");
+                assertEqual(sym.params[0].desc, "The pages description.", "user defined param description is found.");
+            */
+            
+            // @constructor
+            if (this.comment.getTag("constructor").length) {
+                this.isa = "CONSTRUCTOR";
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@constructor*"+"/"));
+                assertEqual(sym.isa, "CONSTRUCTOR", "@constructor tag, makes symbol a constructor.");
+            */
+            
+            // @static
+            if (this.comment.getTag("static").length) {
+                this.isStatic = true;
+                if (this.isa == "CONSTRUCTOR") {
+                    this.isNamespace = true;
+                }
+            }
+            
+                // @static
+            if (this.comment.getTag("singleton").length) {
+                this.isStatic = true;
+                //if (this.isa == "CONSTRUCTOR") {
+                //     this.isNamespace = true;
+                //}
+            }
+            
+            
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@static\n@constructor*"+"/"));
+                assertEqual(sym.isStatic, true, "@static tag, makes isStatic true.");
+                assertEqual(sym.isNamespace, true, "@static and @constructor tag, makes isNamespace true.");
+            */
+            
+            // @inner
+            if (this.comment.getTag("inner").length) {
+                this.isInner = true;
+                this.isStatic = false;
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@inner*"+"/"));
+                assertEqual(sym.isStatic, false, "@inner tag, makes isStatic false.");
+                assertEqual(sym.isInner, true, "@inner makes isInner true.");
+            */
+            
+            // @field
+            if (this.comment.getTag("field").length) {
+                this.isa = "OBJECT";
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FUNCTION", new DocComment("/**@field*"+"/"));
+                assertEqual(sym.isa, "OBJECT", "@field tag, makes symbol an object.");
+            */
+            
+            // @function
+            if (this.comment.getTag("function").length) {
+                this.isa = "FUNCTION";
+            }
+            
+            // @param
+            if (this.comment.getTag("param").length && this.isa == "OBJECT" ) {
+                // change a property to a function..
+                this.isa = "FUNCTION";
+            }
+            
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@function*"+"/"));
+                assertEqual(sym.isa, "FUNCTION", "@function tag, makes symbol a function.");
+            */
+            
+            // @event
+            var events = this.comment.getTag("event");
+            if (events.length) {
+                this.isa = "FUNCTION";
+                this.isEvent = true;
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@event*"+"/"));
+                assertEqual(sym.isa, "FUNCTION", "@event tag, makes symbol a function.");
+                assertEqual(sym.isEvent, true, "@event makes isEvent true.");
+            */
+            
+            // @name
+            var names = this.comment.getTag("name");
+            if (names.length) {
+                this.setName(names[0].desc);
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @property
+            var properties = this.comment.getTag("property");
+            if (properties.length) {
+                thisProperties = this.properties;
+                for (var i = 0; i < properties.length; i++) {
+                    var property = new Symbol(this.alias+"#"+properties[i].name, [], "OBJECT", new DocComment("/**"+properties[i].desc+"\n@name "+properties[i].name+"\n@memberOf "+this.alias+"#*/"));
+                    // TODO: shouldn't the following happen in the addProperty method of Symbol?
+                    property.name = properties[i].name;
+                    property.memberOf = this.alias;
+                    if (properties[i].type) property.type = properties[i].type;
+                    if (properties[i].defaultValue) property.defaultValue = properties[i].defaultValue;
+                    this.addProperty(property);
+                    Parser.addSymbol(property);
+                }
+            }
+            
+            // config..
+            var conf = this.comment.getTag("cfg");
+            if (conf.length) {
+                for (var i = 0; i < conf.length; i++) {
+                    this.addConfig(conf[i]);
+                }
+            }
+            
+            /*~t
+                // todo
+            */
+
+            // @return
+            var returns = this.comment.getTag("return");
+            if (returns.length) { // there can be many return tags in a single doclet
+                this.returns = returns;
+                this.type = returns.map(function($){return $.type}).join(", ");
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @exception
+            this.exceptions = this.comment.getTag("throws");
+            
+            /*~t
+                // todo
+            */
+            
+            // @requires
+            var requires = this.comment.getTag("requires");
+            if (requires.length) {
+                this.requires = requires.map(function($){return $.desc});
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @type
+            var types = this.comment.getTag("type");
+            if (types.length) {
+                this.type = types[0].desc; //multiple type tags are ignored
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @private
+            if (this.comment.getTag("private").length || this.isInner) {
+                this.isPrivate = true;
+            }
+            
+            // @ignore
+            if (this.comment.getTag("ignore").length) {
+                this.isIgnored = true;
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @inherits ... as ...
+            var inherits = this.comment.getTag("inherits");
+            if (inherits.length) {
+                for (var i = 0; i < inherits.length; i++) {
+                    if (/^\s*([a-z$0-9_.#-]+)(?:\s+as\s+([a-z$0-9_.#]+))?/i.test(inherits[i].desc)) {
+                        var inAlias = RegExp.$1;
+                        var inAs = RegExp.$2 || inAlias;
+
+                        if (inAlias) inAlias = inAlias.replace(/\.prototype\.?/g, "#");
+                        
+                        if (inAs) {
+                            inAs = inAs.replace(/\.prototype\.?/g, "#");
+                            inAs = inAs.replace(/^this\.?/, "#");
+                        }
+
+                        if (inAs.indexOf(inAlias) != 0) { //not a full namepath
+                            var joiner = ".";
+                            if (this.alias.charAt(this.alias.length-1) == "#" || inAs.charAt(0) == "#") {
+                                joiner = "";
+                            }
+                            inAs = this.alias + joiner + inAs;
+                        }
+                    }
+                    this.inherits.push({alias: inAlias, as: inAs});
+                }
+            }
+            
+            /*~t
+                // todo
+            */
+
+            // @augments
+            this.augments = this.comment.getTag("augments");
+            
+            //@extends - Ext
+            if (this.comment.getTag("extends")) {   
+                this.augments = this.comment.getTag("extends");
+            }
+            
+            
+            // @default
+            var defaults = this.comment.getTag("default");
+            if (defaults.length) {
+                if (this.is("OBJECT")) {
+                    this.defaultValue = defaults[0].desc;
+                }
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @memberOf
+            var memberOfs = this.comment.getTag("memberOf");
+            if (memberOfs.length) {
+                this.memberOf = memberOfs[0].desc;
+                this.memberOf = this.memberOf.replace(/\.prototype\.?/g, "#");
+            }
+
+            /*~t
+                // todo
+            */
+            
+            // @public
+            if (this.comment.getTag("public").length) {
+                this.isPrivate = false;
+            }
+            
+            /*~t
+                // todo
+            */
+        },
+
+        is : function(what) {
+            return this.isa === what;
+        },
+
+        isBuiltin : function() {
+            return SymbolSet.isBuiltin(this.alias);
+        },
+
+        setType : function(/**String*/comment, /**Boolean*/overwrite) {
+            if (!overwrite && this.type) return;
+            var typeComment = DocComment.unwrapComment(comment);
+            this.type = typeComment;
+        },
+
+        inherit : function(symbol) {
+            if (!this.hasMember(symbol.name) && !symbol.isInner) {
+                if (symbol.is("FUNCTION"))
+                    this.methods.push(symbol);
+                else if (symbol.is("OBJECT"))
+                    this.properties.push(symbol);
+            }
+        },
+
+        hasMember : function(name) {
+            return (this.hasMethod(name) || this.hasProperty(name));
+        },
+
+        addMember : function(symbol) {
+            //println("ADDMEMBER: " + this.name +  " ++ " + symbol.name);
+            
+            if (symbol.comment.getTag("cfg").length == 1) { 
+                symbol.comment.getTag("cfg")[0].memberOf = this.alias;
+                this.addConfig(symbol.comment.getTag("cfg")[0]);
+                return;
+            }
+            
+            if (symbol.is("FUNCTION")) { this.addMethod(symbol); }
+            else if (symbol.is("OBJECT")) { this.addProperty(symbol); }
+        },
+
+        hasMethod : function(name) {
+            var thisMethods = this.methods;
+            for (var i = 0, l = thisMethods.length; i < l; i++) {
+                if (thisMethods[i].name == name) return true;
+                if (thisMethods[i].alias == name) return true;
+            }
+            return false;
+        },
+
+        addMethod : function(symbol) {
+            var methodAlias = symbol.alias;
+            var thisMethods = this.methods;
+            for (var i = 0, l = thisMethods.length; i < l; i++) {
+                if (thisMethods[i].alias == methodAlias) {
+                    thisMethods[i] = symbol; // overwriting previous method
+                    return;
+                }
+            }
+            thisMethods.push(symbol); // new method with this alias
+        },
+
+        hasProperty : function(name) {
+            var thisProperties = this.properties;
+            for (var i = 0, l = thisProperties.length; i < l; i++) {
+                if (thisProperties[i].name == name) return true;
+                if (thisProperties[i].alias == name) return true;
+            }
+            return false;
+        },
+
+        addProperty : function(symbol) {
+            var propertyAlias = symbol.alias;
+            var thisProperties = this.properties;
+            for (var i = 0, l = thisProperties.length; i < l; i++) {
+                if (thisProperties[i].alias == propertyAlias) {
+                    thisProperties[i] = symbol; // overwriting previous property
+                    return;
+                }
+            }
+
+            thisProperties.push(symbol); // new property with this alias
+        },
+        
+        addDocTag : function(docTag)
+        {
+            this.comment.tags.push(docTag);
+            if (docTag.title == 'cfg') {
+                this.addConfig(docTag);
+            }
+            
+        },
+        
+        addConfig : function(docTag)
+        {
+            if (typeof(docTag['memberOf']) == 'undefined') {
+                // remove prototype data...
+                //var a = this.alias.split('#')[0];
+                //docTag.memberOf = a;
+                docTag.memberOf = this.alias;
+            }
+            if (typeof(this.cfgs[docTag.name]) == 'undefined') {
+                this.cfgs[docTag.name] = docTag;
+            }
+            
+        },
+        configToArray: function()
+        {
+            var r = [];
+            for(var ci in this.cfgs) {
+                // dont show hidden!!
+                if (this.cfgs[ci].desc.match(/@hide/)) {
+                    continue;
+                }
+                r.push(this.cfgs[ci]); 
+               
+            }
+            return r;
+          }
+});
+
+
+
+
+
+Symbol.srcFile = ""; //running reference to the current file being parsed
+
+
+Symbol.fromDump = function(t)
+{
+    var ns = new Symbol();
+    for (var i in t) {
+        if (typeof(ns[i]) == "undefined") {
+            println("ERR:no default for Symbol:"+ i);
+        }
+        ns[i] = t[i];
+    }
+    return ns;
+}
\ No newline at end of file
diff --git a/JSDOC/SymbolSet.js b/JSDOC/SymbolSet.js
new file mode 100644 (file)
index 0000000..6e2c059
--- /dev/null
@@ -0,0 +1,315 @@
+//<script type="text/javascript">
+
+XObject         = imports.XObject.XObject;
+Options         = imports.BuildDocs.Options;
+Parser          = imports.Parser.Parser;
+Symbol          = imports.Symbol.Symbol;
+DocComment      = imports.DocComment.DocComment;
+
+
+SymbolSet = XObject.define(
+    function() {
+        this.init();
+    },
+    Object,
+    {
+        
+        init : function() {
+            this._index = {};
+        },
+
+        keys : function() {
+            var found = [];
+            for (var p in this._index) {
+                found.push(p);
+            }
+            return found;
+        },
+
+
+        hasSymbol : function(alias) {
+            return this.keys().indexOf(alias) > -1;
+        },
+
+        addSymbol : function(symbol) {
+            print("ADDING SYMBOL:"+symbol.alias.toString());
+            
+            if (this.hasSymbol(symbol.alias)) {
+                Options.LOG.warn("Overwriting symbol documentation for: "+symbol.alias + ".");
+            }
+            this._index[symbol.alias] = symbol;
+        },
+
+        getSymbol : function(alias) {
+            
+            if (this.hasSymbol(alias)) return this._index[alias];
+            return false;
+        },
+
+        toArray : function() {
+            var found = [];
+            for (var p in this._index) {
+                found.push(this._index[p]);
+            }
+            return found;
+        },
+
+        deleteSymbol : function(alias) {
+            if (!this.hasSymbol(alias)) return;
+            delete this._index[alias];
+        },
+
+        renameSymbol : function(oldName, newName) {
+            // todo: should check if oldname or newname already exist
+            if (typeof(this._index[oldName]) == "undefined") {
+                throw "Cant rename " + oldName + " to " + newName + " As it doesnt exist";
+               }
+            this._index[newName] = this._index[oldName];
+            this.deleteSymbol(oldName);
+            this._index[newName].alias = newName;
+            return newName;
+        },
+
+        relate : function() {
+            this.resolveBorrows();
+            this.resolveMemberOf();
+            this.resolveAugments();
+        },
+
+        resolveBorrows : function() {
+            for (p in this._index) {
+                var symbol = this._index[p];
+                if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
+                
+                var borrows = symbol.inherits;
+                for (var i = 0; i < borrows.length; i++) {
+                    var borrowed = this.getSymbol(borrows[i].alias);
+                    if (!borrowed) {
+                        Options.LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
+                        continue;
+                    }
+                    
+                    var borrowAsName = borrows[i].as;
+                    var borrowAsAlias = borrowAsName;
+                    if (!borrowAsName) {
+                        Options.LOG.warn("Malformed @borrow, 'as' is required.");
+                        continue;
+                    }
+                    
+                    if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
+                        borrowAsName = borrowAsName.replace(borrowed.alias, "")
+                    }
+                    else {
+                        var joiner = "";
+                        if (borrowAsName.charAt(0) != "#") joiner = ".";
+                        borrowAsAlias = borrowed.alias + joiner + borrowAsName;
+                    }
+                    
+                    borrowAsName = borrowAsName.replace(/^[#.]/, "");
+                            
+                    if (this.hasSymbol(borrowAsAlias)) continue;
+
+                    var clone = borrowed.clone();
+                    clone.name = borrowAsName;
+                    clone.alias = borrowAsAlias;
+                    this.addSymbol(clone);
+                }
+            }
+        },
+
+        resolveMemberOf : function() {
+            for (var p in this._index) {
+                var symbol = this.getSymbol(p);
+                
+                if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
+                
+                // the memberOf value was provided in the @memberOf tag
+                else if (symbol.memberOf) {
+                    var parts = symbol.alias.match(new RegExp("^("+symbol.memberOf+"[.#-])(.+)$"));
+                    
+                    // like foo.bar is a memberOf foo
+                    if (parts) {
+                        symbol.memberOf = parts[1];
+                        symbol.name = parts[2];
+                    }
+                    // like bar is a memberOf foo
+                    else {
+                        var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1);
+                        if (!/[.#-]/.test(joiner)) symbol.memberOf += ".";
+                        
+                        this.renameSymbol(p, symbol.memberOf + symbol.name);
+                    }
+                }
+                // the memberOf must be calculated
+                else {
+                    var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/);
+                    if (parts) {
+                        symbol.memberOf = parts[1];
+                        symbol.name = parts[2];                                
+                    }
+                }
+
+                // set isStatic, isInner
+                if (symbol.memberOf) {
+                    switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) {
+                        case '#' :
+                            symbol.isStatic = false;
+                            symbol.isInner = false;
+                            break;
+                            
+                        case '.' :
+                            symbol.isStatic = true;
+                            symbol.isInner = false;
+                            break;
+                            
+                        case '-' :
+                            symbol.isStatic = false;
+                            symbol.isInner = true;
+                            break;
+                            
+                    }
+                }
+                
+                // unowned methods and fields belong to the global object
+                if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
+                    symbol.memberOf = "_global_";
+                }
+                
+                // clean up
+                if (symbol.memberOf.match(/[.#-]$/)) {
+                    symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1);
+                }
+                //print("looking for memberOf: " + symbol.memberOf + " FOR " + symbol.alias);
+                // add to parent's methods or properties list
+                if (symbol.memberOf) {
+                    var container = this.getSymbol(symbol.memberOf);
+                    if (!container) {
+                        if (SymbolSet.isBuiltin(symbol.memberOf)) {
+                            container = Parser.addBuiltin(symbol.memberOf);
+                        }
+                        else {
+                           // print("symbol NOT a BUILT IN - createing a container");
+                            // Eg. Ext.y.z (missing y)
+                            // we need to add in the missing symbol...
+                            container = new Symbol(symbol.memberOf, [], "OBJECT", new DocComment(""));
+                            container.isNamespace = true;
+                            this.addSymbol( container );
+                           // print(container.toSource());
+                            //container = this.getSymbol(symbol.memberOf);
+                            // fake container ... so dont ad symbols to it..
+                            continue;
+                            container = false;
+                            //LOG.warn("Can't document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
+                            //LOG.warn("We only have the following symbols: \n" + 
+                            //    this.keys.toSource());
+                        }
+                    }
+                    
+                    if (container && !container.isNamespace) container.addMember(symbol);
+                }
+            }
+        },
+
+        resolveAugments : function() {
+            // does this sort out multiple extends???
+            for (var p in this._index) {
+                var symbol = this.getSymbol(p);
+                this.buildAugmentsList(symbol); /// build heirachy of inheritance...
+                if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
+                
+                var augments = symbol.augments;
+                for(var ii = 0, il = augments.length; ii < il; ii++) {
+                    var contributer = this.getSymbol(augments[ii]);
+                    
+                    
+                    
+                    if (contributer) {
+                        contributer.childClasses.push(symbol.alias);
+                        symbol.inheritsFrom.push(contributer.alias);
+                        if (!isUnique(symbol.inheritsFrom)) {
+                            Options.LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
+                        }
+                        else {
+                            var cmethods = contributer.methods;
+                            var cproperties = contributer.properties;
+                            var cfgs = contributer.cfgs;
+                            for (var ci = 0, cl = cmethods.length; ci < cl; ci++) {   
+                                symbol.inherit(cmethods[ci]);
+                            }
+                            for (var ci = 0, cl = cproperties.length; ci < cl; ci++) {
+                                symbol.inherit(cproperties[ci]);
+                            }
+                            for (var ci in cfgs) {
+                                symbol.addConfig(cfgs[ci]);
+                            }
+                            
+                                
+                        }
+                    }
+                    else {
+                        
+                        Options.LOG.warn("Can't augment contributer: '"+augments[ii]+"', not found. FOR: " + symbol.alias);
+                        
+                        //LOG.warn("We only have the following symbols: \n" + 
+                          //      this.keys().toSource().split(",").join(",    \n"));
+                       }
+
+                }
+            }
+        },
+
+        buildAugmentsList : function(symbol)
+        {
+            // basic idea is to add all the child extends to the parent.. without looping forever..
+            
+            if (!symbol.augments.length) {
+                return;
+            }
+            
+            var _t = this;
+            print("buildAugmentsList:" + symbol.alias);
+            var addAugments = function (alist, forceit) { // returns number added..
+                if (!alist.length) {
+                    return 0;
+                }
+                print("buildAugmentsList:addAugments" + alist.length);
+                var rval = 0;
+                for(var ii = 0; ii < alist.length; ii++) {
+                    print("getAlias:" + alist[ii]);
+                    if (alist[ii] == symbol.alias) {
+                        continue;
+                    }
+                    var contributer = _t.getSymbol(alist[ii]);
+                    if (!contributer) {
+                        continue;
+                    }
+                    
+                    if (!forceit && symbol.augments.indexOf(alist[ii]) > -1) {
+                        continue;
+                    }
+                    if (symbol.augments.indexOf(alist[ii]) < 0) {
+                        symbol.augments.push(alist[ii]);
+                    }
+                        
+                    
+                    addAugments(contributer.augments,false);
+                    
+                    rval++;
+                }
+                print("buildAugmentsList: ADDED:" + rval);
+                return rval;
+            }
+            addAugments(symbol.augments, true);
+            //while(addAugments(symbol.augments) >  0) { }
+            
+        }
+})
+
+SymbolSet.isBuiltin = function(name) {
+    return (SymbolSet.isBuiltin.coreObjects.indexOf(name) > -1);
+}
+SymbolSet.isBuiltin .coreObjects = [
+    '_global_', 'Array', 'Boolean', 'Date', 'Function', 
+    'Math', 'Number', 'Object', 'RegExp', 'String'
+];
\ No newline at end of file
diff --git a/JSDOC/Walker2.js b/JSDOC/Walker2.js
new file mode 100644 (file)
index 0000000..db484bf
--- /dev/null
@@ -0,0 +1,886 @@
+//<Script type="text/javascript">
+XObject      = imports.XObject.XObject;
+
+Scope        = imports.Scope.Scope;
+DocComment   = imports.DocComment.DocComment;
+Symbol       = imports.Symbol.Symbol;
+Parser       = imports.Parser.Parser;
+
+/**
+* Scope stuff
+* 
+* // FIXME - I need this to do next() without doccomments..
+*/
+
+Walker2 = XObject.define(
+    function(ts) {
+        this.ts = ts;
+        this.warnings = [];
+        this.scopes = [];
+        this.indexedScopes = {};
+        this.symbols = {};
+        //this.timer = new Date() * 1;
+       
+    },
+    Object,
+    
+    {
+    /*
+        timer: 0,
+        timerPrint: function (str) {
+            var ntime = new Date() * 1;
+            var tdif =  ntime -this.timer;
+            this.timer = ntime;
+            var pref = '';
+            if (tdif > 100) { //slower ones..
+                pref = '***';
+            }
+            print(pref+'['+tdif+']'+str);
+            
+        },
+        */
+        warn: function(s) {
+            //this.warnings.push(s);
+            print("WARNING:" + htmlescape(s) + "<BR>");
+        },
+        // defaults should not be initialized here =- otherwise they get duped on new, rather than initalized..
+        warnings : false,
+        ts : false,
+        scopes : false,
+        global : false,
+        mode : "", //"BUILDING_SYMBOL_TREE",
+        braceNesting : 0,
+        indexedScopes : false,
+        munge: true,
+        symbols: false, /// object store of sumbols..
+
+
+
+
+        buildSymbolTree : function()
+        {
+            //print("<PRE>");
+            
+            this.ts.rewind();
+            this.braceNesting = 0;
+            this.scopes = [];
+            this.aliases = {};
+             
+            this.globalScope = new Scope(-1, false, -1, '$global$');
+            indexedScopes = { 0 : this.globalScope };
+            
+            this.mode = 'BUILDING_SYMBOL_TREE';
+            this.parseScope(this.globalScope);
+        },
+        
+
+
+        log : function(str)
+        {
+              //print("<B>LOG:</B>" + htmlescape(str) + "<BR/>\n");
+        },
+        logR : function(str)
+        {
+                //print("<B>LOG:</B>" + str + "<BR/>");
+        },
+
+       
+        currentDoc: false,
+
+
+        parseScope : function(scope, ealiases) // parse a token stream..
+        {
+            //this.timerPrint("parseScope EnterScope"); 
+            
+            var aliases = {};
+            var fixAlias = function(str, nomore)
+            {
+                var ar = str.split('.');
+                var m = ar.shift();
+                
+                //print(str +"?=" +aliases.toSource());
+                if (aliases[m] == undefined) {
+                    return str;
+                }
+                var ret = aliases[m] + (ar.length? '.' : '' )+ ar.join('.');
+                if (nomore !== true) {
+                    ret = fixAlias(ret, true);
+                }
+                
+                
+                
+                return ret;
+            };
+
+            
+            
+            if (ealiases != undefined) {
+                // copy it down..
+                for(var i in ealiases) {
+                    aliases[i] = ealiases[i];
+                }
+                
+                
+            } else {
+                ealiases = {};
+            }
+            //print("STARTING SCOPE WITH: " + ealiases.toSource());
+            var symbol;
+            var token;
+            
+            var identifier;
+
+            var expressionBraceNesting = this.braceNesting;
+            var bracketNesting = 0;
+            var parensNesting = 0;
+           
+            
+            var l1 = '', l2 = '';
+            var scopeName ='';
+            
+            
+            var locBraceNest = 0;
+            // determines if we are in object literals...
+            
+            var isObjectLitAr = [ false ];
+            //print("SCOPE: ------------------START ----------------");
+            this.scopesIn(scope);
+            var scopeLen = this.scopes.length;
+            
+            if (this.ts.cursor < 1) {
+              // this.ts.cursor--; // hopeflly this kludge will work
+            }
+            
+            
+            //print(JSON.stringify(this.ts, null, 4)); Seed.quit();
+            
+            while (null != (token = this.ts.next())) {
+                //print("TOK"+ token.toString());
+                //  this.timerPrint("parseScope AFTER lookT: " + token.toString()); 
+                  
+                if (token.is('WHIT')) {
+                      
+                 
+                    if (!token._isDoc) {
+                        continue; //skip.
+                    }
+                    if (this.currentDoc) {
+                        // add it to the current scope????
+                        
+                        this.addSymbol('', true);
+
+                        
+                        //throw "Unconsumed Doc (TOKwhitespace): " + this.currentDoc.toSource();
+                    }
+                    
+                    
+                    var newDoc = new DocComment(token.data);
+                    
+                    // it's a scope changer..
+                    if (newDoc.getTag("scope").length) {
+                        //print(newDoc.getTag("scope").toSource());
+                        //throw "done";
+                        scope.ident = '$private$|' + newDoc.getTag("scope")[0].desc;
+                        continue;
+                    }
+                    
+                    // it's a scope changer..
+                    if (newDoc.getTag("scopeAlias").length) {
+                        //print(newDoc.getTag("scopeAlias").toSource());
+                        // @scopeAlias a=b
+                        var sal = newDoc.getTag("scopeAlias")[0].desc.split("=");
+                        aliases[sal[0]] = sal[1];
+                        
+                        continue;
+                    }
+                    
+                    
+                    /// got a  doc comment..
+                    //token.data might be this.??? (not sure though)
+                    this.currentDoc = newDoc;
+                    continue;
+                }
+                
+                // catch the various issues .. - scoe changes or doc actions..
+                
+              
+                
+                // things that stop comments carrying on...??
+                
+                if (this.currentDoc && (
+                        token.tokN.data == ';' || 
+                        token.tokN.data == '}')) {
+                    this.addSymbol('', true);
+                    //throw "Unconsumed Doc ("+ token.toString() +"): " + this.currentDoc.toSource();
+                }
+                    
+                
+                // the rest are scoping issues...
+                
+                // var a = b;
+                
+                 if (token.name == 'VAR' &&
+                 
+                        this.ts.lookTok(1).type == 'NAME' &&
+                        this.ts.lookTok(2).data == '-' &&
+                        this.ts.lookTok(3).type == 'NAME'  &&
+                        this.ts.lookTok(4).data == ';'  
+                        
+                 
+                 ) {
+                    //print("SET ALIAS:" + this.ts.lookTok(1).data +'=' + this.ts.lookTok(3).data);
+                     
+                    aliases[this.ts.lookTok(1).data] = this.ts.lookTok(3).data;
+                    
+                
+                }
+                
+                
+              
+                // extends scoping  *** not sure if the can be x = Roo.apply(....)
+                // xxx.extends(a,b, {
+                    // $this$=b|b.prototype
+                // xxx.apply(a, {
+                    // a  << scope
+                // xxx.applyIf(a, {
+                    // a  << scope
+                if (token.type = 'NAME') {
+                    
+                    //print("TOK(ident)"+ token.toString());
+                    
+                    
+                       
+                    
+                    
+                    if (/\.extend$/.test(token.data) &&
+                        this.ts.lookTok(1).data == '(' &&
+                        this.ts.lookTok(2).type == 'NAME' &&
+                        this.ts.lookTok(3).data == ',' &&
+                        this.ts.lookTok(4).type == 'NAME' &&
+                        this.ts.lookTok(5).data == ',' &&
+                        this.ts.lookTok(6).data == '{' 
+                           
+                        ) {
+                        // ignore test for ( a and ,
+                        this.ts.nextTok(); /// (
+                        token = this.ts.nextTok(); // a
+                        scopeName = token.data;
+                        
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+
+                        }
+                        this.ts.nextTok(); // ,
+                        this.ts.nextTok(); // b
+                        
+                        
+                        this.ts.nextTok(); // ,
+                        token = this.ts.nextTok(); // {
+                            
+                        scopeName = fixAlias(scopeName);
+                        
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                            '$this$=' + scopeName  + '|'+scopeName+'.prototype');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                       
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..
+                        
+                    }
+                    
+                    // a = Roo.extend(parentname, {
+                        
+                     if (/\.extend$/.test(token.data) &&
+                        this.ts.lookTok(-2).type == 'NAME'  &&
+                        this.ts.lookTok(-1).data == '=' &&
+                        this.ts.lookTok(1).data == '(' &&
+                        this.ts.lookTok(2).type == 'NAME' &&
+                        this.ts.lookTok(3).data == ',' &&
+                        this.ts.lookTok(4).data == '{' 
+                        ) {
+                        // ignore test for ( a and ,
+                        token = this.ts.lookTok(-2);
+                        scopeName = token.data;
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+
+                        }
+                        this.ts.nextTok(); /// (
+                        this.ts.nextTok(); // parent
+                        
+                        this.ts.nextTok(); // ,
+                        token =  this.ts.nextTok(); // {
+                             
+                        
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                            '$this$=' + scopeName  + '|'+scopeName+'.prototype');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                       
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..
+                        
+                    }
+                    
+                    
+                     // apply ( XXXX,  {
+                         
+                    if (/\.(applyIf|apply)$/.test(token.data) && 
+                        this.ts.lookTok(1).data == '('  &&
+                        this.ts.lookTok(2).type == 'NAME' &&
+                        this.ts.lookTok(3).data == ','  &&
+                        this.ts.lookTok(4).data == '{' 
+                        
+                        ) {
+                        this.ts.nextTok(); /// (
+                         
+                        //print("GOT : applyIF!"); 
+                         
+                        token = this.ts.nextTok(); // b
+                        scopeName = token.data;
+                        
+                                      
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+
+                        }
+                     
+
+                        
+                        this.ts.nextTok(); /// ,
+                        this.ts.nextTok(); // {
+                            scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                         
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..
+                    }
+                    
+                    
+                    // xxx = new yyy ( {
+                        
+                    // change scope to xxxx
+                    
+                    if ( this.ts.lookTok(1).data == '=' &&
+                        this.ts.lookTok(2).name == 'NEW' &&
+                        this.ts.lookTok(3).type == 'NAME' &&
+                        this.ts.lookTok(4).data == '(' &&
+                        this.ts.lookTok(5).data == '{' 
+                        ) {
+                        scopeName = token.data;
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+                            
+                        }
+                        
+                        this.ts.nextTok(); /// =
+                        this.ts.nextTok(); /// new
+                        this.ts.nextTok(); /// yyy
+                        this.ts.nextTok(); /// (
+                        this.ts.nextTok(); /// {
+                            
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                         
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        
+                        continue; // no more processing..
+                    }
+                    
+
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    // eval can be prefixed with a hint hider for the compresser..
+                    if ((token.data == 'eval') || /\.eval$/.test(token.data)) {
+                        this.currentDoc = false;
+                        continue;
+                    }
+                    
+                    if (this.currentDoc) {
+                        //print(token.toString());
+                        
+                        // ident : function ()
+                        // ident = function ()
+                        var atype = 'OBJECT';
+                        
+                        if (((this.ts.lookTok(1).data == ':' )|| (this.ts.lookTok(1).data == '=')) &&
+                            (this.ts.lookTok(2).name == "FUNCTION")
+                            ) {
+                                atype = 'FUNCTION';
+                        }
+                        
+                        //print("ADD SYM:" + atype + ":" + token.toString() + this.ts.lookTok(1).toString() + this.ts.lookTok(2).toString());
+                        
+                        this.addSymbol(
+                            this.ts.lookTok(-1).tokN == Script.TOKdot ? token.data :    fixAlias(token.data),
+                            false,
+                            atype);
+                        
+                    }
+                 
+                    
+                    continue; // dont care about other idents..
+                    
+                }        
+                if (token.type == "STRN")   {
+                    if (this.currentDoc) {
+                        this.addSymbol(token.data.substring(1,token.data.length-1),false,'OBJECT');
+
+                    }
+                }
+            
+                // really we only have to deal with object constructs and function calls that change the scope...
+                
+                
+                 if (token.name == 'FUNCTION') {
+                     
+                    // see if we have an unconsumed doc...
+                    
+                    if (this.currentDoc) {
+                            print(this.ts.dumpToCur());
+                            throw "Unhandled doc (TOKfunction)" + token.toString();
+                            //this.addSymbol(this.currentDoc.getTag('class')[0].name, true);
+
+                            //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
+                    }
+                    
+                     
+                     
+                     
+                     
+                    /// foo = function() {} << really it set's the 'this' scope to foo.prototype
+                    //$this$=foo.prototype|$private$|foo.prototype
+        
+                    if (
+                            (this.ts.lookTok(-1).data == '=') && 
+                            (this.ts.lookTok(-2).type == 'NAME')
+                        ) {
+                        scopeName = this.ts.lookTok(-2).data;
+                        this.ts.balanceN('(');
+                        token = this.ts.nextTok(); // should be {
+                        //print("FOO=FUNCITON() {}" + this.ts.context() + "\n" + token.toString());
+                        
+                        
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                            '$this$='+scopeName+'.prototype|$private$|'+scopeName+'.prototype');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                        this.parseScope(fnScope, aliases);
+                        
+                        
+                       
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                        
+                    }
+                        
+                
+                // foo = new function() {}
+                        // is this actually used much!?!?!
+                        //$private$
+                        
+                    if (
+                            (this.ts.lookTok(-1).name == 'NEW') && 
+                            (this.ts.lookTok(-2).data == '=') &&
+                            (this.ts.lookTok(-3).type = 'FUNCTION')
+                        ) {
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balanceN(Script.TOKlparen);
+                        token = this.ts.nextTok(); // should be {
+                            scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                        this.parseScope(fnScope, aliases);
+                        
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                        
+                    }    
+                   
+                    
+    ///==== check/set isObjectLitAr ??                
+                    
+                    
+                 // foo: function() {}
+                        // no change to scoping..
+                        
+                    //print("checking for : function() {"); 
+                    //print( [this.ts.lookTok(-3).type , this.ts.lookTok(-2).type , this.ts.lookTok(-1).type ].join(":"));
+                    if (
+                            (this.ts.lookTok(-1).data == ':') && 
+                            (this.ts.lookTok(-2).type == 'NAME') &&
+                            (this.ts.lookTok(-3).data == '(' || this.ts.lookTok(-3).data== ',') 
+                        ) {
+                        //print("got for : function() {"); 
+                            
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balanceN(Script.TOKlparen);
+                        //print(token.toString())
+                        token = this.ts.nextTok(); // should be {
+                        //print(token.toString())
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                         this.parseScope(fnScope, aliases);
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                    } 
+               /// function foo() {} << really it set's the 'this' scope to foo.prototype
+                        //$this$=foo|$private$
+                        //$this$=foo
+                        
+                    if (
+                            (this.ts.lookTok(1).type == 'NAME') 
+                        ) {
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balanceN('(');
+                        token = this.ts.nextTok(); // should be {
+                            
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                        this.parseScope(fnScope, aliases);
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                    }
+                    
+                     
+                // foo = new (function() { }
+                // (function() { }
+                // RETURN function(...) {
+                    
+                    if (
+                           // (this.ts.lookTok(-1).tokN == Script.TOKlparen) && 
+                            (this.ts.lookTok(1).name != 'NAME')   
+                            
+                        //    (this.ts.lookTok(-2).tokN == Script.TOKnew) &&
+                         //   (this.ts.lookTok(-3).tokN == Script.TOKassign) &&
+                         //   (this.ts.lookTok(-4).tokN == Script.TOKidentifier)
+                        ) {
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balanceN('(');
+                        token = this.ts.nextTok(); // should be {
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = ;
+                        //this.scopesIn(fnScope);
+                         this.parseScope(fnScope, aliases);
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                        
+                    }
+                    
+                    
+                    print(this.ts.context());
+                    throw "dont know how to handle function syntax??";
+                    
+                    continue;
+                    
+                    
+                    
+                    
+                } // end checking for TOKfunction
+                    
+                if (token.data == '{') {
+                    
+                     // foo = { // !var!!!
+                        //$this$=foo|Foo
+               
+                
+                    if (
+                            (this.ts.lookTok(-1).data == '=') &&
+                            (this.ts.lookTok(-2).type == 'NAME') &&
+                            (this.ts.lookTok(-3).nane != 'VAR')  
+                        ) {
+                            
+                            scopeName = this.ts.look(-2).data;
+                            scopeName = fixAlias(scopeName);
+                            var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                                '$this$='+scopeName + '|'+scopeName
+                            );
+                            this.indexedScopes[this.ts.cursor] = fnScope;
+                            scope = fnScope;
+                            this.scopesIn(fnScope);
+                            
+                              
+                            locBraceNest++;
+                            //print(">>" +locBraceNest);
+                            continue; // no more processing..   
+                    }
+                    // foo : {
+                    // ?? add |foo| ????
+                      
+                    //print("GOT LBRACE : check for :");
+                    if (
+                            (this.ts.lookTok(-1).data == ':') &&
+                            (this.ts.lookTok(-2).type == 'NAME') &&
+                            (this.ts.lookTok(-3).name != 'VAR') 
+                        ) {
+                            
+                            scopeName = this.ts.lookTok(-2).data;
+                            scopeName = fixAlias(scopeName);
+                            var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
+                            this.indexedScopes[this.ts.cursor] = fnScope;
+                            scope = fnScope;
+                            this.scopesIn(fnScope);
+                            
+                            locBraceNest++;
+                            //print(">>" +locBraceNest);
+                            continue; // no more processing..   
+                    }
+                    var fnScope = new Scope(this.braceNesting, scope, token.n, '');
+                    this.indexedScopes[this.ts.cursor] = fnScope;
+                    scope = fnScope;
+                    this.scopesIn(fnScope);
+                   
+                    locBraceNest++;
+                    //print(">>" +locBraceNest);
+                    continue;
+                    
+                }
+                if (token.data == '{') {
+                    
+                     
+                        if (this.currentDoc) {
+                            this.addSymbol('', true);
+
+                            //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
+                        }
+                        
+                       
+                        locBraceNest--;
+                        
+                            //assert braceNesting >= scope.getBraceNesting();
+                        var closescope = this.scopeOut();   
+                        scope = this.scopes[this.scopes.length-1];
+                        //print("<<:" +  locBraceNest)
+                        //print("<<<<<< " + locBraceNest );
+                        if (locBraceNest < 0) {
+                           // print("POPED OF END OF SCOPE!");
+                            ///this.scopeOut();   
+                            //var ls = this.scopeOut();
+                            //ls.getUsedSymbols();
+                            return;
+                        }
+                        continue;
+                }
+              
+                
+            }
+            
+            
+        },
+     
+         
+        addSymbol: function(lastIdent, appendIt, atype )
+        {
+            
+            /*if (!this.currentDoc.tags.length) {
+                
+              
+                //print(this.currentDoc.toSource());
+                //  this.currentDoc = false;
+                
+                print("SKIP ADD SYM: no tags");
+                print(this.currentDoc.src);
+                return;
+            }
+            */
+            if (this.currentDoc.getTag('private').length) {
+                
+              
+                //print(this.currentDoc.toSource());
+                 this.currentDoc = false;
+                print("SKIP ADD SYM:  it's private");
+                return;
+            }
+            
+            var token = this.ts.cur();
+            if (typeof(appendIt) == 'undefined') {
+                appendIt= false;
+            }
+          //  print(this.currentDoc.toSource(););
+            if (this.currentDoc.getTag('event').length) {
+                //?? why does it end up in desc - and not name/...
+                print(this.currentDoc.getTag('event')[0]);
+                lastIdent = '*' + this.currentDoc.getTag('event')[0].desc;
+                //lastIdent = '*' + lastIdent ;
+            }
+            if (!lastIdent.length && this.currentDoc.getTag('property').length) {
+                lastIdent = this.currentDoc.getTag('property')[0].name;
+                //lastIdent = '*' + lastIdent ;
+            }
+            
+            var _s = lastIdent;
+            if (!/\./.test(_s)) {
+                    
+                //print("WALKER ADDsymbol: " + lastIdent);
+                
+                var s = [];
+                for (var i = 0; i < this.scopes.length;i++) {
+                    s.push(this.scopes[i].ident);
+                }
+                s.push(lastIdent);
+                
+                var s = s.join('|').split('|');
+               print("Walker:ADDSymbol: " + s.join('|') );
+                var _t = '';
+                 _s = '';
+                
+                /// fixme - needs
+                for (var i = 0; i < s.length;i++) {
+                    
+                    if (!s[i].length) {
+                        continue;
+                    }
+                    if ((s[i] == '$private$') || (s[i] == '$global$')) {
+                        _s = '';
+                        continue;
+                    }
+                    if (s[i].substring(0,6) == '$this$') {
+                        var ts = s[i].split('=');
+                        _t = ts[1];
+                        continue;
+                    }
+                    // when to use $this$ (probabl for events)
+                    _s += _s.length ? '.' : '';
+                    _s += s[i];
+                }
+                    
+                
+                /// calc scope!!
+                //print("ADDING SYMBOL: "+ s.join('|') +"\n"+ _s + "\n" +Script.prettyDump(this.currentDoc.toSource()));
+                
+                if (appendIt && !lastIdent.length) {
+                    
+                    // append, and no symbol???
+                    
+                    // see if it's a @class
+                    if (this.currentDoc.getTag('class').length) {
+                        _s = this.currentDoc.getTag('class')[0].desc;
+                        var symbol = new Symbol(_s, [], "CONSTRUCTOR", this.currentDoc);
+                        Parser.addSymbol(symbol);
+                        this.symbols[_s] = symbol;
+                        return;
+                    }
+                    
+                   // if (this.currentDoc.getTag('property').length) {
+                     //   print(Script.pretStringtyDump(this.currentDoc.toSource));
+                    //    throw "Add Prop?";
+                    //}
+                    
+                    _s = _s.replace(/\.prototype.*$/, '');
+                    if (typeof(this.symbols[_s]) == 'undefined') {
+                        print("Symbol:" + _s);
+                        print(this.currentDoc.src);
+                        
+                        throw "Trying to append symbol, but no doc available";
+                    }
+                        
+                    for (var i =0; i < this.currentDoc.tags.length;i++) {
+                        this.symbols[_s].addDocTag(this.currentDoc.tags[i]);
+                    }
+                    this.currentDoc = false;
+                    return;
+                }
+            }    
+            if (typeof(this.symbols[_s]) != 'undefined') {
+                
+                if (this.symbols[_s].comment.hasTags) {
+                    // then existing comment doesnt has tags 
+                     throw "DUPLICATE Symbol " + _s;
+                }
+                // otherwise existing comment has tags - overwrite..
+                
+                
+            }
+            if (typeof(atype) == "undefined") {
+                atype = 'OBJECT'; //this.currentDoc.getTag('class').length ? 'OBJECT' : 'FUNCTION';;
+               }
+            
+            var symbol = new Symbol(_s, [], atype, this.currentDoc);
+            
+            Parser.addSymbol(symbol);
+            this.symbols[_s] = symbol;
+            
+             this.currentDoc = false;
+            
+        },
+        
+        
+        
+        
+        scopesIn : function(s)
+        {
+            this.scopes.push(s);
+            //print(">>>" + this.ts.context()  + "\n>>>"+this.scopes.length+":" +this.scopeListToStr());
+            
+        },
+        scopeOut : function()
+        {
+            
+           // print("<<<" + this.ts.context()  + "\n<<<"+this.scopes.length+":" +this.scopeListToStr());
+            return this.scopes.pop();
+            
+        },
+        
+        scopeListToStr : function()
+        {
+            var s = [];
+            for (var i = 0; i < this.scopes.length;i++) {
+                s.push(this.scopes[i].ident);
+            }
+            return  s.join('\n\t');
+            
+        }
+        
+    
+    
+     
+});
\ No newline at end of file
diff --git a/JsTemplate/Link.js b/JsTemplate/Link.js
new file mode 100644 (file)
index 0000000..9a3089d
--- /dev/null
@@ -0,0 +1,204 @@
+//<script type="text/javascript">
+
+XObject  = imports.XObject.XObject;
+
+/**
+ * Generic Template Link handler..
+ * 
+ * 
+ * 
+ */
+
+/** Handle the creation of HTML links to documented symbols.
+       @constructor
+*/
+Link = XObject.define(
+    function () {
+        this.alias = "";
+        this.src = "";
+        this.file = "";
+        this.text = "";
+        this.innerName = "";
+        this.classLink = false;
+        this.targetName = "";
+        
+        this.target = function(targetName) {
+            if (typeof(targetName) != 'undefined') this.targetName = targetName;
+            return this;
+        }
+        this.inner = function(inner) {
+            if (typeof(inner) != 'undefined') this.innerName = inner;
+            return this;
+        }
+        this.withText = function(text) {
+            if (typeof(text) != 'undefined') this.text = text;
+            return this;
+        }
+        this.toSrc = function(filename) {
+            if (typeof(filename) != 'undefined') this.src = filename;
+            return this;
+        }
+        this.toSymbol = function(alias) {
+            if (typeof(alias) != 'undefined') {
+                this.alias = new String(alias);
+            }
+            return this;
+        }
+        this.toClass = function(alias) {
+            this.classLink = true;
+            return this.toSymbol(alias);
+        }
+        this.toFile = function(file) {
+            if (typeof(file) != 'undefined') this.file = file;
+            return this;
+        }
+        
+        this.toString = function() {
+            var linkString;
+            var thisLink = this;
+
+            if (this.alias) {
+                linkString = this.alias.replace(/(^|[^a-z$0-9_#.:-])([|a-z$0-9_#.:-]+)($|[^a-z$0-9_#.:-])/i,
+                    function(match, prematch, symbolName, postmatch) {
+                        var symbolNames = symbolName.split("|");
+                        var links = [];
+                        for (var i = 0, l = symbolNames.length; i < l; i++) {
+                            thisLink.alias = symbolNames[i];
+                            links.push(thisLink._makeSymbolLink(symbolNames[i]));
+                        }
+                        return prematch+links.join("|")+postmatch;
+                    }
+                );
+            }
+            else if (this.src) {
+                linkString = thisLink._makeSrcLink(this.src);
+            }
+            else if (this.file) {
+                linkString = thisLink._makeFileLink(this.file);
+            }
+
+            return linkString;
+        }
+    }, 
+    Object,
+    {
+        
+        /** Create a link to a snother symbol. */
+        _makeSymbolLink : function(alias) {
+            
+            // look for '/' in alias..
+            if (/\//.test(alias)) {
+                var bits = alias.split('/');
+                var ret = "";
+                for(var i=0; i < bits.length; i++) {
+                    if (i > 0) {
+                        ret +="/";
+                    }
+                    ret += this._makeSymbolLink(bits[i]);
+                }
+                return ret;
+                
+            }
+            
+            
+            
+            var linkBase = Link.base+JSDOC.publish.conf.symbolsDir;
+            var linkTo = Link.symbolSet.getSymbol(alias);
+            var linkPath;
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+            
+            // is it an internal link?
+            if (alias.charAt(0) == "#") {
+                linkPath = alias;
+                fullLinkPath = alias;
+            
+            // if there is no symbol by that name just return the name unaltered
+            } else if (!linkTo) {
+                
+                if (typeof(Link.builtins[alias]) != 'undefined') {
+                    return "<a href=\""+ Link.builtins[alias]+"\""+target+">"+alias+"</a>";
+                 }
+                
+                return this.text || alias;
+            
+            
+            // it's a symbol in another file
+            } else {
+
+                if (!linkTo.is("CONSTRUCTOR") && !linkTo.isNamespace) { // it's a method or property
+                    linkPath = escape(linkTo.memberOf) || "_global_";
+                    linkPath += JSDOC.publish.conf.ext + "#" + Link.symbolNameToLinkName(linkTo);
+                }
+                else {
+                    linkPath = escape(linkTo.alias);
+                    linkPath += JSDOC.publish.conf.ext + (this.classLink? "":"#" + Link.hashPrefix + "constructor");
+                }
+                //linkPath = linkBase + linkPath;
+                fullLinkPath = linkBase + linkPath;
+            }
+            
+            var linkText = this.text || alias;
+            
+            var link = {linkPath: linkPath, linkText: linkText, fullLinkPath: fullLinkPath};
+            
+            if (typeof JSDOC.PluginManager != "undefined") {
+                JSDOC.PluginManager.run("onSymbolLink", link);
+            }
+            
+            return "<a href=\""+link.fullLinkPath+"\""+target+" roo:cls=\""+link.linkPath+"\">"+link.linkText+"</a>";
+        },
+
+
+        /** Create a link to a source file. */
+        _makeSrcLink : function(srcFilePath) {
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+                
+            // transform filepath into a filename
+            var srcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, "."); // was _
+            var lsrcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, ".");
+            var outFilePath = Link.base + JSDOC.publish.conf.srcDir + srcFile.replace(/.js$/, '') + JSDOC.publish.conf.ext;
+            
+            if (!this.text) this.text = FilePath.fileName(srcFilePath);
+            return "<a href=\""+outFilePath+"\""+target+" roo:cls=\"src/"+lsrcFile+"\">"+this.text+"</a>";
+        },
+
+        /** Create a link to a source file. */
+        _makeFileLink : function(filePath) {
+            var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
+                
+            var outFilePath =  Link.base + filePath;
+
+            if (!this.text) this.text = filePath;
+            return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
+        }
+});
+
+
+
+
+/** prefixed for hashes */
+Link.hashPrefix = "";
+
+/** Appended to the front of relative link paths. */
+Link.base = "";
+
+Link.symbolNameToLinkName = function(symbol) {
+       var linker = "";
+       if (symbol.isStatic) linker = ".";
+       else if (symbol.isInner) linker = "-";
+       
+       return Link.hashPrefix+linker+symbol.name;
+}
+
+
+Link.builtins = {
+    'Object' : 'http: