package HTML::Dojo::src;
1;
__DATA__
__CPAN_DIR__ src
__CPAN_FILE__ src/DeferredList.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.Deferred");

dojo.provide("dojo.DeferredList");


dojo.DeferredList = function (list, /*bool?*/ fireOnOneCallback, /*bool?*/ fireOnOneErrback, /*bool?*/ consumeErrors, /*Function?*/ canceller) {
    this.list = list;
    this.resultList = new Array(this.list.length);

    // Deferred init
    this.chain = [];
    this.id = this._nextId();
    this.fired = -1;
    this.paused = 0;
    this.results = [null, null];
    this.canceller = canceller;
    this.silentlyCancelled = false;
    
    if (this.list.length === 0 && !fireOnOneCallback) {
        this.callback(this.resultList);
    }
    
    this.finishedCount = 0;
    this.fireOnOneCallback = fireOnOneCallback;
    this.fireOnOneErrback = fireOnOneErrback;
    this.consumeErrors = consumeErrors;

    var index = 0;
    
    var _this = this;
    
    dojo.lang.forEach(this.list, function(d) {
        var _index = index;
        //dojo.debug("add cb/errb index "+_index);
        d.addCallback(function(r) { _this._cbDeferred(_index, true, r) });
        d.addErrback(function(r) { _this._cbDeferred(_index, false, r) });
        index++;
    });
                      
};


dojo.inherits(dojo.DeferredList, dojo.Deferred);

dojo.lang.extend(dojo.DeferredList, {

    _cbDeferred: function (index, succeeded, result) {
        //dojo.debug("Fire "+index+" succ "+succeeded+" res "+result);
        this.resultList[index] = [succeeded, result];
        this.finishedCount += 1;
        if (this.fired !== 0) {
            if (succeeded && this.fireOnOneCallback) {
                this.callback([index, result]);
            } else if (!succeeded && this.fireOnOneErrback) {
                this.errback(result);
            } else if (this.finishedCount == this.list.length) {
                this.callback(this.resultList);
            }
        }
        if (!succeeded && this.consumeErrors) {
            result = null;
        }
        return result;
    },
    
    gatherResults: function (deferredList) {
        var d = new dojo.DeferredList(deferredList, false, true, false);
        d.addCallback(function (results) {
            var ret = [];
            for (var i = 0; i < results.length; i++) {
                ret.push(results[i][1]);
            }
            return ret;
        });
        return d;
    }
});


__CPAN_FILE__ src/ns.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.ns");

dojo.ns = {
	// summary: private object that implements widget namespace management
	namespaces: {},
	failed: {},
	loading: {},
	loaded: {},
	register: function(/*String*/name, /*String*/module, /*Function?*/resolver, /*Boolean?*/noOverride){
		// summary: creates and registers a dojo.ns.Ns object
		if(!noOverride || !this.namespaces[name]){
			this.namespaces[name] = new dojo.ns.Ns(name, module, resolver);
		}
	},
	allow: function(/*String*/name){
		// summary: Returns false if 'name' is filtered by configuration or has failed to load, true otherwise
		if(this.failed[name]){return false;} // Boolean
		if((djConfig.excludeNamespace)&&(dojo.lang.inArray(djConfig.excludeNamespace, name))){return false;} // Boolean
		// If the namespace is "dojo", or the user has not specified allowed namespaces return true.
		// Otherwise, if the user has specifically allowed this namespace, return true, otherwise false.
		return((name==this.dojo)||(!djConfig.includeNamespace)||(dojo.lang.inArray(djConfig.includeNamespace, name))); // Boolean
	},
	get: function(/*String*/name){
		// summary
		//  Return Ns object registered to 'name', if any
		return this.namespaces[name]; // Ns
	},
	require: function(/*String*/name){
		// summary
  	//  Try to ensure that 'name' is registered, loading a namespace manifest if necessary
		var ns = this.namespaces[name];
		if((ns)&&(this.loaded[name])){return ns;} // Ns
		if(!this.allow(name)){return false;} // Boolean
 		if(this.loading[name]){
			// FIXME: do we really ever have re-entrancy situation? this would appear to be really bad
			// original code did not throw an exception, although that seems the only course
			// adding debug output here to track if this occurs.
			dojo.debug('dojo.namespace.require: re-entrant request to load namespace "' + name + '" must fail.'); 
			return false; // Boolean
		}
		// workaround so we don't break the build system
		var req = dojo.require;
		this.loading[name] = true;
		try {
			//dojo namespace file is always in the Dojo namespaces folder, not any custom folder
			if(name=="dojo"){
				req("dojo.namespaces.dojo");
			}else{
				// if no registered module prefix, use ../<name> by convention
				if(!dojo.hostenv.moduleHasPrefix(name)){
					dojo.registerModulePath(name, "../" + name);
				}
				req([name, 'manifest'].join('.'), false, true);
			}
			if(!this.namespaces[name]){
				this.failed[name] = true; //only look for a namespace once
			}
		}finally{
			this.loading[name]=false;
		}
		return this.namespaces[name]; // Ns
	}
}

dojo.ns.Ns = function(/*String*/name, /*String*/module, /*Function?*/resolver){
	// summary: this object simply encapsulates namespace data
	this.name = name;
	this.module = module;
	this.resolver = resolver;
	this._loaded = [ ];
	this._failed = [ ];
}

dojo.ns.Ns.prototype.resolve = function(/*String*/name, /*String*/domain, /*Boolean?*/omitModuleCheck){
	//summary: map component with 'name' and 'domain' to a module via namespace resolver, if specified
	if(!this.resolver || djConfig["skipAutoRequire"]){return false;} // Boolean
	var fullName = this.resolver(name, domain);
	//only load a widget once. This is a quicker check than dojo.require does
	if((fullName)&&(!this._loaded[fullName])&&(!this._failed[fullName])){
		//workaround so we don't break the build system
		var req = dojo.require;
		req(fullName, false, true); //omit the module check, we'll do it ourselves.
		if(dojo.hostenv.findModule(fullName, false)){
			this._loaded[fullName] = true;
		}else{
			if(!omitModuleCheck){dojo.raise("dojo.ns.Ns.resolve: module '" + fullName + "' not found after loading via namespace '" + this.name + "'");} 
			this._failed[fullName] = true;
		}
	}
	return Boolean(this._loaded[fullName]); // Boolean
}

dojo.registerNamespace = function(/*String*/name, /*String*/module, /*Function?*/resolver){
	// summary: maps a module name to a namespace for widgets, and optionally maps widget names to modules for auto-loading
	// description: An unregistered namespace is mapped to an eponymous module.
	//	For example, namespace acme is mapped to module acme, and widgets are
	//	assumed to belong to acme.widget. If you want to use a different widget
	//	module, use dojo.registerNamespace.
	dojo.ns.register.apply(dojo.ns, arguments);
}

dojo.registerNamespaceResolver = function(/*String*/name, /*Function*/resolver){
	// summary: a resolver function maps widget names to modules, so the
	//	widget manager can auto-load needed widget implementations
	//
	// description: The resolver provides information to allow Dojo
	//	to load widget modules on demand. When a widget is created,
	//	a namespace resolver can tell Dojo what module to require
	//	to ensure that the widget implementation code is loaded.
	//
	// name: will always be lower-case.
	//
	// example:
	//  dojo.registerNamespaceResolver("acme",
	//    function(name){ 
	//      return "acme.widget."+dojo.string.capitalize(name);
	//    }
	//  );
	var n = dojo.ns.namespaces[name];
	if(n){
		n.resolver = resolver;
	}
}

dojo.registerNamespaceManifest = function(/*String*/module, /*String*/path, /*String*/name, /*String*/widgetModule, /*Function?*/resolver){
	// summary: convenience function to register a module path, a namespace, and optionally a resolver all at once.
	dojo.registerModulePath(name, path);
	dojo.registerNamespace(name, widgetModule, resolver);
}

// NOTE: rather put this in dojo.widget.Widget, but that fubars debugAtAllCosts
dojo.registerNamespace("dojo", "dojo.widget");

__CPAN_FILE__ src/date.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.date");

dojo.deprecated("dojo.date", "use one of the modules in dojo.date.* instead", "0.5");

__CPAN_FILE__ src/Deferred.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.Deferred");
dojo.require("dojo.lang.func");

dojo.Deferred = function(/* optional */ canceller){
	/*
	NOTE: this namespace and documentation are imported wholesale 
		from MochiKit

	Encapsulates a sequence of callbacks in response to a value that
	may not yet be available.  This is modeled after the Deferred class
	from Twisted <http://twistedmatrix.com>.

	Why do we want this?  JavaScript has no threads, and even if it did,
	threads are hard.  Deferreds are a way of abstracting non-blocking
	events, such as the final response to an XMLHttpRequest.

	The sequence of callbacks is internally represented as a list
	of 2-tuples containing the callback/errback pair.  For example,
	the following call sequence::

		var d = new Deferred();
		d.addCallback(myCallback);
		d.addErrback(myErrback);
		d.addBoth(myBoth);
		d.addCallbacks(myCallback, myErrback);

	is translated into a Deferred with the following internal
	representation::

		[
			[myCallback, null],
			[null, myErrback],
			[myBoth, myBoth],
			[myCallback, myErrback]
		]

	The Deferred also keeps track of its current status (fired).
	Its status may be one of three things:

		-1: no value yet (initial condition)
		0: success
		1: error

	A Deferred will be in the error state if one of the following
	three conditions are met:

		1. The result given to callback or errback is "instanceof" Error
		2. The previous callback or errback raised an exception while
		   executing
		3. The previous callback or errback returned a value "instanceof"
			Error

	Otherwise, the Deferred will be in the success state.  The state of
	the Deferred determines the next element in the callback sequence to
	run.

	When a callback or errback occurs with the example deferred chain,
	something equivalent to the following will happen (imagine that
	exceptions are caught and returned)::

		// d.callback(result) or d.errback(result)
		if(!(result instanceof Error)){
			result = myCallback(result);
		}
		if(result instanceof Error){
			result = myErrback(result);
		}
		result = myBoth(result);
		if(result instanceof Error){
			result = myErrback(result);
		}else{
			result = myCallback(result);
		}

	The result is then stored away in case another step is added to the
	callback sequence.	Since the Deferred already has a value available,
	any new callbacks added will be called immediately.

	There are two other "advanced" details about this implementation that
	are useful:

	Callbacks are allowed to return Deferred instances themselves, so you
	can build complicated sequences of events with ease.

	The creator of the Deferred may specify a canceller.  The canceller
	is a function that will be called if Deferred.cancel is called before
	the Deferred fires.	 You can use this to implement clean aborting of
	an XMLHttpRequest, etc.	 Note that cancel will fire the deferred with
	a CancelledError (unless your canceller returns another kind of
	error), so the errbacks should be prepared to handle that error for
	cancellable Deferreds.

	*/
	
	this.chain = [];
	this.id = this._nextId();
	this.fired = -1;
	this.paused = 0;
	this.results = [null, null];
	this.canceller = canceller;
	this.silentlyCancelled = false;
};

dojo.lang.extend(dojo.Deferred, {
	getFunctionFromArgs: function(){
		var a = arguments;
		if((a[0])&&(!a[1])){
			if(dojo.lang.isFunction(a[0])){
				return a[0];
			}else if(dojo.lang.isString(a[0])){
				return dj_global[a[0]];
			}
		}else if((a[0])&&(a[1])){
			return dojo.lang.hitch(a[0], a[1]);
		}
		return null;
	},

	makeCalled: function() {
		var deferred = new dojo.Deferred();
		deferred.callback();
		return deferred;
	},

	repr: function(){
		var state;
		if(this.fired == -1){
			state = 'unfired';
		}else if(this.fired == 0){
			state = 'success';
		} else {
			state = 'error';
		}
		return 'Deferred(' + this.id + ', ' + state + ')';
	},

	toString: dojo.lang.forward("repr"),

	_nextId: (function(){
		var n = 1;
		return function(){ return n++; };
	})(),

	cancel: function(){
		/***
		Cancels a Deferred that has not yet received a value, or is
		waiting on another Deferred as its value.

		If a canceller is defined, the canceller is called. If the
		canceller did not return an error, or there was no canceller,
		then the errback chain is started with CancelledError.
		***/
		if(this.fired == -1){
			if (this.canceller){
				this.canceller(this);
			}else{
				this.silentlyCancelled = true;
			}
			if(this.fired == -1){
				this.errback(new Error(this.repr()));
			}
		}else if(	(this.fired == 0)&&
					(this.results[0] instanceof dojo.Deferred)){
			this.results[0].cancel();
		}
	},
			

	_pause: function(){
		// Used internally to signal that it's waiting on another Deferred
		this.paused++;
	},

	_unpause: function(){
		// Used internally to signal that it's no longer waiting on
		// another Deferred.
		this.paused--;
		if ((this.paused == 0) && (this.fired >= 0)) {
			this._fire();
		}
	},

	_continue: function(res){
		// Used internally when a dependent deferred fires.
		this._resback(res);
		this._unpause();
	},

	_resback: function(res){
		// The primitive that means either callback or errback
		this.fired = ((res instanceof Error) ? 1 : 0);
		this.results[this.fired] = res;
		this._fire();
	},

	_check: function(){
		if(this.fired != -1){
			if(!this.silentlyCancelled){
				dojo.raise("already called!");
			}
			this.silentlyCancelled = false;
			return;
		}
	},

	callback: function(res){
		/*
		Begin the callback sequence with a non-error value.
		
		callback or errback should only be called once on a given
		Deferred.
		*/
		this._check();
		this._resback(res);
	},

	errback: function(res){
		// Begin the callback sequence with an error result.
		this._check();
		if(!(res instanceof Error)){
			res = new Error(res);
		}
		this._resback(res);
	},

	addBoth: function(cb, cbfn){
		/*
		Add the same function as both a callback and an errback as the
		next element on the callback sequence.	This is useful for code
		that you want to guarantee to run, e.g. a finalizer.
		*/
		var enclosed = this.getFunctionFromArgs(cb, cbfn);
		if(arguments.length > 2){
			enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2);
		}
		return this.addCallbacks(enclosed, enclosed);
	},

	addCallback: function(cb, cbfn){
		// Add a single callback to the end of the callback sequence.
		var enclosed = this.getFunctionFromArgs(cb, cbfn);
		if(arguments.length > 2){
			enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2);
		}
		return this.addCallbacks(enclosed, null);
	},

	addErrback: function(cb, cbfn){
		// Add a single callback to the end of the callback sequence.
		var enclosed = this.getFunctionFromArgs(cb, cbfn);
		if(arguments.length > 2){
			enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2);
		}
		return this.addCallbacks(null, enclosed);
		return this.addCallbacks(null, cbfn);
	},

	addCallbacks: function (cb, eb) {
		// Add separate callback and errback to the end of the callback
		// sequence.
		this.chain.push([cb, eb])
		if (this.fired >= 0) {
			this._fire();
		}
		return this;
	},

	_fire: function(){
		// Used internally to exhaust the callback sequence when a result
		// is available.
		var chain = this.chain;
		var fired = this.fired;
		var res = this.results[fired];
		var self = this;
		var cb = null;
		while (chain.length > 0 && this.paused == 0) {
			// Array
			var pair = chain.shift();
			var f = pair[fired];
			if (f == null) {
				continue;
			}
			try {
				res = f(res);
				fired = ((res instanceof Error) ? 1 : 0);
				if(res instanceof dojo.Deferred) {
					cb = function(res){
						self._continue(res);
					}
					this._pause();
				}
			}catch(err){
				fired = 1;
				res = err;
			}
		}
		this.fired = fired;
		this.results[fired] = res;
		if((cb)&&(this.paused)){
			// this is for "tail recursion" in case the dependent
			// deferred is already fired
			res.addBoth(cb);
		}
	}
});

__CPAN_FILE__ src/animation.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.animation");
dojo.require("dojo.animation.Animation");

dojo.deprecated("dojo.animation is slated for removal in 0.5; use dojo.lfx instead.", "0.5");

__CPAN_FILE__ src/behavior.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.behavior");
dojo.require("dojo.event.*");

dojo.require("dojo.experimental");
dojo.experimental("dojo.behavior");

dojo.behavior = new function(){
	function arrIn(obj, name){
		if(!obj[name]){ obj[name] = []; }
		return obj[name];
	}

	function forIn(obj, scope, func){
		var tmpObj = {};
		for(var x in obj){
			if(typeof tmpObj[x] == "undefined"){
				if(!func){
					scope(obj[x], x);
				}else{
					func.call(scope, obj[x], x);
				}
			}
		}
	}

	// FIXME: need a better test so we don't exclude nightly Safari's!
	this.behaviors = {};
	this.add = function(behaviorObj){
		/*	behavior objects are specified in the following format:
		 *
		 *	{ 
		 *	 	"#id": {
		 *			"found": function(element){
		 *				// ...
		 *			},
		 *
		 *			"onblah": {targetObj: foo, targetFunc: "bar"},
		 *
		 *			"onblarg": "/foo/bar/baz/blarg",
		 *
		 *			"onevent": function(evt){
		 *			},
		 *
		 *			"onotherevent: function(evt){
		 *				// ...
		 *			}
		 *		},
		 *
		 *		"#id2": {
		 *			// ...
		 *		},
		 *
		 *		"#id3": function(element){
		 *			// ...
		 *		},
		 *
		 *		// publish the match on a topic
		 *		"#id4": "/found/topic/name",
		 *
		 *		// match all direct descendants
		 *		"#id4 > *": function(element){
		 *			// ...
		 *		},
		 *
		 *		// match the first child node that's an element
		 *		"#id4 > @firstElement": { ... },
		 *
		 *		// match the last child node that's an element
		 *		"#id4 > @lastElement":  { ... },
		 *
		 *		// all elements of type tagname
		 *		"tagname": {
		 *			// ...
		 *		},
		 *
		 *		// maps to roughly:
		 *		//	dojo.lang.forEach(body.getElementsByTagName("tagname1"), function(node){
		 *		//		dojo.lang.forEach(node.getElementsByTagName("tagname2"), function(node2){
		 *		//			dojo.lang.forEach(node2.getElementsByTagName("tagname3", function(node3){
		 *		//				// apply rules
		 *		//			});
		 *		//		});
		 *		//	});
		 *		"tagname1 tagname2 tagname3": {
		 *			// ...
		 *		},
		 *
		 *		".classname": {
		 *			// ...
		 *		},
		 *
		 *		"tagname.classname": {
		 *			// ...
		 *		},
		 *	}
		 *
		 *	The "found" method is a generalized handler that's called as soon
		 *	as the node matches the selector. Rules for values that follow also
		 *	apply to the "found" key.
		 *	
		 *	The "on*" handlers are attached with dojo.event.connect(). If the
		 *	value is not a function but is rather an object, it's assumed to be
		 *	the "other half" of a dojo.event.kwConnect() argument object. It
		 *	may contain any/all properties of such a connection modifier save
		 *	for the sourceObj and sourceFunc properties which are filled in by
		 *	the system automatically. If a string is instead encountered, the
		 *	node publishes the specified event on the topic contained in the
		 *	string value.
		 *
		 *	If the value corresponding to the ID key is a function and not a
		 *	list, it's treated as though it was the value of "found".
		 *
		 */

		var tmpObj = {};
		forIn(behaviorObj, this, function(behavior, name){
			var tBehavior = arrIn(this.behaviors, name);
			if((dojo.lang.isString(behavior))||(dojo.lang.isFunction(behavior))){
				behavior = { found: behavior };
			}
			forIn(behavior, function(rule, ruleName){
				arrIn(tBehavior, ruleName).push(rule);
			});
		});
	}

	this.apply = function(){
		dojo.profile.start("dojo.behavior.apply");
		var r = dojo.render.html;
		// note, we apply one way for fast queries and one way for slow
		// iteration. So be it.
		var safariGoodEnough = (!r.safari);
		if(r.safari){
			// Anything over release #420 should work the fast way
			var uas = r.UA.split("AppleWebKit/")[1];
			if(parseInt(uas.match(/[0-9.]{3,}/)) >= 420){
				safariGoodEnough = true;
			}
		}
		if((dj_undef("behaviorFastParse", djConfig) ? (safariGoodEnough) : djConfig["behaviorFastParse"])){
			this.applyFast();
		}else{
			this.applySlow();
		}
		dojo.profile.end("dojo.behavior.apply");
	}

	this.matchCache = {};

	this.elementsById = function(id, handleRemoved){
		var removed = [];
		var added = [];
		arrIn(this.matchCache, id);
		if(handleRemoved){
			var nodes = this.matchCache[id];
			for(var x=0; x<nodes.length; x++){
				if(nodes[x].id != ""){
					removed.push(nodes[x]);
					nodes.splice(x, 1);
					x--;
				}
			}
		}
		var tElem = dojo.byId(id);
		while(tElem){
			if(!tElem["idcached"]){
				added.push(tElem);
			}
			tElem.id = "";
			tElem = dojo.byId(id);
		}
		this.matchCache[id] = this.matchCache[id].concat(added);
		dojo.lang.forEach(this.matchCache[id], function(node){
			node.id = id;
			node.idcached = true;
		});
		return { "removed": removed, "added": added, "match": this.matchCache[id] };
	}

	this.applyToNode = function(node, action, ruleSetName){
		if(typeof action == "string"){
			dojo.event.topic.registerPublisher(action, node, ruleSetName);
		}else if(typeof action == "function"){
			if(ruleSetName == "found"){
				action(node);
			}else{
				dojo.event.connect(node, ruleSetName, action);
			}
		}else{
			action.srcObj = node;
			action.srcFunc = ruleSetName;
			dojo.event.kwConnect(action);
		}
	}

	this.applyFast = function(){
		dojo.profile.start("dojo.behavior.applyFast");
		// fast DOM queries...wheeee!
		forIn(this.behaviors, function(tBehavior, id){
			var elems = dojo.behavior.elementsById(id);
			dojo.lang.forEach(elems.added, 
				function(elem){
					forIn(tBehavior, function(ruleSet, ruleSetName){
						if(dojo.lang.isArray(ruleSet)){
							dojo.lang.forEach(ruleSet, function(action){
								dojo.behavior.applyToNode(elem, action, ruleSetName);
							});
						}
					});
				}
			);
		});
		dojo.profile.end("dojo.behavior.applyFast");
	}
	
	this.applySlow = function(){
		// iterate. Ugg.
		dojo.profile.start("dojo.behavior.applySlow");
		var all = document.getElementsByTagName("*");
		var allLen = all.length;
		for(var x=0; x<allLen; x++){
			var elem = all[x];
			if((elem.id)&&(!elem["behaviorAdded"])&&(this.behaviors[elem.id])){
				elem["behaviorAdded"] = true;
				forIn(this.behaviors[elem.id], function(ruleSet, ruleSetName){
					if(dojo.lang.isArray(ruleSet)){
						dojo.lang.forEach(ruleSet, function(action){
							dojo.behavior.applyToNode(elem, action, ruleSetName);
						});
					}
				});
			}
		}
		dojo.profile.end("dojo.behavior.applySlow");
	}
}

dojo.addOnLoad(dojo.behavior, "apply");

__CPAN_FILE__ src/hostenv_adobesvg.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
 * Adobe SVG Viewer host environment
 */
if(typeof window == 'undefined'){
	dojo.raise("attempt to use adobe svg hostenv when no window object");
}

with(dojo.render){
	name = navigator.appName;
	ver = parseFloat(navigator.appVersion, 10);
	switch(navigator.platform){
		case "MacOS":
			os.osx =  true;
			break;
		case "Linux":
			os.linux =  true;
			break;
		case "Windows":
			os.win =  true;
			break;
		default:
			os.linux = true;
			break;
	};
	svg.capable = true;
	svg.support.builtin = true;
	svg.adobe = true;
};

// browserEval("alert(window.location);");

dojo.hostenv.println = function(s){
	try{
    // FIXME: this may not work with adobe's viewer, as we may first need a 
		// reference to the svgDocument
		// FIXME: need a way to determine where to position the text for this
    var ti = document.createElement("text");
    ti.setAttribute("x","50");
		var yPos = 25 + 15*document.getElementsByTagName("text").length;
    ti.setAttribute("y",yPos);
		var tn = document.createTextNode(s);
		ti.appendChild(tn);
		document.documentElement.appendChild(ti);
	}catch(e){

	}
}

dojo.debug = function() {
	if (!djConfig.isDebug) { return; }
	var args = arguments;
	if(typeof dojo.hostenv.println != 'function'){
		dojo.raise("attempt to call dojo.debug when there is no dojo.hostenv println implementation (yet?)");
	}
	var isJUM = dj_global["jum"];
	var s = isJUM ? "": "DEBUG: ";
	for(var i=0;i<args.length;++i){ s += args[i]; }
	if(isJUM){ // this seems to be the only way to get JUM to "play nice"
		jum.debug(s);
	}else{
		dojo.hostenv.println(s);
	}
}

dojo.hostenv.startPackage("dojo.hostenv");

dojo.hostenv.name_ = 'adobesvg';

dojo.hostenv.anonCtr = 0;
dojo.hostenv.anon = {};

dojo.hostenv.nameAnonFunc = function(anonFuncPtr, namespaceObj){
	var ret = "_"+this.anonCtr++;
	var nso = (namespaceObj || this.anon);
	while(typeof nso[ret] != "undefined"){
		ret = "_"+this.anonCtr++;
	}
	nso[ret] = anonFuncPtr;
	return ret;
}

dojo.hostenv.modulesLoadedFired = false;
dojo.hostenv.modulesLoadedListeners = [];
dojo.hostenv.getTextStack = [];
dojo.hostenv.loadUriStack = [];
dojo.hostenv.loadedUris = [];


dojo.hostenv.modulesLoaded = function(){
	if(this.modulesLoadedFired){ return; }
	if((this.loadUriStack.length==0)&&(this.getTextStack.length==0)){
		if(this.inFlightCount > 0){ 
			dojo.debug("couldn't initialize, there are files still in flight");
			return;
		}
		this.modulesLoadedFired = true;
		var mll = this.modulesLoadedListeners;
		for(var x=0; x<mll.length; x++){
			mll[x]();
		}
	}
}

dojo.hostenv.getNewAnonFunc = function(){
	var ret = "_"+this.anonCtr++;
	while(typeof this.anon[ret] != "undefined"){
		ret = "_"+this.anonCtr++;
	}
	// this.anon[ret] = function(){};
	eval("dojo.nostenv.anon."+ret+" = function(){};");
	return [ret, this.anon[ret]];
}

dojo.hostenv.displayStack = function(){
	var oa = [];
	var stack = this.loadUriStack;
	for(var x=0; x<stack.length; x++){
		oa.unshift([stack[x][0], (typeof stack[x][2])]);
	}
	dojo.debug("<pre>"+oa.join("\n")+"</pre>");
}

dojo.hostenv.unwindUriStack = function(){
	var stack = this.loadUriStack;
	for(var x in dojo.hostenv.loadedUris){
		for(var y=stack.length-1; y>=0; y--){
			if(stack[y][0]==x){
				stack.splice(y, 1);
			}
		}
	}
	var next = stack.pop();
	if((!next)&&(stack.length==0)){ 
		return;
	}
	for(var x=0; x<stack.length; x++){
		if((stack[x][0]==next[0])&&(stack[x][2])){
			next[2] == stack[x][2]
		}
	}
	var last = next;
	while(dojo.hostenv.loadedUris[next[0]]){
		last = next;
		next = stack.pop();
	}
	while(typeof next[2] == "string"){ // unwind as far as we can
		try{
			// dojo.debug("<pre><![CDATA["+next[2]+"]]></pre>");
			dj_eval(next[2]);
			next[1](true);
		}catch(e){
			dojo.debug("we got an error when loading "+next[0]);
			dojo.debug("error: "+e);
			// for(var x in e){ alert(x+" "+e[x]); }
		}
		dojo.hostenv.loadedUris[next[0]] = true;
		dojo.hostenv.loadedUris.push(next[0]);
		last = next;
		next = stack.pop();
		if((!next)&&(stack.length==0)){ break; }
		while(dojo.hostenv.loadedUris[next[0]]){
			last = next;
			next = stack.pop();
		}
	}
	if(next){
		stack.push(next);
		dojo.debug("### CHOKED ON: "+next[0]);
	}
}

/**
 * Reads the contents of the URI, and evaluates the contents.
 * Returns true if it succeeded. Returns false if the URI reading failed. Throws if the evaluation throws.
 * The result of the eval is not available to the caller.
 */
dojo.hostenv.loadUri = function(uri, cb){
	if(dojo.hostenv.loadedUris[uri]){
		return;
	}
	var stack = this.loadUriStack;
	stack.push([uri, cb, null]);
	var tcb = function(contents){
		// gratuitous hack for Adobe SVG 3
		if(contents.content){
			contents = contents.content;
		}

		// stack management
		var next = stack.pop();
		if((!next)&&(stack.length==0)){ 
			dojo.hostenv.modulesLoaded();
			return;
		}
		if(typeof contents == "string"){
			stack.push(next);
			for(var x=0; x<stack.length; x++){
				if(stack[x][0]==uri){
					stack[x][2] = contents;
				}
			}
			next = stack.pop();
		}
		if(dojo.hostenv.loadedUris[next[0]]){ 
			// dojo.debug("WE ALREADY HAD: "+next[0]);
			dojo.hostenv.unwindUriStack();
			return;
		}
		// push back onto stack
		stack.push(next);
		if(next[0]!=uri){
			//  and then unwind as far as we can
			if(typeof next[2] == "string"){
				dojo.hostenv.unwindUriStack();
			}

		}else{
			if(!contents){ 
				next[1](false);
			}else{
				var deps = dojo.hostenv.getDepsForEval(next[2]);
				if(deps.length>0){
					eval(deps.join(";"));
				}else{
					dojo.hostenv.unwindUriStack();
				}
			}
		}
	}
	this.getText(uri, tcb, true);
}

/**
 * Reads the contents of the URI, and evaluates the contents.
 * Returns true if it succeeded. Returns false if the URI reading failed. Throws if the evaluation throws.
 * The result of the eval is not available to the caller.
 */
dojo.hostenv.loadUri = function(uri, cb){
	if(dojo.hostenv.loadedUris[uri]){
		return;
	}
	var stack = this.loadUriStack;
	stack.push([uri, cb, null]);
	var tcb = function(contents){
		// gratuitous hack for Adobe SVG 3
		if(contents.content){
			contents = contents.content;
		}

		// stack management
		var next = stack.pop();
		if((!next)&&(stack.length==0)){ 
			dojo.hostenv.modulesLoaded();
			return;
		}
		if(typeof contents == "string"){
			stack.push(next);
			for(var x=0; x<stack.length; x++){
				if(stack[x][0]==uri){
					stack[x][2] = contents;
				}
			}
			next = stack.pop();
		}
		if(dojo.hostenv.loadedUris[next[0]]){ 
			// dojo.debug("WE ALREADY HAD: "+next[0]);
			dojo.hostenv.unwindUriStack();
			return;
		}
		// push back onto stack
		stack.push(next);
		if(next[0]!=uri){
			//  and then unwind as far as we can
			if(typeof next[2] == "string"){
				dojo.hostenv.unwindUriStack();
			}

		}else{
			if(!contents){ 
				next[1](false);
			}else{
				var deps = dojo.hostenv.getDepsForEval(next[2]);
				if(deps.length>0){
					eval(deps.join(";"));
				}else{
					dojo.hostenv.unwindUriStack();
				}
			}
		}
	}
	this.getText(uri, tcb, true);
}

/**
* loadModule("A.B") first checks to see if symbol A.B is defined. 
* If it is, it is simply returned (nothing to do).
* If it is not defined, it will look for "A/B.js" in the script root directory, followed
* by "A.js".
* It throws if it cannot find a file to load, or if the symbol A.B is not defined after loading.
* It returns the object A.B.
*
* This does nothing about importing symbols into the current package.
* It is presumed that the caller will take care of that. For example, to import
* all symbols:
*
*    with (dojo.hostenv.loadModule("A.B")) {
*       ...
*    }
*
* And to import just the leaf symbol:
*
*    var B = dojo.hostenv.loadModule("A.B");
*    ...
*
* dj_load is an alias for dojo.hostenv.loadModule
*/
dojo.hostenv.loadModule = function(modulename, exact_only, omit_module_check){
	// alert("dojo.hostenv.loadModule('"+modulename+"');");
	var module = this.findModule(modulename, 0);
	if(module){
		return module;
	}

	// dojo.debug("dojo.hostenv.loadModule('"+modulename+"');");

	// protect against infinite recursion from mutual dependencies
	if (typeof this.loading_modules_[modulename] !== 'undefined'){
		// NOTE: this should never throw an exception!! "recursive" includes
		// are normal in the course of app and module building, so blow out of
		// it gracefully, but log it in debug mode

		// dojo.raise("recursive attempt to load module '" + modulename + "'");
		dojo.debug("recursive attempt to load module '" + modulename + "'");
	}else{
		this.addedToLoadingCount.push(modulename);
	}
	this.loading_modules_[modulename] = 1;


	// convert periods to slashes
	var relpath = modulename.replace(/\./g, '/') + '.js';

	var syms = modulename.split(".");
	var nsyms = modulename.split(".");
	if(syms[0]=="dojo"){ // FIXME: need a smarter way to do this!
		syms[0] = "src"; 
	}
	var last = syms.pop();
	syms.push(last);
	// figure out if we're looking for a full package, if so, we want to do
	// things slightly diffrently
	var _this = this;
	var pfn = this.pkgFileName;
	if(last=="*"){
		modulename = (nsyms.slice(0, -1)).join('.');

		var module = this.findModule(modulename, 0);
		// dojo.debug("found: "+modulename+"="+module);
		if(module){
			_this.removedFromLoadingCount.push(modulename);
			return module;
		}

		var nextTry = function(lastStatus){
			if(lastStatus){ 
				module = _this.findModule(modulename, false); // pass in false so we can give better error
				if((!module)&&(syms[syms.length-1]!=pfn)){
					dojo.raise("Module symbol '" + modulename + "' is not defined after loading '" + relpath + "'"); 
				}
				if(module){
					_this.removedFromLoadingCount.push(modulename);
					dojo.hostenv.modulesLoaded();
					return;
				}
			}
			syms.pop();
			syms.push(pfn);
			// dojo.debug("syms: "+syms);
			relpath = syms.join("/") + '.js';
			if(relpath.charAt(0)=="/"){
				relpath = relpath.slice(1);
			}
			// dojo.debug("relpath: "+relpath);
			_this.loadPath(relpath, ((!omit_module_check) ? modulename : null), nextTry);
		}

		nextTry();
	}else{
		relpath = syms.join("/") + '.js';
		modulename = nsyms.join('.');

		var nextTry = function(lastStatus){
			// dojo.debug("lastStatus: "+lastStatus);
			if(lastStatus){ 
				// dojo.debug("inital relpath: "+relpath);
				module = _this.findModule(modulename, false); // pass in false so we can give better error
				// if(!module){
				if((!module)&&(syms[syms.length-1]!=pfn)){
					dojo.raise("Module symbol '" + modulename + "' is not defined after loading '" + relpath + "'"); 
				}
				if(module){
					_this.removedFromLoadingCount.push(modulename);
					dojo.hostenv.modulesLoaded();
					return;
				}
			}
			var setPKG = (syms[syms.length-1]==pfn) ? false : true;
			syms.pop();
			if(setPKG){
				syms.push(pfn);
			}
			relpath = syms.join("/") + '.js';
			if(relpath.charAt(0)=="/"){
				relpath = relpath.slice(1);
			}
			// dojo.debug("relpath: "+relpath);
			_this.loadPath(relpath, ((!omit_module_check) ? modulename : null), nextTry);
		}

		this.loadPath(relpath, ((!omit_module_check) ? modulename : null), nextTry);
	}
	return;
}

/**
 * Read the contents of the specified uri and return those contents.
 *
 * FIXME: Make sure this is consistent with other implementations of getText
 * @param uri A relative or absolute uri. If absolute, it still must be in the same "domain" as we are.
 * @param async_cb If not specified, returns false as synchronous is not
 * supported. If specified, load asynchronously, and use async_cb as the handler which receives the result of the request.
 * @param fail_ok Default false. If fail_ok and !async_cb and loading fails, return null instead of throwing.
 */ 
dojo.hostenv.async_cb = null;

dojo.hostenv.unWindGetTextStack = function(){
	if(dojo.hostenv.inFlightCount>0){
		setTimeout("dojo.hostenv.unWindGetTextStack()", 100);
		return;
	}
	// we serialize because this environment is too messed up
	// to know how to do anything else
	dojo.hostenv.inFlightCount++;
	var next = dojo.hostenv.getTextStack.pop();
	if((!next)&&(dojo.hostenv.getTextStack.length==0)){ 
		dojo.hostenv.inFlightCount--;
		dojo.hostenv.async_cb = function(){};
		return;
	}
	dojo.hostenv.async_cb = next[1];
	// http = window.getURL(uri, dojo.hostenv.anon[cbn]);
	window.getURL(next[0], function(result){ 
		dojo.hostenv.inFlightCount--;
		dojo.hostenv.async_cb(result.content);
		dojo.hostenv.unWindGetTextStack();
	});
}

dojo.hostenv.getText = function(uri, async_cb, fail_ok){
	// dojo.debug("Calling getText()");
	try{
		if(async_cb){
			dojo.hostenv.getTextStack.push([uri, async_cb, fail_ok]);
			dojo.hostenv.unWindGetTextStack();
		}else{
			return dojo.raise("No synchronous XMLHTTP implementation available, for uri " + uri);
		}
	}catch(e){
		return dojo.raise("No XMLHTTP implementation available, for uri " + uri);
	}
}


/**
 * Makes an async post to the specified uri.
 *
 * FIXME: Not sure that we need this, but adding for completeness.
 * More details about the implementation of this are available at 
 * http://wiki.svg.org/index.php/PostUrl
 * @param uri A relative or absolute uri. If absolute, it still must be in the same "domain" as we are.
 * @param async_cb If not specified, returns false as synchronous is not
 * supported. If specified, load asynchronously, and use async_cb as the progress handler which takes the xmlhttp object as its argument. If async_cb, this function returns null.
 * @param text Data to post
 * @param fail_ok Default false. If fail_ok and !async_cb and loading fails, return null instead of throwing.
 * @param mime_type optional MIME type of the posted data (such as "text/plain")
 * @param encoding optional encoding for data. null, 'gzip' and 'deflate' are possible values. If browser does not support binary post this parameter is ignored.
 */ 
dojo.hostenv.postText = function(uri, async_cb, text, fail_ok, mime_type, encoding){
	var http = null;
	
	var async_callback = function(httpResponse){
		if (!httpResponse.success) {
			dojo.raise("Request for uri '" + uri + "' resulted in " + httpResponse.status);
		}
		
		if(!httpResponse.content) {
			if (!fail_ok) dojo.raise("Request for uri '" + uri + "' resulted in no content");
			return null;
		}
		// FIXME: wtf, I'm losing a reference to async_cb
		async_cb(httpResponse.content);
	}
	
	try {
		if(async_cb) {
			http = window.postURL(uri, text, async_callback, mimeType, encoding);
		} else {
		return dojo.raise("No synchronous XMLHTTP post implementation available, for uri " + uri);
		}
	} catch(e) {
		return dojo.raise("No XMLHTTP post implementation available, for uri " + uri);
	}
}

/*
 * It turns out that if we check *right now*, as this script file is being loaded,
 * then the last script element in the window DOM is ourselves.
 * That is because any subsequent script elements haven't shown up in the document
 * object yet.
 */
function dj_last_script_src() {
	var scripts = window.document.getElementsByTagName('script');
	if(scripts.length < 1){ 
		dojo.raise("No script elements in window.document, so can't figure out my script src"); 
	}
	var li = scripts.length-1;
	var xlinkNS = "http://www.w3.org/1999/xlink";
	var src = null;
	var script = null;
	while(!src){
		script = scripts.item(li);
		src = script.getAttributeNS(xlinkNS,"href");
		li--;
		if(li<0){ break; }
		// break;
	}
	if(!src){
		dojo.raise("Last script element (out of " + scripts.length + ") has no src");
	}
	return src;
}

if(!dojo.hostenv["library_script_uri_"]){
	dojo.hostenv.library_script_uri_ = dj_last_script_src();
}

// dojo.hostenv.loadUri = function(uri){
	/* FIXME: adding a script element doesn't seem to be synchronous, and so
	 * checking for namespace or object existance after loadUri using this
	 * method will error out. Need to figure out some other way of handling
	 * this!
	 */
	/*
	var se = document.createElement("script");
	se.src = uri;
	var head = document.getElementsByTagName("head")[0];
	head.appendChild(se);
	// document.write("<script type='text/javascript' src='"+uri+"' />");
	return 1;
}
*/

__CPAN_FILE__ src/debug.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.debug = function(/*...*/){
	// summary:
	//		Produce a line of debug output. Does nothing unless
	//		djConfig.isDebug is true. Accepts any nubmer of args, joined with
	//		'' to produce a single line of debugging output.  Caller should not
	//		supply a trailing "\n".
	if (!djConfig.isDebug) { return; }
	var args = arguments;
	if(dj_undef("println", dojo.hostenv)){
		dojo.raise("dojo.debug not available (yet?)");
	}
	var isJUM = dj_global["jum"] && !dj_global["jum"].isBrowser;
	var s = [(isJUM ? "": "DEBUG: ")];
	for(var i=0;i<args.length;++i){
		if(!false && args[i] && args[i] instanceof Error){
			var msg = "[" + args[i].name + ": " + dojo.errorToString(args[i]) +
				(args[i].fileName ? ", file: " + args[i].fileName : "") +
				(args[i].lineNumber ? ", line: " + args[i].lineNumber : "") + "]";
		} else {
			try {
				var msg = String(args[i]);
			} catch(e) {
				if(dojo.render.html.ie) {
					var msg = "[ActiveXObject]";
				} else {
					var msg = "[unknown]";
				}
			}
		}
		s.push(msg);
	}
	
	dojo.hostenv.println(s.join(" "));
}

/**
 * this is really hacky for now - just 
 * display the properties of the object
**/

dojo.debugShallow = function(/*Object*/obj){
	// summary:
	//		outputs a "name: value" style listing of all enumerable properties
	//		in obj. Does nothing if djConfig.isDebug == false.
	// obj: the object to be enumerated
	if (!djConfig.isDebug) { return; }
	dojo.debug('------------------------------------------------------------');
	dojo.debug('Object: '+obj);
	var props = [];
	for(var prop in obj){
		try {
			props.push(prop + ': ' + obj[prop]);
		} catch(E) {
			props.push(prop + ': ERROR - ' + E.message);
		}
	}
	props.sort();
	for(var i = 0; i < props.length; i++) {
		dojo.debug(props[i]);
	}
	dojo.debug('------------------------------------------------------------');
}

dojo.debugDeep = function(/*Object*/obj){
	// summary:
	//		provides an "object explorer" view of the passed obj in a popup
	//		window.
	// obj: the object to be examined
	if (!djConfig.isDebug) { return; }
	if (!dojo.uri || !dojo.uri.dojoUri){ return dojo.debug("You'll need to load dojo.uri.* for deep debugging - sorry!"); }
	if (!window.open){ return dojo.debug('Deep debugging is only supported in host environments with window.open'); }
	var idx = dojo.debugDeep.debugVars.length;
	dojo.debugDeep.debugVars.push(obj);
	// dojo.undo.browser back and forward breaks relpaths
	var url = new dojo.uri.Uri(location, dojo.uri.dojoUri("src/debug/deep.html?var="+idx)).toString();
	var win = window.open(url, '_blank', 'width=600, height=400, resizable=yes, scrollbars=yes, status=yes');
	try{
		win.debugVar = obj;
	}catch(e){}
}
dojo.debugDeep.debugVars = [];

__CPAN_FILE__ src/hostenv_spidermonkey.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
 * SpiderMonkey host environment
 */

dojo.hostenv.name_ = 'spidermonkey';

dojo.hostenv.println = print;
dojo.hostenv.exit = function(exitcode){ 
	quit(exitcode); 
}

// version() returns 0, sigh. and build() returns nothing but just prints.
dojo.hostenv.getVersion = function(){ return version(); }

// make jsc shut up (so we can use jsc for sanity checking) 
/*@cc_on
@if (@_jscript_version >= 7)
var line2pc; var print; var load; var quit;
@end
@*/

if(typeof line2pc == 'undefined'){
	dojo.raise("attempt to use SpiderMonkey host environment when no 'line2pc' global");
}

/*
 * This is a hack that determines the current script file by parsing a generated
 * stack trace (relying on the non-standard "stack" member variable of the
 * SpiderMonkey Error object).
 * If param depth is passed in, it'll return the script file which is that far down
 * the stack, but that does require that you know how deep your stack is when you are
 * calling.
 */
function dj_spidermonkey_current_file(depth){
    var s = '';
    try{
		throw Error("whatever");
	}catch(e){
		s = e.stack;
	}
    // lines are like: bu_getCurrentScriptURI_spidermonkey("ScriptLoader.js")@burst/Runtime.js:101
    var matches = s.match(/[^@]*\.js/gi);
    if(!matches){ 
		dojo.raise("could not parse stack string: '" + s + "'");
	}
    var fname = (typeof depth != 'undefined' && depth) ? matches[depth + 1] : matches[matches.length - 1];
    if(!fname){ 
		dojo.raise("could not find file name in stack string '" + s + "'");
	}
    //print("SpiderMonkeyRuntime got fname '" + fname + "' from stack string '" + s + "'");
    return fname;
}

// call this now because later we may not be on the top of the stack
if(!dojo.hostenv.library_script_uri_){ 
	dojo.hostenv.library_script_uri_ = dj_spidermonkey_current_file(0); 
}

dojo.hostenv.loadUri = function(uri){
	// spidermonkey load() evaluates the contents into the global scope (which
	// is what we want).
	// TODO: sigh, load() does not return a useful value. 
	// Perhaps it is returning the value of the last thing evaluated?
	var ok = load(uri);
	// dojo.debug("spidermonkey load(", uri, ") returned ", ok);
	return 1;
}



__CPAN_FILE__ src/bootstrap2.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

//Semicolon is for when this file is integrated with a custom build on one line
//with some other file's contents. Sometimes that makes things not get defined
//properly, particularly with the using the closure below to do all the work.
;(function(){
	//Don't do this work if dojo.js has already done it.
	if(typeof dj_usingBootstrap != "undefined"){
		return;
	}

	var isRhino = false;
	var isSpidermonkey = false;
	var isDashboard = false;
	if((typeof this["load"] == "function")&&((typeof this["Packages"] == "function")||(typeof this["Packages"] == "object"))){
		isRhino = true;
	}else if(typeof this["load"] == "function"){
		isSpidermonkey  = true;
	}else if(window.widget){
		isDashboard = true;
	}

	var tmps = [];
	if((this["djConfig"])&&((djConfig["isDebug"])||(djConfig["debugAtAllCosts"]))){
		tmps.push("debug.js");
	}

	if((this["djConfig"])&&(djConfig["debugAtAllCosts"])&&(!isRhino)&&(!isDashboard)){
		tmps.push("browser_debug.js");
	}

	var loaderRoot = djConfig["baseScriptUri"];
	if((this["djConfig"])&&(djConfig["baseLoaderUri"])){
		loaderRoot = djConfig["baseLoaderUri"];
	}

	for(var x=0; x < tmps.length; x++){
		var spath = loaderRoot+"src/"+tmps[x];
		if(isRhino||isSpidermonkey){
			load(spath);
		} else {
			try {
				document.write("<scr"+"ipt type='text/javascript' src='"+spath+"'></scr"+"ipt>");
			} catch (e) {
				var script = document.createElement("script");
				script.src = spath;
				document.getElementsByTagName("head")[0].appendChild(script);
			}
		}
	}
})();

__CPAN_FILE__ src/loader.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
 * loader.js - A bootstrap module.  Runs before the hostenv_*.js file. Contains all of the package loading methods.
 */

//A semi-colon is at the start of the line because after doing a build, this function definition
//get compressed onto the same line as the last line in bootstrap1.js. That list line is just a
//curly bracket, and the browser complains about that syntax. The semicolon fixes it. Putting it
//here instead of at the end of bootstrap1.js, since it is more of an issue for this file, (using
//the closure), and bootstrap1.js could change in the future.
;(function(){
	//Additional properties for dojo.hostenv
	var _addHostEnv = {
		pkgFileName: "__package__",
	
		// for recursion protection
		loading_modules_: {},
		loaded_modules_: {},
		addedToLoadingCount: [],
		removedFromLoadingCount: [],
	
		inFlightCount: 0,
	
		// FIXME: it should be possible to pull module prefixes in from djConfig
		modulePrefixes_: {
			dojo: {name: "dojo", value: "src"}
		},

		setModulePrefix: function(/*String*/module, /*String*/prefix){
			// summary: establishes module/prefix pair
			this.modulePrefixes_[module] = {name: module, value: prefix};
		},

		moduleHasPrefix: function(/*String*/module){
			// summary: checks to see if module has been established
			var mp = this.modulePrefixes_;
			return Boolean(mp[module] && mp[module].value); // Boolean
		},

		getModulePrefix: function(/*String*/module){
			// summary: gets the prefix associated with module
			if(this.moduleHasPrefix(module)){
				return this.modulePrefixes_[module].value; // String
			}
			return module; // String
		},

		getTextStack: [],
		loadUriStack: [],
		loadedUris: [],
	
		//WARNING: This variable is referenced by packages outside of bootstrap: FloatingPane.js and undo/browser.js
		post_load_: false,
		
		//Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
		modulesLoadedListeners: [],
		unloadListeners: [],
		loadNotifying: false
	};
	
	//Add all of these properties to dojo.hostenv
	for(var param in _addHostEnv){
		dojo.hostenv[param] = _addHostEnv[param];
	}
})();

dojo.hostenv.loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
// summary:
//	Load a Javascript module given a relative path
//
// description:
//	Loads and interprets the script located at relpath, which is relative to the
//	script root directory.  If the script is found but its interpretation causes
//	a runtime exception, that exception is not caught by us, so the caller will
//	see it.  We return a true value if and only if the script is found.
//
//	For now, we do not have an implementation of a true search path.  We
//	consider only the single base script uri, as returned by getBaseScriptUri().
//
// relpath: A relative path to a script (no leading '/', and typically
// 	ending in '.js').
// module: A module whose existance to check for after loading a path.
//	Can be used to determine success or failure of the load.
// cb: a callback function to pass the result of evaluating the script

	var uri;
	if(relpath.charAt(0) == '/' || relpath.match(/^\w+:/)){
		// dojo.raise("relpath '" + relpath + "'; must be relative");
		uri = relpath;
	}else{
		uri = this.getBaseScriptUri() + relpath;
	}
	if(djConfig.cacheBust && dojo.render.html.capable){
		uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,"");
	}
	try{
		return !module ? this.loadUri(uri, cb) : this.loadUriAndCheck(uri, module, cb); // Boolean
	}catch(e){
		dojo.debug(e);
		return false; // Boolean
	}
}

dojo.hostenv.loadUri = function(/*String (URL)*/uri, /*Function?*/cb){
// summary:
//	Loads JavaScript from a URI
//
// description:
//	Reads the contents of the URI, and evaluates the contents.  This is used to load modules as well
//	as resource bundles.  Returns true if it succeeded. Returns false if the URI reading failed.
//	Throws if the evaluation throws.
//
// uri: a uri which points at the script to be loaded
// cb: a callback function to process the result of evaluating the script as an expression, typically
//	used by the resource bundle loader to load JSON-style resources

	if(this.loadedUris[uri]){
		return true; // Boolean
	}
	var contents = this.getText(uri, null, true);
	if(!contents){ return false; } // Boolean
	this.loadedUris[uri] = true;
	if(cb){ contents = '('+contents+')'; }
	var value = dj_eval(contents);
	if(cb){ cb(value); }
	return true; // Boolean
}

// FIXME: probably need to add logging to this method
dojo.hostenv.loadUriAndCheck = function(/*String (URL)*/uri, /*String*/moduleName, /*Function?*/cb){
	// summary: calls loadUri then findModule and returns true if both succeed
	var ok = true;
	try{
		ok = this.loadUri(uri, cb);
	}catch(e){
		dojo.debug("failed loading ", uri, " with error: ", e);
	}
	return Boolean(ok && this.findModule(moduleName, false)); // Boolean
}

dojo.loaded = function(){ }
dojo.unloaded = function(){ }

dojo.hostenv.loaded = function(){
	this.loadNotifying = true;
	this.post_load_ = true;
	var mll = this.modulesLoadedListeners;
	for(var x=0; x<mll.length; x++){
		mll[x]();
	}

	//Clear listeners so new ones can be added
	//For other xdomain package loads after the initial load.
	this.modulesLoadedListeners = [];
	this.loadNotifying = false;

	dojo.loaded();
}

dojo.hostenv.unloaded = function(){
	var mll = this.unloadListeners;
	while(mll.length){
		(mll.pop())();
	}
	dojo.unloaded();
}

dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName) {
// summary:
//	Registers a function to be triggered after the DOM has finished loading 
//	and widgets declared in markup have been instantiated.  Images and CSS files
//	may or may not have finished downloading when the specified function is called.
//	(Note that widgets' CSS and HTML code is guaranteed to be downloaded before said
//	widgets are instantiated.)
//
// usage:
//	dojo.addOnLoad(functionPointer)
//	dojo.addOnLoad(object, "functionName")

	var dh = dojo.hostenv;
	if(arguments.length == 1) {
		dh.modulesLoadedListeners.push(obj);
	} else if(arguments.length > 1) {
		dh.modulesLoadedListeners.push(function() {
			obj[functionName]();
		});
	}

	//Added for xdomain loading. dojo.addOnLoad is used to
	//indicate callbacks after doing some dojo.require() statements.
	//In the xdomain case, if all the requires are loaded (after initial
	//page load), then immediately call any listeners.
	if(dh.post_load_ && dh.inFlightCount == 0 && !dh.loadNotifying){
		dh.callLoaded();
	}
}

dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
// summary: registers a function to be triggered when the page unloads
//
// usage:
//	dojo.addOnLoad(functionPointer)
//	dojo.addOnLoad(object, "functionName")
	var dh = dojo.hostenv;
	if(arguments.length == 1){
		dh.unloadListeners.push(obj);
	} else if(arguments.length > 1) {
		dh.unloadListeners.push(function() {
			obj[functionName]();
		});
	}
}

dojo.hostenv.modulesLoaded = function(){
	if(this.post_load_){ return; }
	if(this.loadUriStack.length==0 && this.getTextStack.length==0){
		if(this.inFlightCount > 0){ 
			dojo.debug("files still in flight!");
			return;
		}
		dojo.hostenv.callLoaded();
	}
}

dojo.hostenv.callLoaded = function(){
	if(typeof setTimeout == "object"){
		setTimeout("dojo.hostenv.loaded();", 0);
	}else{
		dojo.hostenv.loaded();
	}
}

dojo.hostenv.getModuleSymbols = function(/*String*/modulename){
// summary:
//	Converts a module name in dotted JS notation to an array representing the path in the source tree

	var syms = modulename.split(".");
	for(var i = syms.length; i>0; i--){
		var parentModule = syms.slice(0, i).join(".");
		if ((i==1) && !this.moduleHasPrefix(parentModule)){		
			//Support default module directory (sibling of dojo)
			syms[0] = "../" + syms[0];
		}else{
			var parentModulePath = this.getModulePrefix(parentModule);
			if(parentModulePath != parentModule){
				syms.splice(0, i, parentModulePath);
				break;
			}
		}
	}
	return syms; // Array
}

dojo.hostenv._global_omit_module_check = false;
dojo.hostenv.loadModule = function(/*String*/moduleName, /*Boolean?*/exactOnly, /*Boolean?*/omitModuleCheck){
// summary:
//	loads a Javascript module from the appropriate URI
//
// description:
//	loadModule("A.B") first checks to see if symbol A.B is defined. 
//	If it is, it is simply returned (nothing to do).
//	
//	If it is not defined, it will look for "A/B.js" in the script root directory,
//	followed by "A.js".
//	
//	It throws if it cannot find a file to load, or if the symbol A.B is not
//	defined after loading.
//	
//	It returns the object A.B.
//	
//	This does nothing about importing symbols into the current package.
//	It is presumed that the caller will take care of that. For example, to import
//	all symbols:
//	
//	   with (dojo.hostenv.loadModule("A.B")) {
//	      ...
//	   }
//	
//	And to import just the leaf symbol:
//	
//	   var B = dojo.hostenv.loadModule("A.B");
//	   ...
//	
//	dj_load is an alias for dojo.hostenv.loadModule

	if(!moduleName){ return; }
	omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
	var module = this.findModule(moduleName, false);
	if(module){
		return module;
	}

	// protect against infinite recursion from mutual dependencies
	if(dj_undef(moduleName, this.loading_modules_)){
		this.addedToLoadingCount.push(moduleName);
	}
	this.loading_modules_[moduleName] = 1;

	// convert periods to slashes
	var relpath = moduleName.replace(/\./g, '/') + '.js';

	var nsyms = moduleName.split(".");
	
	// this line allowed loading of a module manifest as if it were a namespace
	// it's an interesting idea, but shouldn't be combined with 'namespaces' proper
	// and leads to unwanted dependencies
	// the effect can be achieved in other (albeit less-flexible) ways now, so I am
	// removing this pending further design work
	// perhaps we can explicitly define this idea of a 'module manifest', and subclass
	// 'namespace manifest' from that
	//dojo.getNamespace(nsyms[0]);

	var syms = this.getModuleSymbols(moduleName);
	var startedRelative = ((syms[0].charAt(0) != '/') && !syms[0].match(/^\w+:/));
	var last = syms[syms.length - 1];
	var ok;
	// figure out if we're looking for a full package, if so, we want to do
	// things slightly diffrently
	if(last=="*"){
		moduleName = nsyms.slice(0, -1).join('.');
		while(syms.length){
			syms.pop();
			syms.push(this.pkgFileName);
			relpath = syms.join("/") + '.js';
			if(startedRelative && relpath.charAt(0)=="/"){
				relpath = relpath.slice(1);
			}
			ok = this.loadPath(relpath, !omitModuleCheck ? moduleName : null);
			if(ok){ break; }
			syms.pop();
		}
	}else{
		relpath = syms.join("/") + '.js';
		moduleName = nsyms.join('.');
		var modArg = !omitModuleCheck ? moduleName : null;
		ok = this.loadPath(relpath, modArg);
		if(!ok && !exactOnly){
			syms.pop();
			while(syms.length){
				relpath = syms.join('/') + '.js';
				ok = this.loadPath(relpath, modArg);
				if(ok){ break; }
				syms.pop();
				relpath = syms.join('/') + '/'+this.pkgFileName+'.js';
				if(startedRelative && relpath.charAt(0)=="/"){
					relpath = relpath.slice(1);
				}
				ok = this.loadPath(relpath, modArg);
				if(ok){ break; }
			}
		}

		if(!ok && !omitModuleCheck){
			dojo.raise("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
		}
	}

	// check that the symbol was defined
	//Don't bother if we're doing xdomain (asynchronous) loading.
	if(!omitModuleCheck && !this["isXDomain"]){
		// pass in false so we can give better error
		module = this.findModule(moduleName, false);
		if(!module){
			dojo.raise("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); 
		}
	}

	return module;
}

dojo.hostenv.startPackage = function(/*String*/packageName){
// summary:
//	Creates a JavaScript package
//
// description:
//	startPackage("A.B") follows the path, and at each level creates a new empty
//	object or uses what already exists. It returns the result.
//
// packageName: the package to be created as a String in dot notation

	//Make sure we have a string.
	var fullPkgName = String(packageName);
	var strippedPkgName = fullPkgName;

	var syms = packageName.split(/\./);
	if(syms[syms.length-1]=="*"){
		syms.pop();
		strippedPkgName = syms.join(".");
	}
	var evaledPkg = dojo.evalObjPath(strippedPkgName, true);
	this.loaded_modules_[fullPkgName] = evaledPkg;
	this.loaded_modules_[strippedPkgName] = evaledPkg;
	
	return evaledPkg; // Object
}

dojo.hostenv.findModule = function(/*String*/moduleName, /*Boolean?*/mustExist){
// summary:
//	Returns the Object representing the module, if it exists, otherwise null.
//
// moduleName A fully qualified module including package name, like 'A.B'.
// mustExist Optional, default false. throw instead of returning null
//	if the module does not currently exist.

	var lmn = String(moduleName);

	if(this.loaded_modules_[lmn]){
		return this.loaded_modules_[lmn]; // Object
	}

	if(mustExist){
		dojo.raise("no loaded module named '" + moduleName + "'");
	}
	return null; // null
}

//Start of old bootstrap2:

dojo.kwCompoundRequire = function(/*Object containing Arrays*/modMap){
// description:
//	This method taks a "map" of arrays which one can use to optionally load dojo
//	modules. The map is indexed by the possible dojo.hostenv.name_ values, with
//	two additional values: "default" and "common". The items in the "default"
//	array will be loaded if none of the other items have been choosen based on
//	the hostenv.name_ item. The items in the "common" array will _always_ be
//	loaded, regardless of which list is chosen.  Here's how it's normally
//	called:
//	
//	dojo.kwCompoundRequire({
//		browser: [
//			["foo.bar.baz", true, true], // an example that passes multiple args to loadModule()
//			"foo.sample.*",
//			"foo.test,
//		],
//		default: [ "foo.sample.*" ],
//		common: [ "really.important.module.*" ]
//	});

	var common = modMap["common"]||[];
	var result = modMap[dojo.hostenv.name_] ? common.concat(modMap[dojo.hostenv.name_]||[]) : common.concat(modMap["default"]||[]);

	for(var x=0; x<result.length; x++){
		var curr = result[x];
		if(curr.constructor == Array){
			dojo.hostenv.loadModule.apply(dojo.hostenv, curr);
		}else{
			dojo.hostenv.loadModule(curr);
		}
	}
}

dojo.require = function(/*String*/ resourceName){
	// summary
	//	Ensure that the given resource (ie, javascript
	//	source file) has been loaded.
	// description
	//	dojo.require() is similar to C's #include command or java's "import" command.
	//	You call dojo.require() to pull in the resources (ie, javascript source files)
	//	that define the functions you are using. 
	//
	//	Note that in the case of a build, many resources have already been included
	//	into dojo.js (ie, many of the javascript source files have been compressed and
	//	concatened into dojo.js), so many dojo.require() calls will simply return
	//	without downloading anything.
	dojo.hostenv.loadModule.apply(dojo.hostenv, arguments);
}

dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
	// summary
	//	If the condition is true then call dojo.require() for the specified resource
	var arg0 = arguments[0];
	if((arg0 === true)||(arg0=="common")||(arg0 && dojo.render[arg0].capable)){
		var args = [];
		for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
		dojo.require.apply(dojo, args);
	}
}

dojo.requireAfterIf = dojo.requireIf;

dojo.provide = function(/*String*/ resourceName){
	// summary
	//	Each javascript source file must have (exactly) one dojo.provide()
	//	call at the top of the file, corresponding to the file name.
	//	For example, dojo/src/foo.js must have dojo.provide("dojo.foo"); at the top of the file.
	//
	// description
	//	Each javascript source file is called a resource.  When a resource
	//	is loaded by the browser, dojo.provide() registers that it has
	//	been loaded.
	//	
	//	For backwards compatibility reasons, in addition to registering the resource,
	//	dojo.provide() also ensures that the javascript object for the module exists.  For
	//	example, dojo.provide("dojo.html.common"), in addition to registering that common.js
	//	is a resource for the dojo.html module, will ensure that the dojo.html javascript object
	//	exists, so that calls like dojo.html.foo = function(){ ... } don't fail.
	//
	//	In the case of a build (or in the future, a rollup), where multiple javascript source
	//	files are combined into one bigger file (similar to a .lib or .jar file), that file
	//	will contain multiple dojo.provide() calls, to note that it includes
	//	multiple resources.
	return dojo.hostenv.startPackage.apply(dojo.hostenv, arguments);
}

dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
	// summary: maps a module name to a path
	// description: An unregistered module is given the default path of ../<module>,
	//	relative to Dojo root. For example, module acme is mapped to ../acme.
	//	If you want to use a different module name, use dojo.registerModulePath. 
	return dojo.hostenv.setModulePrefix(module, prefix);
}

dojo.setModulePrefix = function(/*String*/module, /*String*/prefix){
	// summary: maps a module name to a path
	dojo.deprecated('dojo.setModulePrefix("' + module + '", "' + prefix + '")', "replaced by dojo.registerModulePath", "0.5");
	return dojo.registerModulePath(module, prefix);
}

dojo.exists = function(/*Object*/obj, /*String*/name){
	// summary: determine if an object supports a given method
	// description: useful for longer api chains where you have to test each object in the chain
	var p = name.split(".");
	for(var i = 0; i < p.length; i++){
		if(!obj[p[i]]){ return false; } // Boolean
		obj = obj[p[i]];
	}
	return true; // Boolean
}

// Localization routines

dojo.hostenv.normalizeLocale = function(/*String?*/locale){
//	summary:
//		Returns canonical form of locale, as used by Dojo.  All variants are case-insensitive and are separated by '-'
//		as specified in RFC 3066. If no locale is specified, the user agent's default is returned.

	return locale ? locale.toLowerCase() : dojo.locale; // String
};

dojo.hostenv.searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){
//	summary:
//		A helper method to assist in searching for locale-based resources.  Will iterate through
//		the variants of a particular locale, either up or down, executing a callback function.
//		For example, "en-us" and true will try "en-us" followed by "en" and finally "ROOT".

	locale = dojo.hostenv.normalizeLocale(locale);

	var elements = locale.split('-');
	var searchlist = [];
	for(var i = elements.length; i > 0; i--){
		searchlist.push(elements.slice(0, i).join('-'));
	}
	searchlist.push(false);
	if(down){searchlist.reverse();}

	for(var j = searchlist.length - 1; j >= 0; j--){
		var loc = searchlist[j] || "ROOT";
		var stop = searchFunc(loc);
		if(stop){ break; }
	}
}

//These two functions are placed outside of preloadLocalizations
//So that the xd loading can use/override them.
dojo.hostenv.localesGenerated /***BUILD:localesGenerated***/; // value will be inserted here at build time, if necessary

dojo.hostenv.registerNlsPrefix = function(){
// summary:
//	Register module "nls" to point where Dojo can find pre-built localization files
	dojo.registerModulePath("nls","nls");	
}

dojo.hostenv.preloadLocalizations = function(){
// summary:
//	Load built, flattened resource bundles, if available for all locales used in the page.
//	Execute only once.  Note that this is a no-op unless there is a build.

	if(dojo.hostenv.localesGenerated){
		dojo.hostenv.registerNlsPrefix();

		function preload(locale){
			locale = dojo.hostenv.normalizeLocale(locale);
			dojo.hostenv.searchLocalePath(locale, true, function(loc){
				for(var i=0; i<dojo.hostenv.localesGenerated.length;i++){
					if(dojo.hostenv.localesGenerated[i] == loc){
						dojo["require"]("nls.dojo_"+loc);
						return true; // Boolean
					}
				}
				return false; // Boolean
			});
		}
		preload();
		var extra = djConfig.extraLocale||[];
		for(var i=0; i<extra.length; i++){
			preload(extra[i]);
		}
	}
	dojo.hostenv.preloadLocalizations = function(){};
}

dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale){
// summary:
//	Declares translated resources and loads them if necessary, in the same style as dojo.require.
//	Contents of the resource bundle are typically strings, but may be any name/value pair,
//	represented in JSON format.  See also dojo.i18n.getLocalization.
//
// moduleName: name of the package containing the "nls" directory in which the bundle is found
// bundleName: bundle name, i.e. the filename without the '.js' suffix
// locale: the locale to load (optional)  By default, the browser's user locale as defined by dojo.locale
//
// description:
//	Load translated resource bundles provided underneath the "nls" directory within a package.
//	Translated resources may be located in different packages throughout the source tree.  For example,
//	a particular widget may define one or more resource bundles, structured in a program as follows,
//	where moduleName is mycode.mywidget and bundleNames available include bundleone and bundletwo:
//	...
//	mycode/
//	 mywidget/
//	  nls/
//	   bundleone.js (the fallback translation, English in this example)
//	   bundletwo.js (also a fallback translation)
//	   de/
//	    bundleone.js
//	    bundletwo.js
//	   de-at/
//	    bundleone.js
//	   en/
//	    (empty; use the fallback translation)
//	   en-us/
//	    bundleone.js
//	   en-gb/
//	    bundleone.js
//	   es/
//	    bundleone.js
//	    bundletwo.js
//	  ...etc
//	...
//	Each directory is named for a locale as specified by RFC 3066, (http://www.ietf.org/rfc/rfc3066.txt),
//	normalized in lowercase.  Note that the two bundles in the example do not define all the same variants.
//	For a given locale, bundles will be loaded for that locale and all more general locales above it, including
//	a fallback at the root directory.  For example, a declaration for the "de-at" locale will first
//	load nls/de-at/bundleone.js, then nls/de/bundleone.js and finally nls/bundleone.js.  The data will
//	be flattened into a single Object so that lookups will follow this cascading pattern.  An optional build
//	step can preload the bundles to avoid data redundancy and the multiple network hits normally required to
//	load these resources.

	dojo.hostenv.preloadLocalizations();
 	var bundlePackage = [moduleName, "nls", bundleName].join(".");
//NOTE: When loading these resources, the packaging does not match what is on disk.  This is an
// implementation detail, as this is just a private data structure to hold the loaded resources.
// e.g. tests/hello/nls/en-us/salutations.js is loaded as the object tests.hello.nls.salutations.en_us={...}
// The structure on disk is intended to be most convenient for developers and translators, but in memory
// it is more logical and efficient to store in a different order.  Locales cannot use dashes, since the
// resulting path will not evaluate as valid JS, so we translate them to underscores.

	var bundle = dojo.hostenv.findModule(bundlePackage);
	if(bundle){
		if(djConfig.localizationComplete && bundle._built){return;}
		var jsLoc = dojo.hostenv.normalizeLocale(locale).replace('-', '_');
		var translationPackage = bundlePackage+"."+jsLoc;
		if(dojo.hostenv.findModule(translationPackage)){return;}
	}

	bundle = dojo.hostenv.startPackage(bundlePackage);
	var syms = dojo.hostenv.getModuleSymbols(moduleName);
	var modpath = syms.concat("nls").join("/");
	var parent;
	dojo.hostenv.searchLocalePath(locale, false, function(loc){
		var jsLoc = loc.replace('-', '_');
		var translationPackage = bundlePackage + "." + jsLoc;
		var loaded = false;
		if(!dojo.hostenv.findModule(translationPackage)){
			// Mark loaded whether it's found or not, so that further load attempts will not be made
			dojo.hostenv.startPackage(translationPackage);
			var module = [modpath];
			if(loc != "ROOT"){module.push(loc);}
			module.push(bundleName);
			var filespec = module.join("/") + '.js';
			loaded = dojo.hostenv.loadPath(filespec, null, function(hash){
				// Use singleton with prototype to point to parent bundle, then mix-in result from loadPath
				var clazz = function(){};
				clazz.prototype = parent;
				bundle[jsLoc] = new clazz();
				for(var j in hash){ bundle[jsLoc][j] = hash[j]; }
			});
		}else{
			loaded = true;
		}
		if(loaded && bundle[jsLoc]){
			parent = bundle[jsLoc];
		}else{
			bundle[jsLoc] = parent;
		}
	});
};

(function(){
	// If other locales are used, dojo.requireLocalization should load them as well, by default.
	// Override dojo.requireLocalization to do load the default bundle, then iterate through the
	// extraLocale list and load those translations as well, unless a particular locale was requested.

	var extra = djConfig.extraLocale;
	if(extra){
		if(!extra instanceof Array){
			extra = [extra];
		}

		var req = dojo.requireLocalization;
		dojo.requireLocalization = function(m, b, locale){
			req(m,b,locale);
			if(locale){return;}
			for(var i=0; i<extra.length; i++){
				req(m,b,extra[i]);
			}
		};
	}
})();

__CPAN_FILE__ src/storage.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/** 
		FIXME: Write better docs.

		@author Brad Neuberg, bkn3@columbia.edu 
*/
dojo.provide("dojo.storage");

dojo.require("dojo.lang.*");
dojo.require("dojo.event.*");

// create an empty "StorageProvider", which was being created as a side-effect
//	of the erroneous dojo.provide("dojo.storage.StorageProvider")
dojo.storage.StorageProvider = {}


/** The base class for all storage providers. */

/** 
	 The constructor for a storage provider. You should avoid initialization
	 in the constructor; instead, define initialization in your initialize()
	 method. 
*/
dojo.declare("dojo.storage", null, {
	/** A put() call to a storage provider was succesful. */
	SUCCESS: "success",
	
	/** A put() call to a storage provider failed. */
	FAILED: "failed",
	
	/** A put() call to a storage provider is pending user approval. */
	PENDING: "pending",
	
	/** 
	  Returned by getMaximumSize() if this storage provider can not determine
	  the maximum amount of data it can support. 
	*/
	SIZE_NOT_AVAILABLE: "Size not available",
	
	/**
	  Returned by getMaximumSize() if this storage provider has no theoretical
	  limit on the amount of data it can store. 
	*/
	SIZE_NO_LIMIT: "No size limit",
	
	/** 
		The namespace for all storage operations. This is useful if several
		applications want access to the storage system from the same domain but
		want different storage silos. 
	*/
	"namespace": "dojoStorage",
	
	/**  
		If a function is assigned to this property, then when the settings
		provider's UI is closed this function is called. Useful, for example,
		if the user has just cleared out all storage for this provider using
		the settings UI, and you want to update your UI.
	*/
	onHideSettingsUI: null,

	initialize: function(){
		// summary: 
		//		Allows this storage provider to initialize itself. This is
		//		called after the page has finished loading, so you can not do
		//		document.writes(). 
		dojo.unimplemented("dojo.storage.initialize");
	},
	
	isAvailable: function(){ /*Boolean*/
		// summary: 
		//		Returns whether this storage provider is available on this
		//		platform. 
		dojo.unimplemented("dojo.storage.isAvailable");
	},
	
	/**

	*/
	put: function(	/*string*/ key,
					/*object*/ value, 
					/*function*/ resultsHandler){
		// summary:
		//		Puts a key and value into this storage system.
		// key:
		//		A string key to use when retrieving this value in the future.
		// value:
		//		A value to store; this can be any JavaScript type.
		// resultsHandler:
		//		A callback function that will receive three arguments. The
		//		first argument is one of three values: dojo.storage.SUCCESS,
		//		dojo.storage.FAILED, or dojo.storage.PENDING; these values
		//		determine how the put request went. In some storage systems
		//		users can deny a storage request, resulting in a
		//		dojo.storage.FAILED, while in other storage systems a storage
		//		request must wait for user approval, resulting in a
		//		dojo.storage.PENDING status until the request is either
		//		approved or denied, resulting in another call back with
		//		dojo.storage.SUCCESS. 
		//		The second argument in the call back is the key name that was being stored.
		//		The third argument in the call back is an optional message that
		//		details possible error messages that might have occurred during
		//		the storage process.

//	  Example:
//		var resultsHandler = function(status, key, message){
//		  alert("status="+status+", key="+key+", message="+message);
//		};
//		dojo.storage.put("test", "hello world", resultsHandler);
		dojo.unimplemented("dojo.storage.put");
	},

	get: function(/*string*/ key){ /*Object*/
		// summary:
		//		Gets the value with the given key. Returns null if this key is
		//		not in the storage system.
		// key:
		//		A string key to get the value of.
		// return: Returns any JavaScript object type; null if the key is not present
		dojo.unimplemented("dojo.storage.get");
	},

	hasKey: function(/*string*/ key){ /*Boolean*/
		// summary: Determines whether the storage has the given key. 
		return (this.get(key) != null);
	},

	/**
	
	getKeys: function(){ //Array
		// summary: Enumerates all of the available keys in this storage system.
		dojo.unimplemented("dojo.storage.getKeys");
	},

	*/
	clear: function(){
		// summary: 
		//		Completely clears this storage system of all of it's values and
		//		keys. 
		dojo.unimplemented("dojo.storage.clear");
	},
  
	/** Removes the given key from the storage system. */
	remove: function(key){
		dojo.unimplemented("dojo.storage.remove");
	},

	isPermanent: function(){ /*Boolean*/
		// summary:
		//		Returns whether this storage provider's values are persisted
		//		when this platform is shutdown. 
		dojo.unimplemented("dojo.storage.isPermanent");
	},

	/**
	  The maximum storage allowed by this provider.
	
	  @returns Returns the maximum storage size 
	           supported by this provider, in 
	           thousands of bytes (i.e., if it 
	           returns 60 then this means that 60K 
	           of storage is supported).
	    
	           If this provider can not determine 
	           it's maximum size, then 
	           dojo.storage.SIZE_NOT_AVAILABLE is 
	           returned; if there is no theoretical
	           limit on the amount of storage 
	           this provider can return, then
	           dojo.storage.SIZE_NO_LIMIT is 
	           returned
	*/
	getMaximumSize: function(){
		dojo.unimplemented("dojo.storage.getMaximumSize");
	},

	hasSettingsUI: function(){ /*Boolean*/
		// summary: Determines whether this provider has a settings UI.
		return false;
	},

	showSettingsUI: function(){
		// summary: If this provider has a settings UI, it is shown. 
		dojo.unimplemented("dojo.storage.showSettingsUI");
	},

	hideSettingsUI: function(){
		// summary: If this provider has a settings UI, hides it.
		dojo.unimplemented("dojo.storage.hideSettingsUI");
	},
	
	getType: function(){ /*String*/
		// summary:
		//		The provider name as a string, such as
		//		"dojo.storage.FlashStorageProvider". 
		dojo.unimplemented("dojo.storage.getType");
	},
	
	isValidKey: function(/*string*/ keyName){ /*Boolean*/
		// summary:
		//		Subclasses can call this to ensure that the key given is valid
		//		in a consistent way across different storage providers. We use
		//		the lowest common denominator for key values allowed: only
		//		letters, numbers, and underscores are allowed. No spaces. 
		if((keyName == null)||(typeof keyName == "undefined")){
			return false;
		}
			
		return /^[0-9A-Za-z_]*$/.test(keyName);
	}
});




/**
	Initializes the storage systems and figures out the best available 
	storage options on this platform.
*/
dojo.storage.manager = new function(){
	this.currentProvider = null;
	this.available = false;
	this.initialized = false;
	this.providers = [];
	
	// TODO: Provide a way for applications to override the default namespace
	this["namespace"] = "dojo.storage";
	
	this.initialize = function(){
		// summary: 
		//		Initializes the storage system and autodetects the best storage
		//		provider we can provide on this platform
		this.autodetect();
	};
	
	/**
	
	*/
	this.register = function(/*string*/ name, /*Object*/ instance) {
		// summary:
		//		Registers the existence of a new storage provider; used by
		//		subclasses to inform the manager of their existence. 
		// name:
		//		The full class name of this provider, such as
		//		"dojo.storage.browser.Flash6StorageProvider".
		// instance:
		//		An instance of this provider, which we will use to call
		//		isAvailable() on. 
		this.providers[this.providers.length] = instance;
		this.providers[name] = instance;
	};
	
	/**
	    
	*/
	this.setProvider = function(storageClass){
		// summary:
		//		Instructs the storageManager to use the given storage class for
		//		all storage requests.
		// description:
		//		Example:
		//			dojo.storage.setProvider(
		//				dojo.storage.browser.IEStorageProvider)
	
	};
	
	this.autodetect = function(){
		// summary:
		//		Autodetects the best possible persistent storage provider
		//		available on this platform. 
		if(this.initialized == true) // already finished
			return;
			
		// go through each provider, seeing if it can be used
		var providerToUse = null;
		for(var i = 0; i < this.providers.length; i++) {
			providerToUse = this.providers[i];
			if(providerToUse.isAvailable()){
				break;
			}
		}	
		
		if(providerToUse == null){ // no provider available
			this.initialized = true;
			this.available = false;
			this.currentProvider = null;
			dojo.raise("No storage provider found for this platform");
		}
			
		// create this provider and copy over it's properties
		this.currentProvider = providerToUse;
	  	for(var i in providerToUse){
	  		dojo.storage[i] = providerToUse[i];
		}
		dojo.storage.manager = this;
		
		// have the provider initialize itself
		dojo.storage.initialize();
		
		this.initialized = true;
		this.available = true;
	};
	
	this.isAvailable = function(){ /*Boolean*/
		// summary: Returns whether any storage options are available.
		return this.available;
	};
	
	this.isInitialized = function(){ /*Boolean*/
	 	// summary:
		//		Returns whether the storage system is initialized and ready to
		//		be used. 

		// FIXME: This should _really_ not be in here, but it fixes a bug
		if(dojo.flash.ready == false){
			return false;
		}else{
			return this.initialized;
		}
	};

	this.supportsProvider = function(/*string*/ storageClass){
		// summary: Determines if this platform supports the given storage provider.
		// description:
		//		Example:
		//			dojo.storage.manager.supportsProvider(
		//				"dojo.storage.browser.InternetExplorerStorageProvider");

		// construct this class dynamically
		try{
			// dynamically call the given providers class level isAvailable()
			// method
			var provider = eval("new " + storageClass + "()");
			var results = provider.isAvailable();
			if(results == null || typeof results == "undefined")
				return false;
			return results;
		}catch (exception){
			dojo.debug("exception="+exception);
			return false;
		}
	};

	/** Gets the current provider. */
	this.getProvider = function(){
		return this.currentProvider;
	};
	
	this.loaded = function(){
		// summary:
		//		The storage provider should call this method when it is loaded
		//		and ready to be used. Clients who will use the provider will
		//		connect to this method to know when they can use the storage
		//		system:
	};
};

__CPAN_FILE__ src/style.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.style");
dojo.kwCompoundRequire({
	browser: ["dojo.html.style"]
});
dojo.deprecated("dojo.style", "replaced by dojo.html.style", "0.5");

__CPAN_FILE__ src/data.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data");

// currently a stub for dojo.data

dojo.data = {};

__CPAN_FILE__ src/svg.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.svg");
dojo.require("dojo.lang.common");
dojo.require("dojo.dom");

dojo.mixin(dojo.svg, dojo.dom);

dojo.svg.graphics=dojo.svg.g=new function(/* DOMDocument */ d){
	//	summary
	//	Singleton to encapsulate SVG rendering functions.
	this.suspend=function(){
		//	summary
		//	Suspend the rendering engine
		try { d.documentElement.suspendRedraw(0); } catch(e){ }
	};
	this.resume=function(){
		//	summary
		//	Resume the rendering engine
		try { d.documentElement.unsuspendRedraw(0); } catch(e){ }
	};
	this.force=function(){
		//	summary
		//	Force the render engine to redraw
		try { d.documentElement.forceRedraw(); } catch(e){ }
	};
}(document);

dojo.svg.animations=dojo.svg.anim=new function(/* DOMDocument */ d){
	//	summary
	//	Singleton to encapsulate SVG animation functionality.
	this.arePaused=function(){
		//	summary
		//	check to see if all animations are paused
		try {
			return d.documentElement.animationsPaused();	//	bool
		} catch(e){
			return false;	//	bool
		}
	} ;
	this.pause=function(){
		//	summary
		//	pause all animations
		try { d.documentElement.pauseAnimations(); } catch(e){ }
	};
	this.resume=function(){
		//	summary
		//	resume all animations
		try { d.documentElement.unpauseAnimations(); } catch(e){ }
	};
}(document);

//	fixme: these functions should be mixed in from dojo.style, but dojo.style is HTML-centric and needs to change.
dojo.svg.toCamelCase=function(/* string */ selector){
	//	summary
	//	converts a CSS-style selector to a camelCased one
	var arr=selector.split('-'), cc=arr[0];
	for(var i=1; i < arr.length; i++) {
		cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
	}
	return cc;	// string
};
dojo.svg.toSelectorCase=function(/* string */ selector) {
	//	summary
	//	converts a camelCased selector to a CSS style one
	return selector.replace(/([A-Z])/g, "-$1" ).toLowerCase();	//	string
};
dojo.svg.getStyle=function(/* SVGElement */ node, /* string */ cssSelector){
	//	summary
	//	get the computed style of selector for node.
	return document.defaultView.getComputedStyle(node, cssSelector);	//	object
};
dojo.svg.getNumericStyle=function(/* SVGElement */ node, /* string */ cssSelector){
	//	summary
	//	return the numeric version of the computed style of selector on node.
	return parseFloat(dojo.svg.getStyle(node, cssSelector));
};

//	fixme: there are different ways of doing the following, need to take into account
dojo.svg.getOpacity=function(/* SVGElement */node){
	//	summary
	//	Return the opacity of the passed element
	return Math.min(1.0, dojo.svg.getNumericStyle(node, "fill-opacity"));	//	float
};
dojo.svg.setOpacity=function(/* SVGElement */ node, /* float */ opacity){
	//	summary
	//	set the opacity of node using attributes.
	node.setAttributeNS(this.xmlns.svg, "fill-opacity", opacity);
	node.setAttributeNS(this.xmlns.svg, "stroke-opacity", opacity);
};
dojo.svg.clearOpacity=function(/* SVGElement */ node){
	//	summary
	//	Set any attributes setting opacity to opaque (1.0)
	node.setAttributeNS(this.xmlns.svg, "fill-opacity", "1.0");
	node.setAttributeNS(this.xmlns.svg, "stroke-opacity", "1.0");
};

/**
 *	Coordinates and dimensions.
 */

// TODO ////////////////////////////////////////////////////////// TODO
dojo.svg.getCoords=function(/* SVGElement */ node){
	//	summary
	//	Returns the x/y coordinates of the passed node, if available.
	if (node.getBBox) {
		var box=node.getBBox();
		return { x: box.x, y: box.y };	//	object
	}
	return null;	//	object
};
dojo.svg.setCoords=function(/* SVGElement */node, /* object */coords){
	//	summary
	//	Set the x/y coordinates of the passed node
	var p=dojo.svg.getCoords();
	if (!p) return;
	var dx=p.x - coords.x;
	var dy=p.y - coords.y;
	dojo.svg.translate(node, dx, dy);
};
dojo.svg.getDimensions=function(/* SVGElement */node){
	//	summary
	//	Get the height and width of the passed node.
	if (node.getBBox){
		var box=node.getBBox();
		return { width: box.width, height : box.height };	//	object
	}
	return null;	//	object
};
dojo.svg.setDimensions=function(/* SVGElement */node, /* object */dim){
	//	summary
	//	Set the dimensions of the passed element if possible.
	//	will only support shape-based and container elements; path-based elements are ignored.
	if (node.width){
		node.width.baseVal.value=dim.width;
		node.height.baseVal.value=dim.height;
	}
	else if (node.r){
		node.r.baseVal.value=Math.min(dim.width, dim.height)/2;
	}
	else if (node.rx){
		node.rx.baseVal.value=dim.width/2;
		node.ry.baseVal.value=dim.height/2;
	}
};

/**
 *	Transformations.
 */
dojo.svg.translate=function(/* SVGElement */node, /* int */dx, /* int */dy){
	//	summary
	//	Translates the passed node by dx and dy
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var t=node.ownerSVGElement.createSVGTransform();
		t.setTranslate(dx, dy);
		node.transform.baseVal.appendItem(t);
	}
};
dojo.svg.scale=function(/* SVGElement */node, /* float */scaleX, /* float? */scaleY){
	//	summary
	//	Scales the passed element by factor scaleX and scaleY.  If scaleY not passed, scaleX is used.
	if (!scaleY) var scaleY=scaleX;
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var t=node.ownerSVGElement.createSVGTransform();
		t.setScale(scaleX, scaleY);
		node.transform.baseVal.appendItem(t);
	}
};
dojo.svg.rotate=function(/* SVGElement */node, /* float */ang, /* int? */cx, /* int? */cy){
	//	summary
	//	rotate the passed node by ang, with optional cx/cy as the rotation point.
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var t=node.ownerSVGElement.createSVGTransform();
		if (cx == null) t.setMatrix(t.matrix.rotate(ang));
		else t.setRotate(ang, cx, cy);
		node.transform.baseVal.appendItem(t);
	}
};
dojo.svg.skew=function(/* SVGElement */node, /* float */ang, /* string? */axis){
	//	summary
	//	skew the passed node by ang over axis.
	var dir=axis || "x";
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var t=node.ownerSVGElement.createSVGTransform();
		if (dir != "x") t.setSkewY(ang);
		else t.setSkewX(ang);
		node.transform.baseVal.appendItem(t);
	}
};
dojo.svg.flip=function(/* SVGElement */node, /* string? */axis){
	//	summary
	//	flip the passed element over axis
	var dir=axis || "x";
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var t=node.ownerSVGElement.createSVGTransform();
		t.setMatrix((dir != "x") ? t.matrix.flipY() : t.matrix.flipX());
		node.transform.baseVal.appendItem(t);
	}
};
dojo.svg.invert=function(/* SVGElement */node){
	//	summary
	//	transform the passed node by the inverse of the current matrix
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var t=node.ownerSVGElement.createSVGTransform();
		t.setMatrix(t.matrix.inverse());
		node.transform.baseVal.appendItem(t);
	}
};
dojo.svg.applyMatrix=function(
	/* SVGElement */node, 
	/* int || SVGMatrix */a, 
	/* int? */b, 
	/* int? */c, 
	/* int? */d, 
	/* int? */e, 
	/* int? */f
){
	//	summary
	//	apply the passed matrix to node.  If params b - f are passed, a matrix will be created.
	if (node.transform && node.ownerSVGElement && node.ownerSVGElement.createSVGTransform){
		var m;
		if (b){
			var m=node.ownerSVGElement.createSVGMatrix();
			m.a=a;
			m.b=b;
			m.c=c;
			m.d=d;
			m.e=e;
			m.f=f;
		} else m=a;
		var t=node.ownerSVGElement.createSVGTransform();
		t.setMatrix(m);
		node.transform.baseVal.appendItem(t);
	}
};

/**
 *	Grouping and z-index operations.
 */
dojo.svg.group=function(/* Nodelist || array */nodes){
	//	summary
	//	expect an array of nodes, attaches the group to the parent of the first node.
	var p=nodes.item(0).parentNode;
	var g=document.createElementNS(this.xmlns.svg, "g");
	for (var i=0; i < nodes.length; i++) g.appendChild(nodes.item(i));
	p.appendChild(g);
	return g;
};
dojo.svg.ungroup=function(/* SVGGElement */g){
	//	summary
	//	puts the children of the group on the same level as group was.
	var p=g.parentNode;
	while (g.childNodes.length > 0) p.appendChild(g.childNodes.item(0));
	p.removeChild(g);
};
//	if the node is part of a group, return the group, else return null.
dojo.svg.getGroup=function(/* SVGElement */node){
	//	summary
	//	if the node is part of a group, return the group, else return null.
	var a=this.getAncestors(node);
	for (var i=0; i < a.length; i++){
		if (a[i].nodeType == this.ELEMENT_NODE && a[i].nodeName.toLowerCase() == "g")
			return a[i];
	}
	return null;
};
dojo.svg.bringToFront=function(/* SVGElement */node){
	//	summary
	//	move the passed node the to top of the group (i.e. last child)
	var n=this.getGroup(node) || node;
	n.ownerSVGElement.appendChild(n);
};
dojo.svg.sendToBack=function(/* SVGElement */node){
	//	summary
	//	move the passed node to the bottom of the group (i.e. first child)
	var n=this.getGroup(node) || node;
	n.ownerSVGElement.insertBefore(n, n.ownerSVGElement.firstChild);
};

//	TODO: possibly push node up a level in the DOM if it's at the beginning or end of the childNodes list.
dojo.svg.bringForward=function(/* SVGElement */node){
	//	summary
	//	move the passed node up one in the child node chain
	var n=this.getGroup(node) || node;
	if (this.getLastChildElement(n.parentNode) != n){
		this.insertAfter(n, this.getNextSiblingElement(n), true);
	}
};
dojo.svg.sendBackward=function(/* SVGElement */node){
	//	summary
	//	move the passed node down one in the child node chain
	var n=this.getGroup(node) || node;
	if (this.getFirstChildElement(n.parentNode) != n){
		this.insertBefore(n, this.getPreviousSiblingElement(n), true);
	}
};
// END TODO ////////////////////////////////////////////////////// TODO

dojo.svg.createNodesFromText=function(/* string */ txt, /* bool? */ wrap){
	//	summary
	//	Create a list of nodes from text
	var docFrag=(new DOMParser()).parseFromString(txt, "text/xml").normalize();
	if(wrap){ 
		return [docFrag.firstChild.cloneNode(true)];	//	array
	}
	var nodes=[];
	for(var x=0; x<docFrag.childNodes.length; x++){
		nodes.push(docFrag.childNodes.item(x).cloneNode(true));
	}
	return nodes;	// array
}
// vim:ts=4:noet:tw=0:

__CPAN_FILE__ src/validate.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate");
dojo.require("dojo.validate.common");

__CPAN_FILE__ src/crypto.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.crypto");

dojo.crypto.cipherModes={ 
	//	summary
	//	Enumeration for various cipher modes.
	ECB:0, 
	CBC:1, 
	PCBC:2, 
	CFB:3, 
	OFB:4, 
	CTR:5 
};

dojo.crypto.outputTypes={ 
	//	summary
	//	Enumeration for input and output encodings.
	Base64:0,
	Hex:1,
	String:2,
	Raw:3 
};

__CPAN_FILE__ src/docs.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.docs");
dojo.require("dojo.io.*");
dojo.require("dojo.event.topic");
dojo.require("dojo.rpc.JotService");
dojo.require("dojo.dom");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.Deferred");
dojo.require("dojo.DeferredList");

/*
 * TODO:
 *
 * Package summary needs to compensate for "is"
 * Handle host environments
 * Deal with dojo.widget weirdness
 * Parse parameters
 * Limit function parameters to only the valid ones (Involves packing parameters onto meta during rewriting)
 *
 */

dojo.docs = new function() {
	this._url = dojo.uri.dojoUri("docscripts");
	this._rpc = new dojo.rpc.JotService;
	this._rpc.serviceUrl = dojo.uri.dojoUri("docscripts/jsonrpc.php");
};
dojo.lang.mixin(dojo.docs, {
	_count: 0,
	_callbacks: {function_names: []},
	_cache: {}, // Saves the JSON objects in cache
	require: function(/*String*/ require, /*bool*/ sync) {
		dojo.debug("require(): " + require);
		var parts = require.split("/");
		var size = parts.length;
		var deferred = new dojo.Deferred;
		var args = {
			mimetype: "text/json",
			load: function(type, data){
				dojo.debug("require(): loaded");
				
				if(parts[0] != "function_names") {
					for(var i = 0, part; part = parts[i]; i++){
						data = data[part];
					}
				}
				deferred.callback(data);
			},
			error: function(){
				deferred.errback();
			}
		};
		
		if (sync) {
			args.sync = true;
		}

		if(location.protocol == "file:"){
			if(size){
				if(parts[0] == "function_names"){
					args.url = [this._url, "local_json", "function_names"].join("/");
				}else{
					var dirs = parts[0].split(".");
					args.url = [this._url, "local_json", dirs[0]].join("/");
					if(dirs.length > 1){
						args.url = [args.url, dirs[1]].join(".");
					}
				}
			}
		}
		
		dojo.io.bind(args);
		return deferred;
	},
	getFunctionNames: function(){
		return this.require("function_names"); // dojo.Deferred
	},
	unFormat: function(/*String*/ string){
		var fString = string;
		if(string.charAt(string.length - 1) == "_"){
			fString = [string.substring(0, string.length - 1), "*"].join("");
		}
		return fString;
	},
	getMeta: function(/*mixed*/ selectKey, /*String*/ pkg, /*String*/ name, /*Function*/ callback, /*String?*/ id){
		// summary: Gets information about a function in regards to its meta data
		if(typeof name == "function"){
			// pId: a
			// pkg: ignore
			id = callback;
			callback = name;
			name = pkg;
			pkg = null;
			dojo.debug("getMeta(" + name + ")");
		}else{
			dojo.debug("getMeta(" + pkg + "/" + name + ")");
		}
		
		if(!id){
			id = "_";
		}

		if(!selectKey){
			selectKey = ++dojo.docs._count;
		}

		var input;
		if(typeof selectKey == "object" && selectKey.selectKey){
			input = selectKey;
			selectKey = selectKey.selectKey;
		}else{
			input = {};
		}

		dojo.docs._buildCache({
			type: "meta",
			callbacks: [dojo.docs._gotMeta, callback],
			pkg: pkg,
			name: name,
			id: id,
			selectKey: selectKey,
			input: input
		});
	},
	_withPkg: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input, /*String*/ newType){
		dojo.debug("_withPkg(" + evt.name + ") has package: " + data[0]);
		evt.pkg = data[0];
		if("load" == type && evt.pkg){
			evt.type = newType;
			dojo.docs._buildCache(evt);
		}else{
			if(evt.callbacks && evt.callbacks.length){
				evt.callbacks.shift()("error", {}, evt, evt.input);
			}
		}
	},
	_gotMeta: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){
		dojo.debug("_gotMeta(" + evt.name + ")");

		var cached = dojo.docs._getCache(evt.pkg, evt.name, "meta", "functions", evt.id);
		if(cached.summary){
			data.summary = cached.summary;
		}
		if(evt.callbacks && evt.callbacks.length){
			evt.callbacks.shift()(type, data, evt, evt.input);
		}
	},
	getSrc: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback, /*String?*/ id){
		// summary: Gets src file (created by the doc parser)
		dojo.debug("getSrc(" + name + ")");
		if(!id){
			id = "_";
		}
		if(!selectKey){
			selectKey = ++dojo.docs._count;
		}
		
		var input;
		if(typeof selectKey == "object" && selectKey.selectKey){
			input = selectKey;
			selectKey = selectKey.selectKey;
		}else{
			input = {};
		}
		
		dojo.docs._buildCache({
			type: "src",
			callbacks: [callback],
			name: name,
			id: id,
			input: input,
			selectKey: selectKey
		});
	},
	getDoc: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback, /*String?*/ id){
		// summary: Gets external documentation stored on Jot for a given function
		dojo.debug("getDoc(" + name  + ")");

		if(!id){
			id = "_";
		}

		if(!selectKey){
			selectKey = ++dojo.docs._count;
		}

		var input = {};
		if(typeof selectKey == "object" && selectKey.selectKey){
			input.input = selectKey;
			selectKey = selectKey.selectKey;
		}

		input.type = "doc";
		input.name = name;
		input.selectKey = selectKey;
		input.callbacks = [callback];
		input.selectKey = selectKey;

		dojo.docs._buildCache(input);
	},
	_gotDoc: function(/*String*/ type, /*Array*/ data, /*Object*/ evt, /*Object*/ input){
		dojo.debug("_gotDoc(" + evt.type + ")");
		
		evt[evt.type] = data;
		if(evt.expects && evt.expects.doc){
			for(var i = 0, expect; expect = evt.expects.doc[i]; i++){
				if(!(expect in evt)){
					dojo.debug("_gotDoc() waiting for more data");
					return;
				}
			}
		}
		
		var cache = dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta");

		var description = evt.fn.description;
		cache.description = description;
		data = {
			returns: evt.fn.returns,
			id: evt.id,
			variables: [],
			selectKey: evt.selectKey
		}
		if(!cache.parameters){
			cache.parameters = {};
		}
		for(var i = 0, param; param = evt.param[i]; i++){
			var fName = param["DocParamForm/name"];
			if(!cache.parameters[fName]){
				cache.parameters[fName] = {};
			}
			cache.parameters[fName].description = param["DocParamForm/desc"]
		}

		data.description = cache.description;
		data.parameters = cache.parameters;
		
		evt.type = "doc";
	
		if(evt.callbacks && evt.callbacks.length){
			evt.callbacks.shift()("load", data, evt, input);
		}
	},
	getPkgDoc: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback){
		// summary: Gets external documentation stored on Jot for a given package
		dojo.debug("getPkgDoc(" + name + ")");
		var input = {};
		if(typeof selectKey == "object" && selectKey.selectKey){
			input = selectKey;
			selectKey = selectKey.selectKey;
		}
		if(!selectKey){
			selectKey = ++dojo.docs._count;
		}
		dojo.docs._buildCache({
			type: "pkgdoc",
			callbacks: [callback],
			name: name,
			selectKey: selectKey,
			input: input
		});
	},
	getPkgInfo: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback){
		// summary: Gets a combination of the metadata and external documentation for a given package
		dojo.debug("getPkgInfo(" + name + ")");
		if(!selectKey){
			selectKey = ++dojo.docs._count;
		}

		var input = {
			selectKey: selectKey,
			expects: {
				pkginfo: ["pkgmeta", "pkgdoc"]
			},
			callback: callback
		};
		dojo.docs.getPkgMeta(input, name, dojo.docs._getPkgInfo);
		dojo.docs.getPkgDoc(input, name, dojo.docs._getPkgInfo);
	},
	_getPkgInfo: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){
		dojo.debug("_getPkgInfo() for " + evt.type);
		var key = evt.selectKey;
		var input = {};
		var results = {};
		if(typeof key == "object"){
			input = key;
			key = key.selectKey;
			input[evt.type] = data;
			if(input.expects && input.expects.pkginfo){
				for(var i = 0, expect; expect = input.expects.pkginfo[i]; i++){
					if(!(expect in input)){
						dojo.debug("_getPkgInfo() waiting for more data");
						return;
					}
				}
			}
			results = input.pkgmeta;
			results.description = input.pkgdoc;
		}

		if(input.callback){
			input.callback("load", results, evt);
		}
	},
	getInfo: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback){
		dojo.debug("getInfo(" + name + ")");
		var input = {
			expects: {
				"info": ["meta", "doc"]
			},
			selectKey: selectKey,
			callback: callback
		}
		dojo.docs.getMeta(input, name, dojo.docs._getInfo);
		dojo.docs.getDoc(input, name, dojo.docs._getInfo);
	},
	_getInfo: function(/*String*/ type, /*String*/ data, /*Object*/ evt, /*Object*/ input){
		dojo.debug("_getInfo(" + evt.type + ")");
		if(input && input.expects && input.expects.info){
			input[evt.type] = data;
			for(var i = 0, expect; expect = input.expects.info[i]; i++){
				if(!(expect in input)){
					dojo.debug("_getInfo() waiting for more data");
					return;
				}
			}
		}

		if(input.callback){
			input.callback("load", dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta"), evt, input);
		}
	},
	_getMainText: function(/*String*/ text){
		// summary: Grabs the innerHTML from a Jot Rech Text node
		dojo.debug("_getMainText()");
		return text.replace(/^<html[^<]*>/, "").replace(/<\/html>$/, "").replace(/<\w+\s*\/>/g, "");
	},
	getPackageMeta: function(/*Object*/ input){
		dojo.debug("getPackageMeta(): " + input.pkg);
		return this.require(input.pkg + "/meta", input.sync);
	},
	OLDgetPkgMeta: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback){
		dojo.debug("getPkgMeta(" + name + ")");
		var input = {};
		if(typeof selectKey == "object" && selectKey.selectKey){
			input = selectKey;
			selectKey = selectKey.selectKey;
		}else if(!selectKey){
			selectKey = ++dojo.docs._count;
		}
		dojo.docs._buildCache({
			type: "pkgmeta",
			callbacks: [callback],
			name: name,
			selectKey: selectKey,
			input: input
		});
	},
	OLD_getPkgMeta: function(/*Object*/ input){
		dojo.debug("_getPkgMeta(" + input.name + ")");
		input.type = "pkgmeta";
		dojo.docs._buildCache(input);
	},
	_onDocSearch: function(/*Object*/ input){
		var _this = this;
		var name = input.name.toLowerCase();
		if(!name) return;

		this.getFunctionNames().addCallback(function(data){
			dojo.debug("_onDocSearch(): function names loaded for " + name);

			var output = [];
			var list = [];
			var closure = function(pkg, fn) {
				return function(data){
					dojo.debug("_onDocSearch(): package meta loaded for: " + pkg);
					if(data.functions){
						var functions = data.functions;
						for(var key in functions){
							if(fn == key){
								var ids = functions[key];
								for(var id in ids){
									var fnMeta = ids[id];
									output.push({
										package: pkg,
										name: fn,
										id: id,
										summary: fnMeta.summary
									});
								}
							}
						}
					}
					return output;
				}
			}

			pkgLoop:
			for(var pkg in data){
				if(pkg.toLowerCase() == name){
					name = pkg;
					dojo.debug("_onDocSearch found a package");
					//dojo.docs._onDocSelectPackage(input);
					return;
				}
				for(var i = 0, fn; fn = data[pkg][i]; i++){
					if(fn.toLowerCase().indexOf(name) != -1){
						dojo.debug("_onDocSearch(): Search matched " + fn);
						var meta = _this.getPackageMeta({pkg: pkg});
						meta.addCallback(closure(pkg, fn));
						list.push(meta);

						// Build a list of all packages that need to be loaded and their loaded state.
						continue pkgLoop;
					}
				}
			}
			
			list = new dojo.DeferredList(list);
			list.addCallback(function(results){
				dojo.debug("_onDocSearch(): All packages loaded");
				_this._printFunctionResults(results[0][1]);
			});
		});
	},
	_onDocSearchFn: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){
		dojo.debug("_onDocSearchFn(" + evt.name + ")");

		var name = evt.name || evt.pkg;

		dojo.debug("_onDocSearchFn found a function");

		evt.pkgs = packages;
		evt.pkg = name;
		evt.loaded = 0;
		for(var i = 0, pkg; pkg = packages[i]; i++){
			dojo.docs.getPkgMeta(evt, pkg, dojo.docs._onDocResults);
		}
	},
	_onPkgResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){
		dojo.debug("_onPkgResults(" + evt.type + ")");
		var description = "";
		var path = "";
		var methods = {};
		var requires = {};
		if(input){
			input[evt.type] = data;
			if(input.expects && input.expects.pkgresults){
				for(var i = 0, expect; expect = input.expects.pkgresults[i]; i++){
					if(!(expect in input)){
						dojo.debug("_onPkgResults() waiting for more data");
						return;
					}
				}
			}
			path = input.pkgdoc.path;
			description = input.pkgdoc.description;
			methods = input.pkgmeta.methods;
			requires = input.pkgmeta.requires;
		}
		var pkg = evt.name.replace("_", "*");
		var results = {
			path: path,
			description: description,
			size: 0,
			methods: [],
			pkg: pkg,
			selectKey: evt.selectKey,
			requires: requires
		}
		var rePrivate = /_[^.]+$/;
		for(var method in methods){
			if(!rePrivate.test(method)){
				for(var pId in methods[method]){
					results.methods.push({
						pkg: pkg,
						name: method,
						id: pId,
						summary: methods[method][pId].summary
					})
				}
			}
		}
		results.size = results.methods.length;
		dojo.docs._printPkgResult(results);
	},
	_onDocResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){
		dojo.debug("_onDocResults(" + evt.name + "/" + input.pkg + ") " + type);
		++input.loaded;

		if(input.loaded == input.pkgs.length){
			var pkgs = input.pkgs;
			var name = input.pkg;
			var results = {selectKey: evt.selectKey, methods: []};
			var rePrivate = /_[^.]+$/;
			data = dojo.docs._cache;

			for(var i = 0, pkg; pkg = pkgs[i]; i++){
				var methods = dojo.docs._getCache(pkg, "meta", "methods");
				for(var fn in methods){
					if(fn.toLowerCase().indexOf(name) == -1){
						continue;
					}
					if(fn != "requires" && !rePrivate.test(fn)){
						for(var pId in methods[fn]){
							var result = {
								pkg: pkg,
								name: fn,
								id: "_",
								summary: ""
							}
							if(methods[fn][pId].summary){
								result.summary = methods[fn][pId].summary;
							}
							results.methods.push(result);
						}
					}
				}
			}

			dojo.debug("Publishing docResults");
			dojo.docs._printFnResults(results);
		}
	},
	_printFunctionResults: function(results){
		dojo.debug("_printFnResults(): called");
		// summary: Call this function to send the /docs/function/results topic
	},
	_printPkgResult: function(results){
		dojo.debug("_printPkgResult(): called");
	},
	_onDocSelectFunction: function(/*Object*/ input){
		// summary: Get doc, meta, and src
		var name = input.name;
		var pkg = input.pkg;
		dojo.debug("_onDocSelectFunction(" + name + ")");
		if(!name){
			return false;
		}
		if(!input.selectKey){
			input.selectKey = ++dojo.docs._count;
		}
		input.expects = {
			"docresults": ["meta", "doc", "pkgmeta"]
		}
		dojo.docs.getMeta(input, pkg, name, dojo.docs._onDocSelectResults);
		dojo.docs.getDoc(input, pkg, name, dojo.docs._onDocSelectResults);
	},
	_onDocSelectPackage: function(/*Object*/ input){
		dojo.debug("_onDocSelectPackage(" + input.name + ")")
		input.expects = {
			"pkgresults": ["pkgmeta", "pkgdoc"]
		};
		if(!input.selectKey){
			input.selectKey = ++dojo.docs._count;
		}
		dojo.docs.getPkgMeta(input, input.name, dojo.docs._onPkgResults);
		dojo.docs.getPkgDoc(input, input.name, dojo.docs._onPkgResults);
	},
	_onDocSelectResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){
		dojo.debug("_onDocSelectResults(" + evt.type + ", " + evt.name + ")");
		if(evt.type == "meta"){
			dojo.docs.getPkgMeta(input, evt.pkg, dojo.docs._onDocSelectResults);
		}
		if(input){
			input[evt.type] = data;
			if(input.expects && input.expects.docresults){
				for(var i = 0, expect; expect = input.expects.docresults[i]; i++){
					if(!(expect in input)){
						dojo.debug("_onDocSelectResults() waiting for more data");
						return;
					}
				}
			}
		}

		dojo.docs._printFunctionDetail(input);
	},
	
	_printFunctionDetail: function(results) {
		// summary: Call this function to send the /docs/function/detail topic event
	},

	_buildCache: function(/*Object*/ input){
		dojo.debug("_buildCache(" + input.type + ", " + input.name + ")");
		// Get stuff from the input object
		var type = input.type;
		var pkg = input.pkg;
		var callbacks = input.callbacks;
		var id = input.id;
		if(!id){
			id = input.id = "_";
		}
		var name = input.name;
		var selectKey = input.selectKey;

		var META = "meta";
		var METHODS = "methods";
		var SRC = "src";
		var DESCRIPTION = "description";
		var INPUT = "input";
		var LOAD = "load";
		var ERROR = "error";
		
		var docs = dojo.docs;
		var getCache = docs._getCache;
		
		// Stuff to pass to RPC
		var search = [];
	
		if(type == "doc"){
			if(!pkg){
				docs.functionPackages(selectKey, name, function(){ var a = arguments; docs._withPkg.call(this, a[0], a[1], a[2], a[3], "doc"); }, input);
				return;
			}else{
				var cached = getCache(pkg, META, METHODS, name, id, META);
			
				if(cached[DESCRIPTION]){
					callbacks.shift()(LOAD, cached[DESCRIPTION], input, input[INPUT]);
					return;
				}

				var obj = {};
				obj.forFormName = "DocFnForm";
				obj.limit = 1;

				obj.filter = "it/DocFnForm/require = '" + pkg + "' and it/DocFnForm/name = '" + name + "' and ";
				if(id == "_"){
					obj.filter += " not(it/DocFnForm/id)";
				}else{
					obj.filter += " it/DocFnForm/id = '" + id + "'";
				}

				obj.load = function(data){
					var cached = getCache(pkg, META, METHODS, name, id, META);

					var description = "";
					var returns = "";
					if(data.list && data.list.length){
						description = docs._getMainText(data.list[0]["main/text"]);
						returns = data.list[0]["DocFnForm/returns"];
					}

					cached[DESCRIPTION]  = description;
					if(!cached.returns){
						cached.returns = {};
					}
					cached.returns.summary = returns;

					input.type = "fn";
					docs._gotDoc(LOAD, cached, input, input[INPUT]);				
				}
				obj.error = function(data){
					input.type = "fn";
					docs._gotDoc(ERROR, {}, input, input[INPUT]);
				}
				search.push(obj);

				obj = {};
				obj.forFormName = "DocParamForm";

				obj.filter = "it/DocParamForm/fns = '" + pkg + "=>" + name;
				if(id != "_"){
					obj.filter += "=>" + id;
				}
				obj.filter += "'";
			
				obj.load = function(data){
					var cache = getCache(pkg, META, METHODS, name, id, META);
					for(var i = 0, param; param = data.list[i]; i++){
						var pName = param["DocParamForm/name"];
						if(!cache.parameters[pName]){
							cache.parameters[pName] = {};
						}
						cache.parameters[pName].summary = param["DocParamForm/desc"];
					}
					input.type = "param";
					docs._gotDoc(LOAD, cache.parameters, input);
				}
				obj.error = function(data){
					input.type = "param";
					docs._gotDoc(ERROR, {}, input);
				}
				search.push(obj);
			}
		}else if(type == "pkgdoc"){
			var cached = getCache(name, META);

			if(cached[DESCRIPTION]){
				callbacks.shift()(LOAD, {description: cached[DESCRIPTION], path: cached.path}, input, input.input);
				return;
			}

			var obj = {};
			obj.forFormName = "DocPkgForm";
			obj.limit = 1;
			obj.filter = "it/DocPkgForm/require = '" + name + "'";
			
			obj.load = function(data){
				var description = "";
				var list = data.list;
				if(list && list.length && list[0]["main/text"]){
					description = docs._getMainText(list[0]["main/text"]);
					cached[DESCRIPTION] = description;
					cached.path = list[0].name;
				}

				if(callbacks && callbacks.length){
					callbacks.shift()(LOAD, {description: description, path: cached.path}, input, input.input);
				}
			}
			obj.error = function(data){
				if(callbacks && callbacks.length){
					callbacks.shift()(ERROR, "", input, input.input);
				}
			}
			search.push(obj);
		}else if(type == "function_names"){
			var cached = getCache();
			if(!cached.function_names){
				dojo.debug("_buildCache() new cache");
				if(callbacks && callbacks.length){
					docs._callbacks.function_names.push([input, callbacks.shift()]);
				}
				cached.function_names = {loading: true};
				
				var obj = {};
				obj.url = "function_names";
				obj.load = function(type, data, evt){
					cached.function_names = data;
					while(docs._callbacks.function_names.length){
						var parts = docs._callbacks.function_names.pop();
						parts[1](LOAD, data, parts[0]);
					}
				}
				obj.error = function(type, data, evt){
					while(docs._callbacks.function_names.length){
						var parts = docs._callbacks.function_names.pop();
						parts[1](LOAD, {}, parts[0]);
					}
				}
				search.push(obj);
			}else if(cached.function_names.loading){
				dojo.debug("_buildCache() loading cache, adding to callback list");
				if(callbacks && callbacks.length){
					docs._callbacks.function_names.push([input, callbacks.shift()]);
				}
				return;
			}else{
				dojo.debug("_buildCache() loading from cache");
				if(callbacks && callbacks.length){
					callbacks.shift()(LOAD, cached.function_names, input);
				}
				return;
			}
		}else if(type == META || type == SRC){
			if(!pkg){
				if(type == META){
					docs.functionPackages(selectKey, name, function(){ var a = arguments; docs._withPkg.call(this, a[0], a[1], a[2], a[3], META); }, input);
					return;
				}else{
					docs.functionPackages(selectKey, name, function(){ var a = arguments; docs._withPkg.call(this, a[0], a[1], a[2], a[3], SRC); }, input);
					return;
				}
			}else{
				var cached = getCache(pkg, META, METHODS, name, id);

				if(cached[type] && cached[type].returns){
					if(callbacks && callbacks.length){
						callbacks.shift()(LOAD, cached[type], input);
						return;
					}
				}

				dojo.debug("Finding " + type + " for: " + pkg + ", function: " + name + ", id: " + id);

				var obj = {};

				if(type == SRC){
					obj.mimetype = "text/plain"
				}
				obj.url = pkg + "/" + name + "/" + id + "/" + type;
				obj.load = function(type, data, evt){
					dojo.debug("_buildCache() loaded " + input.type);

					if(input.type == SRC){
						getCache(pkg, META, METHODS, name, id).src = data;
						if(callbacks && callbacks.length){
							callbacks.shift()(LOAD, data, input, input[INPUT]);
						}
					}else{
						var cache = getCache(pkg, META, METHODS, name, id, META);
						if(!cache.parameters){
							cache.parameters = {};
						}
						for(var i = 0, param; param = data.parameters[i]; i++){
							if(!cache.parameters[param[1]]){
								cache.parameters[param[1]] = {};
							}
							cache.parameters[param[1]].type = param[0];
						}
						if(!cache.returns){
							cache.returns = {};
						}
						cache.returns.type = data.returns;
					}

					if(callbacks && callbacks.length){
						callbacks.shift()(LOAD, cache, input, input[INPUT]);
					}
				}
				obj.error = function(type, data, evt){
					if(callbacks && callbacks.length){
						callbacks.shift()(ERROR, {}, input, input[INPUT]);
					}
				}
			}

			search.push(obj);
		}else if(type == "pkgmeta"){
			var cached = getCache(name, "meta");

			if(cached.requires){
				if(callbacks && callbacks.length){
					callbacks.shift()(LOAD, cached, input, input[INPUT]);
					return;
				}
			}

			dojo.debug("Finding package meta for: " + name);

			var obj = {};

			obj.url = name + "/meta";
			obj.load = function(type, data, evt){
				dojo.debug("_buildCache() loaded for: " + name);
		
				var methods = data.methods;
				if(methods){
					for(var method in methods){
						if (method == "is") {
							continue;
						}
						for(var pId in methods[method]){
							getCache(name, META, METHODS, method, pId, META).summary = methods[method][pId];
						}
					}
				}

				var requires = data.requires;
				var cache = getCache(name, META);
				if(requires){
					cache.requires = requires;
				}
				if(callbacks && callbacks.length){
					callbacks.shift()(LOAD, cache, input, input[INPUT]);
				}
			}
			obj.error = function(type, data, evt){
				if(callbacks && callbacks.length){
					callbacks.shift()(ERROR, {}, input, input[INPUT]);
				}
			}
			search.push(obj);
		}
		
		for(var i = 0, obj; obj = search[i]; i++){
			var load = obj.load;
			var error = obj.error;
			delete obj.load;
			delete obj.error;
			var mimetype = obj.mimetype;
			if(!mimetype){
				mimetype = "text/json"
			}
			if(obj.url){
				dojo.io.bind({
					url: new dojo.uri.Uri(docs._url, obj.url),
					input: input,
					mimetype: mimetype,
					error: error,
					load: load
				});
			}else{
				docs._rpc.callRemote("search", obj).addCallbacks(load, error);
			}
		}
	},
	selectFunction: function(/*String*/ name, /*String?*/ id){
		// summary: The combined information
	},
	savePackage: function(/*Object*/ callbackObject, /*String*/ callback, /*Object*/ parameters){
		dojo.event.kwConnect({
			srcObj: dojo.docs,
			srcFunc: "_savedPkgRpc",
			targetObj: callbackObject,
			targetFunc: callback,
			once: true
		});
		
		var props = {};
		var cache = dojo.docs._getCache(parameters.pkg, "meta");

		var i = 1;

		if(!cache.path){
			var path = "id";
			props[["pname", i].join("")] = "DocPkgForm/require";
			props[["pvalue", i++].join("")] = parameters.pkg;
		}else{
			var path = cache.path;
		}

		props.form = "//DocPkgForm";
		props.path = ["/WikiHome/DojoDotDoc/", path].join("");

		if(parameters.description){
			props[["pname", i].join("")] = "main/text";
			props[["pvalue", i++].join("")] = parameters.description;
		}
		
		dojo.docs._rpc.callRemote("saveForm",	props).addCallbacks(dojo.docs._pkgRpc, dojo.docs._pkgRpc);
	},
	_pkgRpc: function(data){
		if(data.name){
			dojo.docs._getCache(data["DocPkgForm/require"], "meta").path = data.name;
			dojo.docs._savedPkgRpc("load");
		}else{
			dojo.docs._savedPkgRpc("error");
		}
	},
	_savedPkgRpc: function(type){
	},
	functionPackages: function(/*mixed*/ selectKey, /*String*/ name, /*Function*/ callback, /*Object*/ input){
		// summary: Gets the package associated with a function and stores it in the .pkg value of input
		dojo.debug("functionPackages() name: " + name);

		if(!input){
			input = {};
		}
		if(!input.callbacks){
			input.callbacks = [];
		}

		input.type = "function_names";
		input.name = name;
		input.callbacks.unshift(callback);
		input.callbacks.unshift(dojo.docs._functionPackages);
		dojo.docs._buildCache(input);
	},
	_functionPackages: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){
		dojo.debug("_functionPackages() name: " + evt.name);
		evt.pkg = '';

		var results = [];
		var data = dojo.docs._cache['function_names'];
		for(var key in data){
			if(dojo.lang.inArray(data[key], evt.name)){
				dojo.debug("_functionPackages() package: " + key);
				results.push(key);
			}
		}

		if(evt.callbacks && evt.callbacks.length){
			evt.callbacks.shift()(type, results, evt, evt.input);
		}
	},
	setUserName: function(/*String*/ name){
		dojo.docs._userName = name;
		if(name && dojo.docs._password){
			dojo.docs._logIn();
		}
	},
	setPassword: function(/*String*/ password){
		dojo.docs._password = password;
		if(password && dojo.docs._userName){
			dojo.docs._logIn();
		}
	},
	_logIn: function(){
		dojo.io.bind({
			url: dojo.docs._rpc.serviceUrl.toString(),
			method: "post",
			mimetype: "text/json",
			content: {
				username: dojo.docs._userName,
				password: dojo.docs._password
			},
			load: function(type, data){
				if(data.error){
					dojo.docs.logInSuccess();
				}else{
					dojo.docs.logInFailure();
				}
			},
			error: function(){
				dojo.docs.logInFailure();
			}
		});
	},
	logInSuccess: function(){},
	logInFailure: function(){},
	_set: function(/*Object*/ base, /*String...*/ keys, /*String*/ value){
		var args = [];
		for(var i = 0, arg; arg = arguments[i]; i++){
			args.push(arg);
		}

		if(args.length < 3) return;
		base = args.shift();
		value = args.pop();
		var key = args.pop();
		for(var i = 0, arg; arg = args[i]; i++){
			if(typeof base[arg] != "object"){
				base[arg] = {};
			}
			base = base[arg];
		}
		base[key] = value;
	},
	_getCache: function(/*String...*/ keys){
		var obj = dojo.docs._cache;
		for(var i = 0; i < arguments.length; i++){
			var arg = arguments[i];
			if(!obj[arg]){
				obj[arg] = {};
			}
			obj = obj[arg];
		}
		return obj;
	}
});

dojo.event.topic.subscribe("/docs/search", dojo.docs, "_onDocSearch");
dojo.event.topic.subscribe("/docs/function/select", dojo.docs, "_onDocSelectFunction");
dojo.event.topic.subscribe("/docs/package/select", dojo.docs, "_onDocSelectPackage");

dojo.event.topic.registerPublisher("/docs/function/results", dojo.docs, "_printFunctionResults");
dojo.event.topic.registerPublisher("/docs/function/detail", dojo.docs, "_printFunctionDetail");
dojo.event.topic.registerPublisher("/docs/package/detail", dojo.docs, "_printPkgResult");
__CPAN_FILE__ src/regexp.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.regexp");
dojo.evalObjPath("dojo.regexp.us", true);	// this file also defines stuff in the dojo.regexp.us module (TODO: move to separate file?)

// *** Regular Expression Generators ***

dojo.regexp.tld = function(/*Object?*/flags){
	// summary: Builds a RE that matches a top-level domain
	//
	// flags:
	//    flags.allowCC  Include 2 letter country code domains.  Default is true.
	//    flags.allowGeneric  Include the generic domains.  Default is true.
	//    flags.allowInfra  Include infrastructure domains.  Default is true.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.allowCC != "boolean"){ flags.allowCC = true; }
	if(typeof flags.allowInfra != "boolean"){ flags.allowInfra = true; }
	if(typeof flags.allowGeneric != "boolean"){ flags.allowGeneric = true; }

	// Infrastructure top-level domain - only one at present
	var infraRE = "arpa";

	// Generic top-level domains RE.
	var genericRE = 
		"aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|xxx|jobs|mobi|post";
	
	// Country Code top-level domains RE
	var ccRE = 
		"ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|" +
		"bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|" +
		"ec|ee|eg|er|es|et|fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|" +
		"hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kr|kw|ky|kz|la|" +
		"lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|" +
		"mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|" +
		"ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sk|sl|sm|sn|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|" +
		"to|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw";

	// Build top-level domain RE
	var a = [];
	if(flags.allowInfra){ a.push(infraRE); }
	if(flags.allowGeneric){ a.push(genericRE); }
	if(flags.allowCC){ a.push(ccRE); }

	var tldRE = "";
	if (a.length > 0) {
		tldRE = "(" + a.join("|") + ")";
	}

	return tldRE; // String
}

dojo.regexp.ipAddress = function(/*Object?*/flags){
	// summary: Builds a RE that matches an IP Address
	//
	// description:
	//  Supports 5 formats for IPv4: dotted decimal, dotted hex, dotted octal, decimal and hexadecimal.
	//  Supports 2 formats for Ipv6.
	//
	// flags  An object.  All flags are boolean with default = true.
	//    flags.allowDottedDecimal  Example, 207.142.131.235.  No zero padding.
	//    flags.allowDottedHex  Example, 0x18.0x11.0x9b.0x28.  Case insensitive.  Zero padding allowed.
	//    flags.allowDottedOctal  Example, 0030.0021.0233.0050.  Zero padding allowed.
	//    flags.allowDecimal  Example, 3482223595.  A decimal number between 0-4294967295.
	//    flags.allowHex  Example, 0xCF8E83EB.  Hexadecimal number between 0x0-0xFFFFFFFF.
	//      Case insensitive.  Zero padding allowed.
	//    flags.allowIPv6   IPv6 address written as eight groups of four hexadecimal digits.
	//    flags.allowHybrid   IPv6 address written as six groups of four hexadecimal digits
	//      followed by the usual 4 dotted decimal digit notation of IPv4. x:x:x:x:x:x:d.d.d.d

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.allowDottedDecimal != "boolean"){ flags.allowDottedDecimal = true; }
	if(typeof flags.allowDottedHex != "boolean"){ flags.allowDottedHex = true; }
	if(typeof flags.allowDottedOctal != "boolean"){ flags.allowDottedOctal = true; }
	if(typeof flags.allowDecimal != "boolean"){ flags.allowDecimal = true; }
	if(typeof flags.allowHex != "boolean"){ flags.allowHex = true; }
	if(typeof flags.allowIPv6 != "boolean"){ flags.allowIPv6 = true; }
	if(typeof flags.allowHybrid != "boolean"){ flags.allowHybrid = true; }

	// decimal-dotted IP address RE.
	var dottedDecimalRE = 
		// Each number is between 0-255.  Zero padding is not allowed.
		"((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";

	// dotted hex IP address RE.  Each number is between 0x0-0xff.  Zero padding is allowed, e.g. 0x00.
	var dottedHexRE = "(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]";

	// dotted octal IP address RE.  Each number is between 0000-0377.  
	// Zero padding is allowed, but each number must have at least 4 characters.
	var dottedOctalRE = "(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]";

	// decimal IP address RE.  A decimal number between 0-4294967295.  
	var decimalRE =  "(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|" +
		"4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])";

	// hexadecimal IP address RE. 
	// A hexadecimal number between 0x0-0xFFFFFFFF. Case insensitive.  Zero padding is allowed.
	var hexRE = "0[xX]0*[\\da-fA-F]{1,8}";

	// IPv6 address RE. 
	// The format is written as eight groups of four hexadecimal digits, x:x:x:x:x:x:x:x,
	// where x is between 0000-ffff. Zero padding is optional. Case insensitive. 
	var ipv6RE = "([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}";

	// IPv6/IPv4 Hybrid address RE. 
	// The format is written as six groups of four hexadecimal digits, 
	// followed by the 4 dotted decimal IPv4 format. x:x:x:x:x:x:d.d.d.d
	var hybridRE = "([\\da-fA-F]{1,4}\\:){6}" + 
		"((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";

	// Build IP Address RE
	var a = [];
	if(flags.allowDottedDecimal){ a.push(dottedDecimalRE); }
	if(flags.allowDottedHex){ a.push(dottedHexRE); }
	if(flags.allowDottedOctal){ a.push(dottedOctalRE); }
	if(flags.allowDecimal){ a.push(decimalRE); }
	if(flags.allowHex){ a.push(hexRE); }
	if(flags.allowIPv6){ a.push(ipv6RE); }
	if(flags.allowHybrid){ a.push(hybridRE); }

	var ipAddressRE = "";
	if(a.length > 0){
		ipAddressRE = "(" + a.join("|") + ")";
	}

	return ipAddressRE; // String
}

dojo.regexp.host = function(/*Object?*/flags){
	// summary: Builds a RE that matches a host
	// description: A host is a domain name or an IP address, possibly followed by a port number.
	// flags: An object.
	//    flags.allowIP  Allow an IP address for hostname.  Default is true.
	//    flags.allowLocal  Allow the host to be "localhost".  Default is false.
	//    flags.allowPort  Allow a port number to be present.  Default is true.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.allowIP != "boolean"){ flags.allowIP = true; }
	if(typeof flags.allowLocal != "boolean"){ flags.allowLocal = false; }
	if(typeof flags.allowPort != "boolean"){ flags.allowPort = true; }

	// Domain names can not end with a dash.
	var domainNameRE = "([0-9a-zA-Z]([-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?\\.)+" + dojo.regexp.tld(flags);

	// port number RE
	var portRE = ( flags.allowPort ) ? "(\\:" + dojo.regexp.integer({signed: false}) + ")?" : "";

	// build host RE
	var hostNameRE = domainNameRE;
	if(flags.allowIP){ hostNameRE += "|" +  dojo.regexp.ipAddress(flags); }
	if(flags.allowLocal){ hostNameRE += "|localhost"; }

	return "(" + hostNameRE + ")" + portRE; // String
}

dojo.regexp.url = function(/*Object?*/flags){
	// summary: Builds a regular expression that matches a URL
	//
	// flags: An object
	//    flags.scheme  Can be true, false, or [true, false]. 
	//      This means: required, not allowed, or match either one.
	//    flags in regexp.host can be applied.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.scheme == "undefined"){ flags.scheme = [true, false]; }

	// Scheme RE
	var protocolRE = dojo.regexp.buildGroupRE(flags.scheme,
		function(q){ if(q){ return "(https?|ftps?)\\://"; } return ""; }
	);

	// Path and query and anchor RE
	var pathRE = "(/([^?#\\s/]+/)*)?([^?#\\s/]+(\\?[^?#\\s/]*)?(#[A-Za-z][\\w.:-]*)?)?";

	return protocolRE + dojo.regexp.host(flags) + pathRE;
}


dojo.regexp.emailAddress = function(/*Object?*/flags){
	// summary: Builds a regular expression that matches an email address
	//
	//flags: An object
	//    flags.allowCruft  Allow address like <mailto:foo@yahoo.com>.  Default is false.
	//    flags in regexp.host can be applied.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if (typeof flags.allowCruft != "boolean") { flags.allowCruft = false; }
	flags.allowPort = false; // invalid in email addresses

	// user name RE - apostrophes are valid if there's not 2 in a row
	var usernameRE = "([\\da-z]+[-._+&'])*[\\da-z]+";

	// build emailAddress RE
	var emailAddressRE = usernameRE + "@" + dojo.regexp.host(flags);

	// Allow email addresses with cruft
	if ( flags.allowCruft ) {
		emailAddressRE = "<?(mailto\\:)?" + emailAddressRE + ">?";
	}

	return emailAddressRE; // String
}

dojo.regexp.emailAddressList = function(/*Object?*/flags){
	// summary: Builds a regular expression that matches a list of email addresses.
	//
	// flags: An object.
	//    flags.listSeparator  The character used to separate email addresses.  Default is ";", ",", "\n" or " ".
	//    flags in regexp.emailAddress can be applied.
	//    flags in regexp.host can be applied.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.listSeparator != "string"){ flags.listSeparator = "\\s;,"; }

	// build a RE for an Email Address List
	var emailAddressRE = dojo.regexp.emailAddress(flags);
	var emailAddressListRE = "(" + emailAddressRE + "\\s*[" + flags.listSeparator + "]\\s*)*" + 
		emailAddressRE + "\\s*[" + flags.listSeparator + "]?\\s*";

	return emailAddressListRE; // String
}

dojo.regexp.integer = function(/*Object?*/flags){
	// summary: Builds a regular expression that matches an integer
	//
	// flags: An object
	//    flags.signed  The leading plus-or-minus sign.  Can be true, false, or [true, false].
	//      Default is [true, false], (i.e. will match if it is signed or unsigned).
	//    flags.separator  The character used as the thousands separator.  Default is no separator.
	//      For more than one symbol use an array, e.g. [",", ""], makes ',' optional.
	//	flags.groupSize group size between separators
	//	flags.groupSize2 second grouping (for India)

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.signed == "undefined"){ flags.signed = [true, false]; }
	if(typeof flags.separator == "undefined"){
		flags.separator = "";
	} else if(typeof flags.groupSize == "undefined"){
		flags.groupSize = 3;
	}
	// build sign RE
	var signRE = dojo.regexp.buildGroupRE(flags.signed,
		function(q) { return q ? "[-+]" : ""; }
	);

	// number RE
	var numberRE = dojo.regexp.buildGroupRE(flags.separator,
		function(sep){ 
			if(sep == ""){ 
				return "(0|[1-9]\\d*)";
			}
			var grp = flags.groupSize, grp2 = flags.groupSize2;
			if(typeof grp2 != "undefined"){
				var grp2RE = "(0|[1-9]\\d{0," + (grp2-1) + "}([" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
				return ((grp-grp2) > 0) ? "(" + grp2RE + "|(0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
			}
			return  "(0|[1-9]\\d{0," + (grp-1) + "}([" + sep + "]\\d{" + grp + "})*)";
		}
	);

	// integer RE
	return signRE + numberRE; // String
}

dojo.regexp.realNumber = function(/*Object?*/flags){
	// summary: Builds a regular expression to match a real number in exponential notation
	//
	// flags:An object
	//    flags.places  The integer number of decimal places.
	//      If not given, the decimal part is optional and the number of places is unlimited.
	//    flags.decimal  A string for the character used as the decimal point.  Default is ".".
	//    flags.fractional  Whether decimal places are allowed.
	//      Can be true, false, or [true, false].  Default is [true, false]
	//    flags.exponent  Express in exponential notation.  Can be true, false, or [true, false].
	//      Default is [true, false], (i.e. will match if the exponential part is present are not).
	//    flags.eSigned  The leading plus-or-minus sign on the exponent.  Can be true, false, 
	//      or [true, false].  Default is [true, false], (i.e. will match if it is signed or unsigned).
	//    flags in regexp.integer can be applied.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.places != "number"){ flags.places = Infinity; }
	if(typeof flags.decimal != "string"){ flags.decimal = "."; }
	if(typeof flags.fractional == "undefined"){ flags.fractional = [true, false]; }
	if(typeof flags.exponent == "undefined"){ flags.exponent = [true, false]; }
	if(typeof flags.eSigned == "undefined"){ flags.eSigned = [true, false]; }

	// integer RE
	var integerRE = dojo.regexp.integer(flags);

	// decimal RE
	var decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
		function(q){
			var re = "";
			if(q && (flags.places > 0)){
				re = "\\" + flags.decimal;
				if(flags.places == Infinity){ 
					re = "(" + re + "\\d+)?"; 
				}else{ 
					re = re + "\\d{" + flags.places + "}"; 
				}
			}

			return re;
		}
	);

	// exponent RE
	var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
		function(q){ 
			if(q){ return "([eE]" + dojo.regexp.integer({ signed: flags.eSigned}) + ")"; }
			return ""; 
		}
	);

	// real number RE
	return integerRE + decimalRE + exponentRE; // String
}

dojo.regexp.currency = function(/*Object?*/flags){
	// summary: Builds a regular expression to match a monetary value
	//
	// flags: An object
	//    flags.symbol  A currency symbol such as Yen "ï¿½", Pound "ï¿½", or the Euro sign "ï¿½".  
	//      Default is "$".  For more than one symbol use an array, e.g. ["$", ""], makes $ optional.
	//    flags.placement  The symbol can come "before" the number or "after" the number.  Default is "before".
	//    flags.signPlacement  The sign can come "before" the number or "after" the sign,
	//      "around" to put parentheses around negative values, or "end" for the final char.  Default is "before".
	//    flags.cents  deprecated, in favor of flags.fractional
	//    flags in regexp.realNumber can be applied except exponent, eSigned.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.signed == "undefined"){ flags.signed = [true, false]; }
	if(typeof flags.symbol == "undefined"){ flags.symbol = "$"; }
	if(typeof flags.placement != "string"){ flags.placement = "before"; }
	if(typeof flags.signPlacement != "string"){ flags.signPlacement = "before"; }
	if(typeof flags.separator == "undefined"){ flags.separator = ","; }
	if(typeof flags.fractional == "undefined" && typeof flags.cents != "undefined"){
		dojo.deprecated("dojo.regexp.currency: flags.cents", "use flags.fractional instead", "0.5");
		flags.fractional = flags.cents;
	}
	if(typeof flags.decimal != "string"){ flags.decimal = "."; }

	// build sign RE
	var signRE = dojo.regexp.buildGroupRE(flags.signed,
		function(q){ if (q){ return "[-+]"; } return ""; }
	);

	// build symbol RE
	var symbolRE = dojo.regexp.buildGroupRE(flags.symbol,
		function(symbol){ 
			// escape all special characters
			return "\\s?" + symbol.replace( /([.$?*!=:|\\\/^])/g, "\\$1") + "\\s?";
		}
	);

	switch (flags.signPlacement){
		case "before":
			symbolRE = signRE + symbolRE;
			break;
		case "after":
			symbolRE = symbolRE + signRE;
			break;
	}

	// number RE
	var flagsCopy = flags; //TODO: copy by value?
	flagsCopy.signed = false; flagsCopy.exponent = false;
	var numberRE = dojo.regexp.realNumber(flagsCopy);

	// build currency RE
	var currencyRE;
	switch (flags.placement){
		case "before":
			currencyRE = symbolRE + numberRE;
			break;
		case "after":
			currencyRE = numberRE + symbolRE;
			break;
	}

	switch (flags.signPlacement){
		case "around":
			currencyRE = "(" + currencyRE + "|" + "\\(" + currencyRE + "\\)" + ")";
			break;
		case "begin":
			currencyRE = signRE + currencyRE;
			break;
		case "end":
			currencyRE = currencyRE + signRE;
			break;
	}
	return currencyRE; // String
}


dojo.regexp.us.state = function(/*Object?*/flags){
	// summary: A regular expression to match US state and territory abbreviations
	//
	// flags  An object.
	//    flags.allowTerritories  Allow Guam, Puerto Rico, etc.  Default is true.
	//    flags.allowMilitary  Allow military 'states', e.g. Armed Forces Europe (AE).  Default is true.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.allowTerritories != "boolean"){ flags.allowTerritories = true; }
	if(typeof flags.allowMilitary != "boolean"){ flags.allowMilitary = true; }

	// state RE
	var statesRE = 
		"AL|AK|AZ|AR|CA|CO|CT|DE|DC|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|" + 
		"NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY";

	// territories RE
	var territoriesRE = "AS|FM|GU|MH|MP|PW|PR|VI";

	// military states RE
	var militaryRE = "AA|AE|AP";

	// Build states and territories RE
	if(flags.allowTerritories){ statesRE += "|" + territoriesRE; }
	if(flags.allowMilitary){ statesRE += "|" + militaryRE; }

	return "(" + statesRE + ")"; // String
}

dojo.regexp.time = function(/*Object?*/flags){
	// summary: Builds a regular expression to match any International format for time
	// description: The RE can match one format or one of multiple formats.
	//
	//  Format
	//  h        12 hour, no zero padding.
	//  hh       12 hour, has leading zero.
	//  H        24 hour, no zero padding.
	//  HH       24 hour, has leading zero.
	//  m        minutes, no zero padding.
	//  mm       minutes, has leading zero.
	//  s        seconds, no zero padding.
	//  ss       seconds, has leading zero.
	//  t        am or pm, case insensitive.
	//  All other characters must appear literally in the expression.
	//
	//  Example
	//    "h:m:s t"  ->   2:5:33 PM
	//    "HH:mm:ss" ->  14:05:33
	//
	// flags: An object
	//    flags.format  A string or an array of strings.  Default is "h:mm:ss t".
	//    flags.amSymbol  The symbol used for AM.  Default is "AM".
	//    flags.pmSymbol  The symbol used for PM.  Default is "PM".

	dojo.deprecated("dojo.regexp.time", "Use dojo.date.parse instead", "0.5");

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.format == "undefined"){ flags.format = "h:mm:ss t"; }
	if(typeof flags.amSymbol != "string"){ flags.amSymbol = "AM"; }
	if(typeof flags.pmSymbol != "string"){ flags.pmSymbol = "PM"; }

	// Converts a time format to a RE
	var timeRE = function(format){
		// escape all special characters
		format = format.replace( /([.$?*!=:|{}\(\)\[\]\\\/^])/g, "\\$1");
		var amRE = flags.amSymbol.replace( /([.$?*!=:|{}\(\)\[\]\\\/^])/g, "\\$1");
		var pmRE = flags.pmSymbol.replace( /([.$?*!=:|{}\(\)\[\]\\\/^])/g, "\\$1");

		// replace tokens with Regular Expressions
		format = format.replace("hh", "(0[1-9]|1[0-2])");
		format = format.replace("h", "([1-9]|1[0-2])");
		format = format.replace("HH", "([01][0-9]|2[0-3])");
		format = format.replace("H", "([0-9]|1[0-9]|2[0-3])");
		format = format.replace("mm", "([0-5][0-9])");
		format = format.replace("m", "([1-5][0-9]|[0-9])");
		format = format.replace("ss", "([0-5][0-9])");
		format = format.replace("s", "([1-5][0-9]|[0-9])");
		format = format.replace("t", "\\s?(" + amRE + "|" + pmRE + ")\\s?" );

		return format; // String
	};

	// build RE for multiple time formats
	return dojo.regexp.buildGroupRE(flags.format, timeRE); // String
}

dojo.regexp.numberFormat = function(/*Object?*/flags){
	// summary: Builds a regular expression to match any sort of number based format
	// description:
	//  Use this method for phone numbers, social security numbers, zip-codes, etc.
	//  The RE can match one format or one of multiple formats.
	//
	//  Format
	//    #        Stands for a digit, 0-9.
	//    ?        Stands for an optional digit, 0-9 or nothing.
	//    All other characters must appear literally in the expression.
	//
	//  Example   
	//    "(###) ###-####"       ->   (510) 542-9742
	//    "(###) ###-#### x#???" ->   (510) 542-9742 x153
	//    "###-##-####"          ->   506-82-1089       i.e. social security number
	//    "#####-####"           ->   98225-1649        i.e. zip code
	//
	// flags:  An object
	//    flags.format  A string or an Array of strings for multiple formats.

	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	if(typeof flags.format == "undefined"){ flags.format = "###-###-####"; }

	// Converts a number format to RE.
	var digitRE = function(format){
		// escape all special characters, except '?'
		format = format.replace( /([.$*!=:|{}\(\)\[\]\\\/^])/g, "\\$1");

		// Now replace '?' with Regular Expression
		format = format.replace(/\?/g, "\\d?");

		// replace # with Regular Expression
		format = format.replace(/#/g, "\\d");

		return format; // String
	};

	// build RE for multiple number formats
	return dojo.regexp.buildGroupRE(flags.format, digitRE); //String
}


dojo.regexp.buildGroupRE = function(/*value or Array of values*/a, /*Function(x) returns a regular expression as a String*/re){
	// summary: Builds a regular expression that groups subexpressions
	// description: A utility function used by some of the RE generators.
	//  The subexpressions are constructed by the function, re, in the second parameter.
	//  re builds one subexpression for each elem in the array a, in the first parameter.
	//  Returns a string for a regular expression that groups all the subexpressions.
	//
	// a:  A single value or an array of values.
	// re:  A function.  Takes one parameter and converts it to a regular expression. 

	// case 1: a is a single value.
	if(!(a instanceof Array)){
		return re(a); // String
	}

	// case 2: a is an array
	var b = [];
	for (var i = 0; i < a.length; i++){
		// convert each elem to a RE
		b.push(re(a[i]));
	}

	 // join the REs as alternatives in a RE group.
	return "(" + b.join("|") + ")"; // String
}

__CPAN_FILE__ src/hostenv_rhino.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
* Rhino host environment
*/
// make jsc shut up (so we can use jsc for sanity checking) 
/*@cc_on
@if (@_jscript_version >= 7)
var loadClass; var print; var load; var quit; var version; var Packages; var java;
@end
@*/

dojo.hostenv.println=function(line){
	print(line);
}

dojo.locale = dojo.locale || java.util.Locale.getDefault().toString().replace('_','-').toLowerCase();
dojo.render.name = dojo.hostenv.name_ = 'rhino';
dojo.hostenv.getVersion = function() {return version();};

if (dj_undef("byId")) {
	dojo.byId = function(id, doc){
		if(id && (typeof id == "string" || id instanceof String)){
			if(!doc){ doc = document; }
			return doc.getElementById(id);
		}
		return id; // assume it's a node
	}
}

// see comments in spidermonkey loadUri
dojo.hostenv.loadUri = function(uri, cb){
	try{
		var local = (new java.io.File(uri)).exists();
		if(!local){
			try{
				// try it as a file first, URL second
				var stream = (new java.net.URL(uri)).openStream();
				// close the stream so we don't leak resources
				stream.close();
			}catch(e){
				// no debug output; this failure just means the uri was not found.
				return false;
			}
		}
//FIXME: Use Rhino 1.6 native readFile/readUrl if available?
		if(cb){
			var contents = (local ? readText : readUri)(uri, "UTF-8");
			cb(eval('('+contents+')'));
		}else{
			load(uri);
		}
		return true;
	}catch(e){
		dojo.debug("rhino load('" + uri + "') failed. Exception: " + e);
		return false;
	}
}

dojo.hostenv.exit = function(exitcode){ 
	quit(exitcode);
}

// Hack to determine current script...
//
// These initial attempts failed:
//   1. get an EcmaError and look at e.getSourceName(): try {eval ("static in return")} catch(e) { ...
//   Won't work because NativeGlobal.java only does a put of "name" and "message", not a wrapped reflecting object.
//   Even if the EcmaError object had the sourceName set.
//  
//   2. var e = Packages.org.mozilla.javascript.Context.getCurrentContext().reportError('');
//   Won't work because it goes directly to the errorReporter, not the return value.
//   We want context.interpreterSourceFile and context.interpreterLine, which are used in static Context.getSourcePositionFromStack
//   (set by Interpreter.java at interpretation time, if in interpreter mode).
//
//   3. var e = Packages.org.mozilla.javascript.Context.getCurrentContext().reportRuntimeError('');
//   This returns an object, but e.message still does not have source info.
//   In compiler mode, perhaps not set; in interpreter mode, perhaps not used by errorReporter?
//
// What we found works is to do basically the same hack as is done in getSourcePositionFromStack,
// making a new java.lang.Exception() and then calling printStackTrace on a string stream.
// We have to parse the string for the .js files (different from the java files).
// This only works however in compiled mode (-opt 0 or higher).
// In interpreter mode, entire stack is java.
// When compiled, printStackTrace is like:
// java.lang.Exception
//	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
//	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
//	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
//	at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
//	at org.mozilla.javascript.NativeJavaClass.constructSpecific(NativeJavaClass.java:228)
//	at org.mozilla.javascript.NativeJavaClass.construct(NativeJavaClass.java:185)
//	at org.mozilla.javascript.ScriptRuntime.newObject(ScriptRuntime.java:1269)
//	at org.mozilla.javascript.gen.c2.call(/Users/mda/Sites/burstproject/testrhino.js:27)
//    ...
//	at org.mozilla.javascript.tools.shell.Main.main(Main.java:76)
//
// Note may get different answers based on:
//    Context.setOptimizationLevel(-1)
//    Context.setGeneratingDebug(true)
//    Context.setGeneratingSource(true) 
//
// Some somewhat helpful posts:
//    http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=9v9n0g%246gr1%40ripley.netscape.com
//    http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3BAA2DC4.6010702%40atg.com
//
// Note that Rhino1.5R5 added source name information in some exceptions.
// But this seems not to help in command-line Rhino, because Context.java has an error reporter
// so no EvaluationException is thrown.

// do it by using java java.lang.Exception
function dj_rhino_current_script_via_java(depth) {
    var optLevel = Packages.org.mozilla.javascript.Context.getCurrentContext().getOptimizationLevel();  
   // if (optLevel == -1){ dojo.unimplemented("getCurrentScriptURI (determine current script path for rhino when interpreter mode)", ''); }
    var caw = new java.io.CharArrayWriter();
    var pw = new java.io.PrintWriter(caw);
    var exc = new java.lang.Exception();
    var s = caw.toString();
    // we have to exclude the ones with or without line numbers because they put double entries in:
    //   at org.mozilla.javascript.gen.c3._c4(/Users/mda/Sites/burstproject/burst/Runtime.js:56)
    //   at org.mozilla.javascript.gen.c3.call(/Users/mda/Sites/burstproject/burst/Runtime.js)
    var matches = s.match(/[^\(]*\.js\)/gi);
    if(!matches){
		throw Error("cannot parse printStackTrace output: " + s);
	}

    // matches[0] is entire string, matches[1] is this function, matches[2] is caller, ...
    var fname = ((typeof depth != 'undefined')&&(depth)) ? matches[depth + 1] : matches[matches.length - 1];
    var fname = matches[3];
	if(!fname){ fname = matches[1]; }
    // print("got fname '" + fname + "' from stack string '" + s + "'");
    if (!fname){ throw Error("could not find js file in printStackTrace output: " + s); }
    //print("Rhino getCurrentScriptURI returning '" + fname + "' from: " + s); 
    return fname;
}

// UNUSED: leverage new support in native exception for getSourceName
/*
function dj_rhino_current_script_via_eval_exception() {
    var exc;
    // 'ReferenceError: "undefinedsymbol" is not defined.'
    try {eval ("undefinedsymbol()") } catch(e) {exc = e;}
    // 'Error: whatever'
    // try{throw Error("whatever");} catch(e) {exc = e;}
    // 'SyntaxError: identifier is a reserved word'
    // try {eval ("static in return")} catch(e) { exc = e; }
   // print("got exception: '" + exc + "' type=" + (typeof exc));
    // print("exc.stack=" + (typeof exc.stack));
    var sn = exc.rhinoException.getSourceName();
    print("SourceName=" + sn);
    return sn;
}*/

// reading a file from disk in Java is a humiliating experience by any measure.
// Lets avoid that and just get the freaking text
function readText(path, encoding){
	encoding = encoding || "utf-8";
	// NOTE: we intentionally avoid handling exceptions, since the caller will
	// want to know
	var jf = new java.io.File(path);
	var is = new java.io.FileInputStream(jf);
	return dj_readInputStream(is, encoding);
}

function readUri(uri, encoding){
	var conn = (new java.net.URL(uri)).openConnection();
	encoding = encoding || conn.getContentEncoding() || "utf-8";
	var is = conn.getInputStream();
	return dj_readInputStream(is, encoding);
}

function dj_readInputStream(is, encoding){
	var input = new java.io.BufferedReader(new java.io.InputStreamReader(is, encoding));
	try {
		var sb = new java.lang.StringBuffer();
		var line = "";
		while((line = input.readLine()) !== null){
			sb.append(line);
			sb.append(java.lang.System.getProperty("line.separator"));
		}
		return sb.toString();
	} finally {
		input.close();
	}
}

// call this now because later we may not be on the top of the stack
if(!djConfig.libraryScriptUri.length){
	try{
		djConfig.libraryScriptUri = dj_rhino_current_script_via_java(1);
	}catch(e){
		// otherwise just fake it
		if(djConfig["isDebug"]){
			print("\n");
			print("we have no idea where Dojo is located.");
			print("Please try loading rhino in a non-interpreted mode or set a");
			print("\n\tdjConfig.libraryScriptUri\n");
			print("Setting the dojo path to './'");
			print("This is probably wrong!");
			print("\n");
			print("Dojo will try to load anyway");
		}
		djConfig.libraryScriptUri = "./";
	}
}

dojo.doc = function(){
	// summary:
	//		return the document object associated with the dojo.global()
	return document;
}

dojo.body = function(){
	return document.body;	
}

function setTimeout(func, delay){
	// summary: provides timed callbacks using Java threads

	var def={
		sleepTime:delay,
		hasSlept:false,
		
		run:function(){
			if (!this.hasSlept){
				this.hasSlept=true;
				java.lang.Thread.currentThread().sleep(this.sleepTime);
			}
			try {
				func();
			} catch(e){dojo.debug("Error running setTimeout thread:" + e);}
		}
	};
	
	var runnable=new java.lang.Runnable(def);
	var thread=new java.lang.Thread(runnable);
	thread.start();
}

__CPAN_FILE__ src/lang.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang");
dojo.require("dojo.lang.common");

dojo.deprecated("dojo.lang", "replaced by dojo.lang.common", "0.5");

__CPAN_FILE__ src/bootstrap1.js
/**
* @file bootstrap1.js
*
* summary: First file that is loaded that 'bootstraps' the entire dojo library suite.
* note:  Must run before hostenv_*.js file.
*
* @author  Copyright 2004 Mark D. Anderson (mda@discerning.com)
* TODOC: should the copyright be changed to Dojo Foundation?
* @license Licensed under the Academic Free License 2.1 http://www.opensource.org/licenses/afl-2.1.php
*
* $Id: bootstrap1.js 6258 2006-10-20 03:12:36Z jburke $
*/

// TODOC: HOW TO DOC THE BELOW?
// @global: djConfig
// summary:  
//		Application code can set the global 'djConfig' prior to loading
//		the library to override certain global settings for how dojo works.  
// description:  The variables that can be set are as follows:
//			- isDebug: false
//			- allowQueryConfig: false
//			- baseScriptUri: ""
//			- baseRelativePath: ""
//			- libraryScriptUri: ""
//			- iePreventClobber: false
//			- ieClobberMinimal: true
//			- locale: undefined
//			- extraLocale: undefined
//			- preventBackButtonFix: true
//			- searchIds: []
//			- parseWidgets: true
// TODOC: HOW TO DOC THESE VARIABLES?
// TODOC: IS THIS A COMPLETE LIST?
// note:
//		'djConfig' does not exist under 'dojo.*' so that it can be set before the 
//		'dojo' variable exists.  
// note:
//		Setting any of these variables *after* the library has loaded does nothing at all. 
// TODOC: is this still true?  Release notes for 0.3 indicated they could be set after load.
//


//TODOC:  HOW TO DOC THIS?
// @global: dj_global
// summary: 
//		an alias for the top-level global object in the host environment
//		(e.g., the window object in a browser).
// description:  
//		Refer to 'dj_global' rather than referring to window to ensure your
//		code runs correctly in contexts other than web browsers (eg: Rhino on a server).
var dj_global = this;

//TODOC:  HOW TO DOC THIS?
// @global: dj_currentContext
// summary: 
//		Private global context object. Where 'dj_global' always refers to the boot-time
//    global context, 'dj_currentContext' can be modified for temporary context shifting.
//    dojo.global() returns dj_currentContext.
// description:  
//		Refer to dojo.global() rather than referring to dj_global to ensure your
//		code runs correctly in managed contexts.
var dj_currentContext = this;


// ****************************************************************
// global public utils
// TODOC: DO WE WANT TO NOTE THAT THESE ARE GLOBAL PUBLIC UTILS?
// ****************************************************************

function dj_undef(/*String*/ name, /*Object?*/ object){
	//summary: Returns true if 'name' is defined on 'object' (or globally if 'object' is null).
	//description: Note that 'defined' and 'exists' are not the same concept.
	return (typeof (object || dj_currentContext)[name] == "undefined");	// Boolean
}

// make sure djConfig is defined
if(dj_undef("djConfig", this)){ 
	var djConfig = {}; 
}

//TODOC:  HOW TO DOC THIS?
// dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
if(dj_undef("dojo", this)){ 
	var dojo = {}; 
}

dojo.global = function(){
	// summary:
	//		return the current global context object
	//		(e.g., the window object in a browser).
	// description: 
	//		Refer to 'dojo.global()' rather than referring to window to ensure your
	//		code runs correctly in contexts other than web browsers (eg: Rhino on a server).
	return dj_currentContext;
}

// Override locale setting, if specified
dojo.locale  = djConfig.locale;

//TODOC:  HOW TO DOC THIS?
dojo.version = {
	// summary: version number of this instance of dojo.
	major: 0, minor: 3, patch: 1, flag: "+",
	revision: Number("$Rev: 6258 $".match(/[0-9]+/)[0]),
	toString: function(){
		with(dojo.version){
			return major + "." + minor + "." + patch + flag + " (" + revision + ")";	// String
		}
	}
}

dojo.evalProp = function(/*String*/ name, /*Object*/ object, /*Boolean?*/ create){
	// summary: Returns 'object[name]'.  If not defined and 'create' is true, will return a new Object.
	// description: 
	//		Returns null if 'object[name]' is not defined and 'create' is not true.
	// 		Note: 'defined' and 'exists' are not the same concept.	
	if((!object)||(!name)) return undefined; // undefined
	if(!dj_undef(name, object)) return object[name]; // mixed
	return (create ? (object[name]={}) : undefined);	// mixed
}

dojo.parseObjPath = function(/*String*/ path, /*Object?*/ context, /*Boolean?*/ create){
	// summary: Parse string path to an object, and return corresponding object reference and property name.
	// description: 
	//		Returns an object with two properties, 'obj' and 'prop'.  
	//		'obj[prop]' is the reference indicated by 'path'.
	// path: Path to an object, in the form "A.B.C".
	// context: Object to use as root of path.  Defaults to 'dojo.global()'.
	// create: If true, Objects will be created at any point along the 'path' that is undefined.
	var object = (context || dojo.global());
	var names = path.split('.');
	var prop = names.pop();
	for (var i=0,l=names.length;i<l && object;i++){
		object = dojo.evalProp(names[i], object, create);
	}
	return {obj: object, prop: prop};	// Object: {obj: Object, prop: String}
}

dojo.evalObjPath = function(/*String*/ path, /*Boolean?*/ create){
	// summary: Return the value of object at 'path' in the global scope, without using 'eval()'.
	// path: Path to an object, in the form "A.B.C".
	// create: If true, Objects will be created at any point along the 'path' that is undefined.
	if(typeof path != "string"){ 
		return dojo.global(); 
	}
	// fast path for no periods
	if(path.indexOf('.') == -1){
		return dojo.evalProp(path, dojo.global(), create);		// mixed
	}

	//MOW: old 'with' syntax was confusing and would throw an error if parseObjPath returned null.
	var ref = dojo.parseObjPath(path, dojo.global(), create);
	if(ref){
		return dojo.evalProp(ref.prop, ref.obj, create);	// mixed
	}
	return null;
}

dojo.errorToString = function(/*Error*/ exception){
	// summary: Return an exception's 'message', 'description' or text.

	// TODO: overriding Error.prototype.toString won't accomplish this?
 	// 		... since natively generated Error objects do not always reflect such things?
	if(!dj_undef("message", exception)){
		return exception.message;		// String
	}else if(!dj_undef("description", exception)){
		return exception.description;	// String
	}else{
		return exception;				// Error
	}
}

dojo.raise = function(/*String*/ message, /*Error?*/ exception){
	// summary: Common point for raising exceptions in Dojo to enable logging.
	//	Throws an error message with text of 'exception' if provided, or
	//	rethrows exception object.

	if(exception){
		message = message + ": "+dojo.errorToString(exception);
	}

	// print the message to the user if hostenv.println is defined
	try { if(djConfig.isDebug){ dojo.hostenv.println("FATAL exception raised: "+message); } } catch (e) {}

	throw exception || Error(message);
}

//Stub functions so things don't break.
//TODOC:  HOW TO DOC THESE?
dojo.debug = function(){};
dojo.debugShallow = function(obj){};
dojo.profile = { start: function(){}, end: function(){}, stop: function(){}, dump: function(){} };

function dj_eval(/*String*/ scriptFragment){ 
	// summary: Perform an evaluation in the global scope.  Use this rather than calling 'eval()' directly.
	// description: Placed in a separate function to minimize size of trapped evaluation context.
	// note:
	//	 - JSC eval() takes an optional second argument which can be 'unsafe'.
	//	 - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
	//  	 scope object for new symbols.
	return dj_global.eval ? dj_global.eval(scriptFragment) : eval(scriptFragment); 	// mixed
}

dojo.unimplemented = function(/*String*/ funcname, /*String?*/ extra){
	// summary: Throw an exception because some function is not implemented.
	// extra: Text to append to the exception message.
	var message = "'" + funcname + "' not implemented";
	if (extra != null) { message += " " + extra; }
	dojo.raise(message);
}

dojo.deprecated = function(/*String*/ behaviour, /*String?*/ extra, /*String?*/ removal){
	// summary: Log a debug message to indicate that a behavior has been deprecated.
	// extra: Text to append to the message.
	// removal: Text to indicate when in the future the behavior will be removed.
	var message = "DEPRECATED: " + behaviour;
	if(extra){ message += " " + extra; }
	if(removal){ message += " -- will be removed in version: " + removal; }
	dojo.debug(message);
}

dojo.render = (function(){
	//TODOC: HOW TO DOC THIS?
	// summary: Details rendering support, OS and browser of the current environment.
	// TODOC: is this something many folks will interact with?  If so, we should doc the structure created...
	function vscaffold(prefs, names){
		var tmp = {
			capable: false,
			support: {
				builtin: false,
				plugin: false
			},
			prefixes: prefs
		};
		for(var i=0; i<names.length; i++){
			tmp[names[i]] = false;
		}
		return tmp;
	}

	return {
		name: "",
		ver: dojo.version,
		os: { win: false, linux: false, osx: false },
		html: vscaffold(["html"], ["ie", "opera", "khtml", "safari", "moz"]),
		svg: vscaffold(["svg"], ["corel", "adobe", "batik"]),
		vml: vscaffold(["vml"], ["ie"]),
		swf: vscaffold(["Swf", "Flash", "Mm"], ["mm"]),
		swt: vscaffold(["Swt"], ["ibm"])
	};
})();

// ****************************************************************
// dojo.hostenv methods that must be defined in hostenv_*.js
// ****************************************************************

/**
 * The interface definining the interaction with the EcmaScript host environment.
*/

/*
 * None of these methods should ever be called directly by library users.
 * Instead public methods such as loadModule should be called instead.
 */
dojo.hostenv = (function(){
	// TODOC:  HOW TO DOC THIS?
	// summary: Provides encapsulation of behavior that changes across different 'host environments' 
	//			(different browsers, server via Rhino, etc).
	// description: None of these methods should ever be called directly by library users.
	//				Use public methods such as 'loadModule' instead.
	
	// default configuration options
	var config = {
		isDebug: false,
		allowQueryConfig: false,
		baseScriptUri: "",
		baseRelativePath: "",
		libraryScriptUri: "",
		iePreventClobber: false,
		ieClobberMinimal: true,
		preventBackButtonFix: true,
		delayMozLoadingFix: false,
		searchIds: [],
		parseWidgets: true
	};

	if (typeof djConfig == "undefined") { djConfig = config; }
	else {
		for (var option in config) {
			if (typeof djConfig[option] == "undefined") {
				djConfig[option] = config[option];
			}
		}
	}

	return {
		name_: '(unset)',
		version_: '(unset)',


		getName: function(){ 
			// sumary: Return the name of the host environment.
			return this.name_; 	// String
		},


		getVersion: function(){ 
			// summary: Return the version of the hostenv.
			return this.version_; // String
		},

		getText: function(/*String*/ uri){
			// summary:	Read the plain/text contents at the specified 'uri'.
			// description: 
			//			If 'getText()' is not implemented, then it is necessary to override 
			//			'loadUri()' with an implementation that doesn't rely on it.

			dojo.unimplemented('getText', "uri=" + uri);
		}
	};
})();


dojo.hostenv.getBaseScriptUri = function(){
	// summary: Return the base script uri that other scripts are found relative to.
	// TODOC: HUH?  This comment means nothing to me.  What other scripts? Is this the path to other dojo libraries?
	//		MAYBE:  Return the base uri to scripts in the dojo library.	 ???
	// return: Empty string or a path ending in '/'.
	if(djConfig.baseScriptUri.length){ 
		return djConfig.baseScriptUri;
	}

	// MOW: Why not:
	//			uri = djConfig.libraryScriptUri || djConfig.baseRelativePath
	//		??? Why 'new String(...)'
	var uri = new String(djConfig.libraryScriptUri||djConfig.baseRelativePath);
	if (!uri) { dojo.raise("Nothing returned by getLibraryScriptUri(): " + uri); }

	// MOW: uri seems to not be actually used.  Seems to be hard-coding to djConfig.baseRelativePath... ???
	var lastslash = uri.lastIndexOf('/');		// MOW ???
	djConfig.baseScriptUri = djConfig.baseRelativePath;
	return djConfig.baseScriptUri;	// String
}

__CPAN_FILE__ src/html.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html");

dojo.require("dojo.html.*");
dojo.deprecated("dojo.html", "replaced by dojo.html.*", "0.5");

__CPAN_FILE__ src/hostenv_jsc.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
 * JScript .NET jsc
 *
 */

dojo.hostenv.name_ = 'jsc';

// Sanity check this is the right hostenv.
// See the Rotor source code jscript/engine/globalobject.cs for what globals
// are available.
if((typeof ScriptEngineMajorVersion != 'function')||(ScriptEngineMajorVersion() < 7)){
	dojo.raise("attempt to use JScript .NET host environment with inappropriate ScriptEngine"); 
}

// for more than you wanted to know about why this import is required even if
// we fully qualify all symbols, see
// http://groups.google.com/groups?th=f050c7aeefdcbde2&rnum=12
import System;

dojo.hostenv.getText = function(uri){
	if(!System.IO.File.Exists(uri)){
		// dojo.raise("No such file '" + uri + "'");
		return 0;
	}
	var reader = new System.IO.StreamReader(uri);
	var contents : String = reader.ReadToEnd();
	return contents;
}

dojo.hostenv.loadUri = function(uri){
	var contents = this.getText(uri);
	if(!contents){
		dojo.raise("got no back contents from uri '" + uri + "': " + contents);
	}
	// TODO: in JScript .NET, eval will not affect the symbol table of the current code?
	var value = dj_eval(contents);
	dojo.debug("jsc eval of contents returned: ", value);
	return 1;

	// for an example doing runtime code compilation, see:
	// http://groups.google.com/groups?selm=eQ1aeciCBHA.1644%40tkmsftngp05&rnum=6
	// Microsoft.JScript or System.CodeDom.Compiler ?
	// var engine = new Microsoft.JScript.Vsa.VsaEngine()
	// what about loading a js file vs. a dll?
	// GetObject("script:" . uri);
}

/* The System.Environment object is useful:
    print ("CommandLine='" + System.Environment.CommandLine + "' " +
	   "program name='" + System.Environment.GetCommandLineArgs()[0] + "' " +
	   "CurrentDirectory='" + System.Environment.CurrentDirectory + "' " +
	   "StackTrace='" + System.Environment.StackTrace + "'");
*/

// same as System.Console.WriteLine
// sigh; Rotor treats symbol "print" at parse time without actually putting it
// in the builtin symbol table.
// Note that the print symbol is not available if jsc is run with the "/print-"
// option.
dojo.hostenv.println = function(s){
	print(s); // = print
}

dojo.hostenv.getLibraryScriptUri = function(){
	return System.Environment.GetCommandLineArgs()[0];
}

__CPAN_FILE__ src/browser_debug.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.hostenv.loadedUris.push("../src/bootstrap1.js");
dojo.hostenv.loadedUris.push("../src/loader.js");
dojo.hostenv.loadedUris.push("../src/hostenv_browser.js");
dojo.hostenv.loadedUris.push("../src/bootstrap2.js");
dojo.hostenv._loadedUrisListStart = dojo.hostenv.loadedUris.length;

function removeComments(contents){
	contents = new String((!contents) ? "" : contents);
	// clobber all comments
	// FIXME broken if // or /* inside quotes or regexp
	contents = contents.replace( /^(.*?)\/\/(.*)$/mg , "$1");
	contents = contents.replace( /(\n)/mg , "__DOJONEWLINE");
	contents = contents.replace( /\/\*(.*?)\*\//g , "");
	return contents.replace( /__DOJONEWLINE/mg , "\n");
}

dojo.hostenv.getRequiresAndProvides = function(contents){
	// FIXME: should probably memoize this!
	if(!contents){ return []; }
	

	// check to see if we need to load anything else first. Ugg.
	var deps = [];
	var tmp;
	RegExp.lastIndex = 0;
	var testExp = /dojo.(hostenv.loadModule|hostenv.require|require|requireIf|kwCompoundRequire|hostenv.conditionalLoadModule|hostenv.startPackage|provide)\([\w\W]*?\)/mg;
	while((tmp = testExp.exec(contents)) != null){
		deps.push(tmp[0]);
	}
	return deps;
}

dojo.hostenv.getDelayRequiresAndProvides = function(contents){
	// FIXME: should probably memoize this!
	if(!contents){ return []; }

	// check to see if we need to load anything else first. Ugg.
	var deps = [];
	var tmp;
	RegExp.lastIndex = 0;
	var testExp = /dojo.(requireAfterIf)\([\w\W]*?\)/mg;
	while((tmp = testExp.exec(contents)) != null){
		deps.push(tmp[0]);
	}
	return deps;
}

/*
dojo.getNonExistantDescendants = function(objpath){
	var ret = [];
	// fast path for no periods
	if(typeof objpath != "string"){ return dj_global; }
	if(objpath.indexOf('.') == -1){
		if(dj_undef(objpath, dj_global)){
			ret.push[objpath];
		}
		return ret;
	}

	var syms = objpath.split(/\./);
	var obj = dj_global;
	for(var i=0;i<syms.length;++i){
		if(dj_undef(syms[i], obj)){
			for(var j=i; j<syms.length; j++){
				ret.push(syms.slice(0, j+1).join("."));
			}
			break;
		}
	}
	return ret;
}
*/

dojo.clobberLastObject = function(objpath){
	if(objpath.indexOf('.') == -1){
		if(!dj_undef(objpath, dj_global)){
			delete dj_global[objpath];
		}
		return true;
	}

	var syms = objpath.split(/\./);
	var base = dojo.evalObjPath(syms.slice(0, -1).join("."), false);
	var child = syms[syms.length-1];
	if(!dj_undef(child, base)){
		// alert(objpath);
		delete base[child];
		return true;
	}
	return false;
}

var removals = [];

function zip(arr){
	var ret = [];
	var seen = {};
	for(var x=0; x<arr.length; x++){
		if(!seen[arr[x]]){
			ret.push(arr[x]);
			seen[arr[x]] = true;
		}
	}
	return ret;
}

// over-write dj_eval to prevent actual loading of subsequent files
var old_dj_eval = dj_eval;
dj_eval = function(){ return true; }
dojo.hostenv.oldLoadUri = dojo.hostenv.loadUri;
dojo.hostenv.loadUri = function(uri, cb /*optional*/){
	if(dojo.hostenv.loadedUris[uri]){
		return true; // fixes endless recursion opera trac 471
	}
	try{
		var text = this.getText(uri, null, true);
		if(!text) { return false; }
		if(cb){
			// No way to load i18n bundles but to eval them, and they usually
			// don't have script needing to be debugged anyway
			var expr = old_dj_eval('('+text+')');
			cb(expr);
		}else {
			var requires = dojo.hostenv.getRequiresAndProvides(text);
			eval(requires.join(";"));
			dojo.hostenv.loadedUris.push(uri);
			dojo.hostenv.loadedUris[uri] = true;
			var delayRequires = dojo.hostenv.getDelayRequiresAndProvides(text);
			eval(delayRequires.join(";"));
		}
	}catch(e){ 
		alert(e);
	}
	return true;
}

dojo.hostenv._writtenIncludes = {};
dojo.hostenv.writeIncludes = function(willCallAgain){
	for(var x=removals.length-1; x>=0; x--){
		dojo.clobberLastObject(removals[x]);
	}
	var depList = [];
	var seen = dojo.hostenv._writtenIncludes;
	for(var x=0; x<dojo.hostenv.loadedUris.length; x++){
		var curi = dojo.hostenv.loadedUris[x];
		// dojo.debug(curi);
		if(!seen[curi]){
			seen[curi] = true;
			depList.push(curi);
		}
	}

	dojo.hostenv._global_omit_module_check = true;
	
	for(var x= dojo.hostenv._loadedUrisListStart; x<depList.length; x++){
		document.write("<script type='text/javascript' src='"+depList[x]+"'></script>");
	}
	document.write("<script type='text/javascript'>dojo.hostenv._global_omit_module_check = false;</script>");
	dojo.hostenv._loadedUrisListStart = 0;
	if (!willCallAgain) {
		// turn off debugAtAllCosts, so that dojo.require() calls inside of ContentPane hrefs
		// work correctly
		dj_eval = old_dj_eval;
		dojo.hostenv.loadUri = dojo.hostenv.oldLoadUri;
	}
}

__CPAN_FILE__ src/json.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.json");
dojo.require("dojo.lang.func");
dojo.require("dojo.string.extras");
dojo.require("dojo.AdapterRegistry");

dojo.json = {
	// jsonRegistry: AdapterRegistry a registry of type-based serializers
	jsonRegistry: new dojo.AdapterRegistry(),

	register: function(	/*String*/		name, 
						/*function*/	check, 
						/*function*/	wrap, 
						/*optional, boolean*/ override){
		// summary:
		//		Register a JSON serialization function. JSON serialization
		//		functions should take one argument and return an object
		//		suitable for JSON serialization:
		//			- string
		//			- number
		//			- boolean
		//			- undefined
		//			- object
		//				- null
		//				- Array-like (length property that is a number)
		//				- Objects with a "json" method will have this method called
		//				- Any other object will be used as {key:value, ...} pairs
		//			
		//		If override is given, it is used as the highest priority JSON
		//		serialization, otherwise it will be used as the lowest.
		// name:
		//		a descriptive type for this serializer
		// check:
		//		a unary function that will be passed an object to determine
		//		whether or not wrap will be used to serialize the object
		// wrap:
		//		the serialization function
		// override:
		//		optional, determines if the this serialization function will be
		//		given priority in the test order

		dojo.json.jsonRegistry.register(name, check, wrap, override);
	},

	evalJson: function(/*String*/ json){
		// summary:
		// 		evaluates the passed string-form of a JSON object
		// json: 
		//		a string literal of a JSON item, for instance:
		//			'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'
		// return:
		//		the result of the evaluation

		// FIXME: should this accept mozilla's optional second arg?
		try {
			return eval("(" + json + ")");
		}catch(e){
			dojo.debug(e);
			return json;
		}
	},

	serialize: function(/*Object*/ o){
		// summary:
		//		Create a JSON serialization of an object, note that this
		//		doesn't check for infinite recursion, so don't do that!
		// o:
		//		an object to be serialized. Objects may define their own
		//		serialization via a special "__json__" or "json" function
		//		property. If a specialized serializer has been defined, it will
		//		be used as a fallback.
		// return:
		//		a String representing the serialized version of the passed
		//		object

		var objtype = typeof(o);
		if(objtype == "undefined"){
			return "undefined";
		}else if((objtype == "number")||(objtype == "boolean")){
			return o + "";
		}else if(o === null){
			return "null";
		}
		if (objtype == "string") { return dojo.string.escapeString(o); }
		// recurse
		var me = arguments.callee;
		// short-circuit for objects that support "json" serialization
		// if they return "self" then just pass-through...
		var newObj;
		if(typeof(o.__json__) == "function"){
			newObj = o.__json__();
			if(o !== newObj){
				return me(newObj);
			}
		}
		if(typeof(o.json) == "function"){
			newObj = o.json();
			if (o !== newObj) {
				return me(newObj);
			}
		}
		// array
		if(objtype != "function" && typeof(o.length) == "number"){
			var res = [];
			for(var i = 0; i < o.length; i++){
				var val = me(o[i]);
				if(typeof(val) != "string"){
					val = "undefined";
				}
				res.push(val);
			}
			return "[" + res.join(",") + "]";
		}
		// look in the registry
		try {
			window.o = o;
			newObj = dojo.json.jsonRegistry.match(o);
			return me(newObj);
		}catch(e){
			// dojo.debug(e);
		}
		// it's a function with no adapter, bad
		if(objtype == "function"){
			return null;
		}
		// generic object code path
		res = [];
		for (var k in o){
			var useKey;
			if (typeof(k) == "number"){
				useKey = '"' + k + '"';
			}else if (typeof(k) == "string"){
				useKey = dojo.string.escapeString(k);
			}else{
				// skip non-string or number keys
				continue;
			}
			val = me(o[k]);
			if(typeof(val) != "string"){
				// skip non-serializable values
				continue;
			}
			res.push(useKey + ":" + val);
		}
		return "{" + res.join(",") + "}";
	}
};

__CPAN_FILE__ src/string.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.string");
dojo.require("dojo.string.common");

__CPAN_FILE__ src/io.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io");

dojo.require("dojo.io.*");
dojo.deprecated("dojo.io", "replaced by dojo.io.*", "0.5");

__CPAN_FILE__ src/experimental.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.experimental");

dojo.experimental = function(/* String */ moduleName, /* String? */ extra){
	// summary: Marks code as experimental.
	// description: 
	//    This can be used to mark a function, file, or module as experimental.
	//    Experimental code is not ready to be used, and the APIs are subject
	//    to change without notice.  Experimental code may be completed deleted
	//    without going through the normal deprecation process.
	// moduleName: The name of a module, or the name of a module file or a specific function
	// extra: some additional message for the user
	
	// examples:
	//    dojo.experimental("dojo.data.Result");
	//    dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
	var message = "EXPERIMENTAL: " + moduleName;
	message += " -- Not yet ready for use.  APIs subject to change without notice.";
	if(extra){ message += " " + extra; }
	dojo.debug(message);
}

__CPAN_FILE__ src/hostenv_dashboard.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.render.name = dojo.hostenv.name_ = "dashboard";

dojo.hostenv.println = function(/*String*/ message){
	// summary: Prints a message to the OS X console
	return alert(message); // null
}

dojo.hostenv.getXmlhttpObject = function(/*Object*/ kwArgs){
	// summary: Returns the appropriate transfer object for the call type
	if(widget.system && kwArgs){
		if((kwArgs.contentType && kwArgs.contentType.indexOf("text/") != 0) || (kwArgs.headers && kwArgs.headers["content-type"] && kwArgs.headers["content-type"].indexOf("text/") != 0)){
			var curl = new dojo.hostenv.CurlRequest;
			curl._save = true;
			return curl;
		}else if(kwArgs.method && kwArgs.method.toUpperCase() == "HEAD"){
			return new dojo.hostenv.CurlRequest;
		}else if(kwArgs.headers && kwArgs.header.referer){
			return new dojo.hostenv.CurlRequest; 
		}
	}
	return new XMLHttpRequest; // XMLHttpRequest
}

dojo.hostenv.CurlRequest = function(){
	// summary: Emulates the XMLHttpRequest Object
	this.onreadystatechange = null;
	this.readyState = 0;
	this.responseText = "";
	this.responseXML = null;
	this.status = 0;
	this.statusText = "";
	this._method = "";
	this._url = "";
	this._async = true;
	this._referrer = "";
	this._headers = [];
	this._save = false;
	this._responseHeader = "";
	this._responseHeaders = {};
	this._fileName = "";
	this._username = "";
	this._password = "";
}

dojo.hostenv.CurlRequest.prototype.open = function(/*String*/ method, /*URL*/ url, /*Boolean?*/ async, /*String?*/ username, /*String?*/ password){
	this._method = method;
	this._url = url;
	if(async){
		this._async = async;
	}
	if(username){
		this._username = username;
	}
	if(password){
		this._password = password;
	}
}

dojo.hostenv.CurlRequest.prototype.setRequestHeader = function(/*String*/ label, /*String*/ value){
	switch(label){
		case "Referer":
			this._referrer = value;
			break;
		case "content-type":
			break;
		default:
			this._headers.push(label + "=" + value);
			break;
	}
}

dojo.hostenv.CurlRequest.prototype.getAllResponseHeaders = function(){
	return this._responseHeader; // String
}

dojo.hostenv.CurlRequest.prototype.getResponseHeader = function(/*String*/ headerLabel){
	return this._responseHeaders[headerLabel]; // String
}

// -sS = Show only errors in errorString
// -i = Display headers with return
// -e = Referrer URI
// -H = Headers
// -d = data to be sent (forces POST)
// -G = forces GET
// -o = Writes to file (in the cache directory)
// -I = Only load headers
// -u = user:password
dojo.hostenv.CurlRequest.prototype.send = function(/*String*/ content){
	this.readyState = 1;
	if(this.onreadystatechange){
		this.onreadystatechange.call(this);
	}
	var query = {sS: ""};
	if(this._referrer){
		query.e = this._referrer;
	}
	if(this._headers.length){
		query.H = this._headers.join("&");
	}
	if(this._username){
		if(this._password){
			query.u = this._username + ":" + this._password;
		}else{
			query.u = this._username;
		}
	}
	if(content){
		query.d = this.content;
		if(this._method != "POST"){
			query.G = "";
		}
	}
	if(this._method == "HEAD"){
		query.I = "";
	}else{
		if(this._save){
			query.I = ""; // Get the headers in the initial query
		}else{
			query.i = "";
		}
	}

	var system = widget.system(dojo.hostenv.CurlRequest._formatCall(query, this._url), null);
	this.readyState = 2;
	if(this.onreadystatechange){
		this.onreadystatechange.call(this);
	}
	if(system.errorString){
		this.responseText = system.errorString;
		this.status = 0;
	}else{
		if(this._save){
			this._responseHeader = system.outputString;
		}else{
			var split = system.outputString.replace(/\r/g, "").split("\n\n", 2);
			this._responseHeader = split[0];
			this.responseText = split[1];
		}
		split = this._responseHeader.split("\n");
		this.statusText = split.shift();
		this.status = this.statusText.split(" ")[1];
		for(var i = 0, header; header = split[i]; i++){
			var header_split = header.split(": ", 2);
			this._responseHeaders[header_split[0]] = header_split[1];
		}
		if(this._save){
			widget.system("/bin/mkdir cache", null);
			// First, make a file name
			this._fileName = this._url.split("/").pop().replace(/\W/g, "");
			// Then, get its extension
			this._fileName += "." + this._responseHeaders["Content-Type"].replace(/[\r\n]/g, "").split("/").pop()
			delete query.I;
			query.o = "cache/" + this._fileName; // Tell it where to be saved.
			system = widget.system(dojo.hostenv.CurlRequest._formatCall(query, this._url), null);
			if(!system.errorString){
				this.responseText = "cache/" + this._fileName;
			}
		}else if(this._method == "HEAD"){
			this.responseText = this._responseHeader;
		}
	}

	this.readyState = 4;
	if(this.onreadystatechange){
		this.onreadystatechange.call(this);
	}
}

dojo.hostenv.CurlRequest._formatCall = function(query, url){
	var call = ["/usr/bin/curl"];
	for(var key in query){
		if(query[key] != ""){
			call.push("-" + key + " '" + query[key].replace(/'/g, "\'") + "'");
		}else{
			call.push("-" + key);
		}
	}
	call.push("'" + url.replace(/'/g, "\'") + "'");
	return call.join(" ");
}

dojo.hostenv.exit = function(){
	if(widget.system){
		widget.system("/bin/rm -rf cache/*", null);
	}
}

__CPAN_FILE__ src/loader_xd.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

//Cross-domain package loader.

//FIXME: How will xd loading work with debugAtAllCosts? Any bad interactions?
//FIXME: widgets won't work fully (HTML/CSS) and also because of the requireIf() thing.

dojo.hostenv.resetXd = function(){
	//This flag indicates where or not we have crossed into xdomain territory. Once any package says
	//it is cross domain, then the rest of the packages have to be treated as xdomain because we need
	//to evaluate packages in order. If there is a xdomain package followed by a xhr package, we can't load
	//the xhr package until the one before it finishes loading. The text of the xhr package will be converted
	//to match the format for a xd package and put in the xd load queue.
	//You can force all packages to be treated as xd by setting the djConfig.forceXDomain.
	this.isXDomain = djConfig.forceXDomain || false;

	this.xdTimer = 0;
	this.xdInFlight = {};
	this.xdOrderedReqs = [];
	this.xdDepMap = {};
	this.xdContents = [];
}

//Call reset immediately to set the state.
dojo.hostenv.resetXd();

dojo.hostenv.createXdPackage = function(contents){
	//Find dependencies.
	var deps = [];
    var depRegExp = /dojo.(require|requireIf|requireAll|provide|requireAfterIf|requireAfter|kwCompoundRequire|conditionalRequire|hostenv\.conditionalLoadModule|.hostenv\.loadModule|hostenv\.moduleLoaded)\(([\w\W]*?)\)/mg;
    var match;
	while((match = depRegExp.exec(contents)) != null){
		deps.push("\"" + match[1] + "\", " + match[2]);
	}

	//Create package object and the call to packageLoaded.
	var output = [];
	output.push("dojo.hostenv.packageLoaded({\n");

	//Add dependencies
	if(deps.length > 0){
		output.push("depends: [");
		for(var i = 0; i < deps.length; i++){
			if(i > 0){
				output.push(",\n");
			}
			output.push("[" + deps[i] + "]");
		}
		output.push("],");
	}

	//Add the contents of the file inside a function.
	//Pass in dojo as an argument to the function to help with
	//allowing multiple versions of dojo in a page.
	output.push("\ndefinePackage: function(dojo){");
	output.push(contents);
	output.push("\n}});");
	
	return output.join("");
}

dojo.hostenv.loadPath = function(relpath, module /*optional*/, cb /*optional*/){
	//Only do getBaseScriptUri if path does not start with a URL with a protocol.
	//If there is a colon before the first / then, we have a URL with a protocol.
	var colonIndex = relpath.indexOf(":");
	var slashIndex = relpath.indexOf("/");
	var uri;
	var currentIsXDomain = false;
	if(colonIndex > 0 && colonIndex < slashIndex){
		uri = relpath;
		this.isXDomain = currentIsXDomain = true;
	}else{
		uri = this.getBaseScriptUri() + relpath;

		//Is ithe base script URI-based URL a cross domain URL?
		colonIndex = uri.indexOf(":");
		slashIndex = uri.indexOf("/");
		if(colonIndex > 0 && colonIndex < slashIndex && (!location.host || uri.indexOf("http://" + location.host) != 0)){
			this.isXDomain = currentIsXDomain = true;
		}
	}

	if(djConfig.cacheBust && dojo.render.html.capable) { uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,""); }
	try{
		return ((!module || this.isXDomain) ? this.loadUri(uri, cb, currentIsXDomain, module) : this.loadUriAndCheck(uri, module, cb));
	}catch(e){
		dojo.debug(e);
		return false;
	}
}

//Overriding loadUri for now. Wanted to override getText(), but it is used by
//the widget code in too many, synchronous ways right now. This means the xd stuff
//is not suitable for widgets yet.
dojo.hostenv.loadUri = function(uri, cb, currentIsXDomain, module){
	if(this.loadedUris[uri]){
		return 1;
	}

	//Add the module (package) to the list of modules.
	if(this.isXDomain){
		//Curious: is this array going to get whacked with multiple access since scripts
		//load asynchronously and may be accessing the array at the same time?
		//JS is single-threaded supposedly, so it should be ok. And we don't need
		//a precise ordering.
		this.xdOrderedReqs.push(module);

		//Add to waiting packages.
		//If this is a __package__.js file, then this must be
		//a package.* request (since xdomain can only work with the first
		//path in a package search list. However, .* module names are not
		//passed to this function, so do an adjustment here.
		if(uri.indexOf("__package__") != -1){
			module += ".*";
		}

		this.xdInFlight[module] = true;

		//Increment inFlightCount
		//This will stop the modulesLoaded from firing all the way.
		this.inFlightCount++;
				
		//Start timer
		if(!this.xdTimer){
			this.xdTimer = setInterval("dojo.hostenv.watchInFlightXDomain();", 100);
		}
		this.xdStartTime = (new Date()).getTime();
	}

	if (currentIsXDomain){
		//Fix name to be a .xd.fileextension name.
		var lastIndex = uri.lastIndexOf('.');
		if(lastIndex <= 0){
			lastIndex = uri.length - 1;
		}

		var xdUri = uri.substring(0, lastIndex) + ".xd";
		if(lastIndex != uri.length - 1){
			xdUri += uri.substring(lastIndex, uri.length);
		}

		//Add to script src
		var element = document.createElement("script");
		element.type = "text/javascript";
		element.src = xdUri;
		if(!this.headElement){
			this.headElement = document.getElementsByTagName("head")[0];
		}
		this.headElement.appendChild(element);
	}else{
		var contents = this.getText(uri, null, true);
		if(contents == null){ return 0; }
		
		if(this.isXDomain){
			var pkg = this.createXdPackage(contents);
			dj_eval(pkg);
		}else{
			if(cb){ contents = '('+contents+')'; }
			var value = dj_eval(contents);
			if(cb){
				cb(value);
			}
		}
	}

	//These steps are done in the non-xd loader version of this function.
	//Maintain these steps to fit in with the existing system.
	this.loadedUris[uri] = true;
	return 1;
}

dojo.hostenv.packageLoaded = function(pkg){
	var deps = pkg.depends;
	var requireList = null;
	var requireAfterList = null;
	var provideList = [];
	if(deps && deps.length > 0){
		var dep = null;
		var insertHint = 0;
		var attachedPackage = false;
		for(var i = 0; i < deps.length; i++){
			dep = deps[i];

			//Look for specific dependency indicators.
			if (dep[0] == "provide" || dep[0] == "hostenv.moduleLoaded"){
				provideList.push(dep[1]);
			}else{
				if(!requireList){
					requireList = [];
				}
				if(!requireAfterList){
					requireAfterList = [];
				}

				var unpackedDeps = this.unpackXdDependency(dep);
				if(unpackedDeps.requires){
					requireList = requireList.concat(unpackedDeps.requires);
				}
				if(unpackedDeps.requiresAfter){
					requireAfterList = requireAfterList.concat(unpackedDeps.requiresAfter);
				}
			}

			//Call the dependency indicator to allow for the normal dojo setup.
			//Only allow for one dot reference, for the hostenv.* type calls.
			var depType = dep[0];
			var objPath = depType.split(".");
			if(objPath.length == 2){
				dojo[objPath[0]][objPath[1]].apply(dojo[objPath[0]], dep.slice(1));
			}else{
				dojo[depType].apply(dojo, dep.slice(1));
			}
		}

		//Save off the package contents for definition later.
		var contentIndex = this.xdContents.push({content: pkg.definePackage, isDefined: false}) - 1;

		//Add provide/requires to dependency map.
		for(var i = 0; i < provideList.length; i++){
			this.xdDepMap[provideList[i]] = { requires: requireList, requiresAfter: requireAfterList, contentIndex: contentIndex };
		}

		//Now update the inflight status for any provided packages in this loaded package.
		//Do this at the very end (in a *separate* for loop) to avoid shutting down the 
		//inflight timer check too soon.
		for(var i = 0; i < provideList.length; i++){
			this.xdInFlight[provideList[i]] = false;
		}
	}
}

//This is a bit brittle: it has to know about the dojo methods that deal with dependencies
//It would be ideal to intercept the actual methods and do something fancy at that point,
//but I have concern about knowing which provide to match to the dependency in that case,
//since scripts can load whenever they want, and trigger new calls to dojo.hostenv.packageLoaded().
dojo.hostenv.unpackXdDependency = function(dep){
	//Extract the dependency(ies).
	var newDeps = null;
	var newAfterDeps = null;
	switch(dep[0]){
		case "requireIf":
		case "requireAfterIf":
		case "conditionalRequire":
			//First arg (dep[1]) is the test. Depedency is dep[2].
			if((dep[1] === true)||(dep[1]=="common")||(dep[1] && dojo.render[dep[1]].capable)){
				newDeps = [{name: dep[2], content: null}];
			}
			break;
		case "requireAll":
			//the arguments are an array, each element a call to require.
			//Get rid of first item, which is "requireAll".
			dep.shift();
			newDeps = dep;
			dojo.hostenv.flattenRequireArray(newDeps);
			break;
		case "kwCompoundRequire":
		case "hostenv.conditionalLoadModule":
			var modMap = dep[1];
			var common = modMap["common"]||[];
			var newDeps = (modMap[dojo.hostenv.name_]) ? common.concat(modMap[dojo.hostenv.name_]||[]) : common.concat(modMap["default"]||[]);	
			dojo.hostenv.flattenRequireArray(newDeps);
			break;
		case "require":
		case "requireAfter":
		case "hostenv.loadModule":
			//Just worry about dep[1]
			newDeps = [{name: dep[1], content: null}];
			break;
	}

	//The requireAfterIf or requireAfter needs to be evaluated after the current package is evaluated.
	if(dep[0] == "requireAfterIf"){
		newAfterDeps = newDeps;
		newDeps = null;
	}
	return {requires: newDeps, requiresAfter: newAfterDeps};
}

//Walks the requires and evaluates package contents in
//the right order.
dojo.hostenv.xdWalkReqs = function(){
	var reqChain = null;
	var req;
	for(var i = 0; i < this.xdOrderedReqs.length; i++){
		req = this.xdOrderedReqs[i];
		if(this.xdDepMap[req]){
			reqChain = [req];
			reqChain[req] = true; //Allow for fast lookup of the req in the array
			this.xdEvalReqs(reqChain);
		}
	}
}

//Trace down any requires.
dojo.hostenv.xdTraceReqs = function(reqs, reqChain){
	if(reqs && reqs.length > 0){
		var nextReq;
		for(var i = 0; i < reqs.length; i++){
			nextReq = reqs[i].name;
			if(nextReq && !reqChain[nextReq]){
				//New req depedency. Follow it down.
				reqChain.push(nextReq);
				reqChain[nextReq] = true;
				this.xdEvalReqs(reqChain);
			}
		}
	}
}

//Do a depth first, breadth second search and eval or reqs.
dojo.hostenv.xdEvalReqs = function(reqChain){
	if(reqChain.length > 0){
		var req = reqChain[reqChain.length - 1];
		var pkg = this.xdDepMap[req];
		if(pkg){
			//Trace down any requires for this package.
			this.xdTraceReqs(pkg.requires, reqChain);

			//Evaluate the package.
			var contents = this.xdContents[pkg.contentIndex];
			if(!contents.isDefined){
				//Evaluate the package to bring it into being.
				//Pass dojo in so that later, to support multiple versions of dojo
				//in a page, we can pass which version of dojo to use.
				contents.content(dojo);
				contents.isDefined = true;
			}
			this.xdDepMap[req] = null;

			//Trace down any requireAfters for this package..
			this.xdTraceReqs(pkg.requiresAfter, reqChain);
		}

		//Done with that require. Remove it and go to the next one.
		reqChain.pop();
		this.xdEvalReqs(reqChain);
	}
}

dojo.hostenv.clearXdInterval = function(){
	clearInterval(this.xdTimer);
	this.xdTimer = 0;
}

dojo.hostenv.watchInFlightXDomain = function(){
	//Make sure we haven't waited timed out.
	var waitInterval = (djConfig.xdWaitSeconds || 30) * 1000;

	if(this.xdStartTime + waitInterval < (new Date()).getTime()){
		this.clearXdInterval();
		var noLoads = "";
		for(var param in this.xdInFlight){
			if(this.xdInFlight[param]){
				noLoads += param + " ";
			}
		}
		dojo.raise("Could not load cross-domain packages: " + noLoads);
	}

	//If any are true, then still waiting.
	//Come back later.	
	for(var param in this.xdInFlight){
		if(this.xdInFlight[param]){
			return;
		}
	}

	//All done loading. Clean up and notify that we are loaded.
	this.clearXdInterval();

	this.xdWalkReqs();

	//Evaluate any packages that were not evaled before.
	//This normally shouldn't happen with proper dojo.provide and dojo.require
	//usage, but providing it just in case. Note that these may not be executed
	//in the original order that the developer intended.
	//Pass dojo in so that later, to support multiple versions of dojo
	//in a page, we can pass which version of dojo to use.
	for(var i = 0; i < this.xdContents.length; i++){
		var current = this.xdContents[i];
		if(current.content && !current.isDefined){
			current.content(dojo);
		}
	}

	//Clean up for the next round of xd loading.
	this.resetXd();

	//Clear inflight count so we will finally do finish work.
	this.inFlightCount = 0; 
	this.callLoaded();
}

dojo.hostenv.flattenRequireArray = function(target){
	//Each result could be an array of 3 elements  (the 3 arguments to dojo.require).
	//We only need the first one.
	if(target){
		for(var i = 0; i < target.length; i++){
			if(target[i] instanceof Array){
				target[i] = {name: target[i][0], content: null};
			}else{
				target[i] = {name: target[i], content: null};
			}
		}
	}
}

//Need to preload any flattened i18n bundles before we start
//executing code, since we cannot do it synchronously, as the
//i18n code normally expects.
dojo.hostenv.xdHasCalledPreload = false;
dojo.hostenv.xdRealCallLoaded = dojo.hostenv.callLoaded;
dojo.hostenv.callLoaded = function(){
	//If getModulePrefix for dojo returns anything other than "src", that means
	//there is a path registered for dojo, with implies that dojo was xdomain loaded.
	if(this.xdHasCalledPreload || dojo.hostenv.getModulePrefix("dojo") == "src"){
		this.xdRealCallLoaded();
		this.xdHasCalledPreload = true;
	}else{
		if(this.localesGenerated){
			this.registerNlsPrefix = function(){
				//Need to set the nls prefix to be the xd location.
				dojo.registerModulePath("nls", dojo.hostenv.getModulePrefix("dojo") + "/../nls");	
			};
			this.preloadLocalizations();
		}
		this.xdHasCalledPreload = true;
	}
}

__CPAN_FILE__ src/dom.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.dom");

dojo.dom.ELEMENT_NODE                  = 1;
dojo.dom.ATTRIBUTE_NODE                = 2;
dojo.dom.TEXT_NODE                     = 3;
dojo.dom.CDATA_SECTION_NODE            = 4;
dojo.dom.ENTITY_REFERENCE_NODE         = 5;
dojo.dom.ENTITY_NODE                   = 6;
dojo.dom.PROCESSING_INSTRUCTION_NODE   = 7;
dojo.dom.COMMENT_NODE                  = 8;
dojo.dom.DOCUMENT_NODE                 = 9;
dojo.dom.DOCUMENT_TYPE_NODE            = 10;
dojo.dom.DOCUMENT_FRAGMENT_NODE        = 11;
dojo.dom.NOTATION_NODE                 = 12;
	
dojo.dom.dojoml = "http://www.dojotoolkit.org/2004/dojoml";

/**
 *	comprehensive list of XML namespaces
**/
dojo.dom.xmlns = {
	//	summary
	//	aliases for various common XML namespaces
	svg : "http://www.w3.org/2000/svg",
	smil : "http://www.w3.org/2001/SMIL20/",
	mml : "http://www.w3.org/1998/Math/MathML",
	cml : "http://www.xml-cml.org",
	xlink : "http://www.w3.org/1999/xlink",
	xhtml : "http://www.w3.org/1999/xhtml",
	xul : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
	xbl : "http://www.mozilla.org/xbl",
	fo : "http://www.w3.org/1999/XSL/Format",
	xsl : "http://www.w3.org/1999/XSL/Transform",
	xslt : "http://www.w3.org/1999/XSL/Transform",
	xi : "http://www.w3.org/2001/XInclude",
	xforms : "http://www.w3.org/2002/01/xforms",
	saxon : "http://icl.com/saxon",
	xalan : "http://xml.apache.org/xslt",
	xsd : "http://www.w3.org/2001/XMLSchema",
	dt: "http://www.w3.org/2001/XMLSchema-datatypes",
	xsi : "http://www.w3.org/2001/XMLSchema-instance",
	rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
	rdfs : "http://www.w3.org/2000/01/rdf-schema#",
	dc : "http://purl.org/dc/elements/1.1/",
	dcq: "http://purl.org/dc/qualifiers/1.0",
	"soap-env" : "http://schemas.xmlsoap.org/soap/envelope/",
	wsdl : "http://schemas.xmlsoap.org/wsdl/",
	AdobeExtensions : "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
};

dojo.dom.isNode = function(/* object */wh){
	//	summary
	//	checks to see if wh is actually a node.
	if(typeof Element == "function") {
		try {
			return wh instanceof Element;	//	boolean
		} catch(E) {}
	} else {
		// best-guess
		return wh && !isNaN(wh.nodeType);	//	boolean
	}
}

dojo.dom.getUniqueId = function(){
	//	summary
	//	returns a unique string for use with any DOM element
	var _document = dojo.doc();
	do {
		var id = "dj_unique_" + (++arguments.callee._idIncrement);
	}while(_document.getElementById(id));
	return id;	//	string
}
dojo.dom.getUniqueId._idIncrement = 0;

dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(/* Element */parentNode, /* string? */tagName){
	//	summary
	//	returns the first child element matching tagName
	var node = parentNode.firstChild;
	while(node && node.nodeType != dojo.dom.ELEMENT_NODE){
		node = node.nextSibling;
	}
	if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
		node = dojo.dom.nextElement(node, tagName);
	}
	return node;	//	Element
}

dojo.dom.lastElement = dojo.dom.getLastChildElement = function(/* Element */parentNode, /* string? */tagName){
	//	summary
	//	returns the last child element matching tagName
	var node = parentNode.lastChild;
	while(node && node.nodeType != dojo.dom.ELEMENT_NODE) {
		node = node.previousSibling;
	}
	if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
		node = dojo.dom.prevElement(node, tagName);
	}
	return node;	//	Element
}

dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(/* Node */node, /* string? */tagName){
	//	summary
	//	returns the next sibling element matching tagName
	if(!node) { return null; }
	do {
		node = node.nextSibling;
	} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);

	if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
		return dojo.dom.nextElement(node, tagName);
	}
	return node;	//	Element
}

dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(/* Node */node, /* string? */tagName){
	//	summary
	//	returns the previous sibling element matching tagName
	if(!node) { return null; }
	if(tagName) { tagName = tagName.toLowerCase(); }
	do {
		node = node.previousSibling;
	} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);

	if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
		return dojo.dom.prevElement(node, tagName);
	}
	return node;	//	Element
}

// TODO: hmph
/*this.forEachChildTag = function(node, unaryFunc) {
	var child = this.getFirstChildTag(node);
	while(child) {
		if(unaryFunc(child) == "break") { break; }
		child = this.getNextSiblingTag(child);
	}
}*/

dojo.dom.moveChildren = function(/* Element */srcNode, /* Element */destNode, /* boolean? */trim){
	//	summary
	//	Moves children from srcNode to destNode and returns the count of children moved; 
	//		will trim off text nodes if trim == true
	var count = 0;
	if(trim) {
		while(srcNode.hasChildNodes() &&
			srcNode.firstChild.nodeType == dojo.dom.TEXT_NODE) {
			srcNode.removeChild(srcNode.firstChild);
		}
		while(srcNode.hasChildNodes() &&
			srcNode.lastChild.nodeType == dojo.dom.TEXT_NODE) {
			srcNode.removeChild(srcNode.lastChild);
		}
	}
	while(srcNode.hasChildNodes()){
		destNode.appendChild(srcNode.firstChild);
		count++;
	}
	return count;	//	number
}

dojo.dom.copyChildren = function(/* Element */srcNode, /* Element */destNode, /* boolean? */trim){
	//	summary
	//	Copies children from srcNde to destNode and returns the count of children copied;
	//		will trim off text nodes if trim == true
	var clonedNode = srcNode.cloneNode(true);
	return this.moveChildren(clonedNode, destNode, trim);	//	number
}

dojo.dom.removeChildren = function(/* Element */node){
	//	summary
	//	removes all children from node and returns the count of children removed.
	var count = node.childNodes.length;
	while(node.hasChildNodes()){ node.removeChild(node.firstChild); }
	return count;	//	number
}

dojo.dom.replaceChildren = function(/* Element */node, /* Node */newChild){
	//	summary
	//	Removes all children of node and appends newChild
	// FIXME: what if newChild is an array-like object?
	dojo.dom.removeChildren(node);
	node.appendChild(newChild);
}

dojo.dom.removeNode = function(/* Node */node){
	//	summary
	//	if node has a parent, removes node from parent and returns a reference to the removed child.
	if(node && node.parentNode){
		// return a ref to the removed child
		return node.parentNode.removeChild(node);	//	Node
	}
}

dojo.dom.getAncestors = function(/* Node */node, /* function? */filterFunction, /* boolean? */returnFirstHit) {
	//	summary
	//	returns all ancestors matching optional filterFunction; will return only the first if returnFirstHit
	var ancestors = [];
	var isFunction = (filterFunction && (filterFunction instanceof Function || typeof filterFunction == "function"));
	while(node) {
		if (!isFunction || filterFunction(node)) {
			ancestors.push(node);
		}
		if (returnFirstHit && ancestors.length > 0) { 
			return ancestors[0]; 	//	Node
		}
		
		node = node.parentNode;
	}
	if (returnFirstHit) { return null; }
	return ancestors;	//	array
}

dojo.dom.getAncestorsByTag = function(/* Node */node, /* string */tag, /* boolean? */returnFirstHit) {
	//	summary
	//	returns all ancestors matching tag (as tagName), will only return first one if returnFirstHit
	tag = tag.toLowerCase();
	return dojo.dom.getAncestors(node, function(el){
		return ((el.tagName)&&(el.tagName.toLowerCase() == tag));
	}, returnFirstHit);	//	Node || array
}

dojo.dom.getFirstAncestorByTag = function(/* Node */node, /* string */tag) {
	//	summary
	//	Returns first ancestor of node with tag tagName
	return dojo.dom.getAncestorsByTag(node, tag, true);	//	Node
}

dojo.dom.isDescendantOf = function(/* Node */node, /* Node */ancestor, /* boolean? */guaranteeDescendant){
	//	summary
	//	Returns boolean if node is a descendant of ancestor
	// guaranteeDescendant allows us to be a "true" isDescendantOf function
	if(guaranteeDescendant && node) { node = node.parentNode; }
	while(node) {
		if(node == ancestor){ 
			return true; 	//	boolean
		}
		node = node.parentNode;
	}
	return false;	//	boolean
}

dojo.dom.innerXML = function(/* Node */node){
	//	summary
	//	Implementation of MS's innerXML function.
	if(node.innerXML){
		return node.innerXML;	//	string
	}else if (node.xml){
		return node.xml;		//	string
	}else if(typeof XMLSerializer != "undefined"){
		return (new XMLSerializer()).serializeToString(node);	//	string
	}
}

dojo.dom.createDocument = function(){
	//	summary
	//	cross-browser implementation of creating an XML document object.
	var doc = null;
	var _document = dojo.doc();

	if(!dj_undef("ActiveXObject")){
		var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ];
		for(var i = 0; i<prefixes.length; i++){
			try{
				doc = new ActiveXObject(prefixes[i]+".XMLDOM");
			}catch(e){ /* squelch */ };

			if(doc){ break; }
		}
	}else if((_document.implementation)&&
		(_document.implementation.createDocument)){
		doc = _document.implementation.createDocument("", "", null);
	}
	
	return doc;	//	DOMDocument
}

dojo.dom.createDocumentFromText = function(/* string */str, /* string? */mimetype){
	//	summary
	//	attempts to create a Document object based on optional mime-type, using str as the contents of the document
	if(!mimetype){ mimetype = "text/xml"; }
	if(!dj_undef("DOMParser")){
		var parser = new DOMParser();
		return parser.parseFromString(str, mimetype);	//	DOMDocument
	}else if(!dj_undef("ActiveXObject")){
		var domDoc = dojo.dom.createDocument();
		if(domDoc){
			domDoc.async = false;
			domDoc.loadXML(str);
			return domDoc;	//	DOMDocument
		}else{
			dojo.debug("toXml didn't work?");
		}
	/*
	}else if((dojo.render.html.capable)&&(dojo.render.html.safari)){
		// FIXME: this doesn't appear to work!
		// from: http://web-graphics.com/mtarchive/001606.php
		// var xml = '<?xml version="1.0"?>'+str;
		var mtype = "text/xml";
		var xml = '<?xml version="1.0"?>'+str;
		var url = "data:"+mtype+";charset=utf-8,"+encodeURIComponent(xml);
		var req = new XMLHttpRequest();
		req.open("GET", url, false);
		req.overrideMimeType(mtype);
		req.send(null);
		return req.responseXML;
	*/
	}else{
		var _document = dojo.doc();
		if(_document.createElement){
			// FIXME: this may change all tags to uppercase!
			var tmp = _document.createElement("xml");
			tmp.innerHTML = str;
			if(_document.implementation && _document.implementation.createDocument) {
				var xmlDoc = _document.implementation.createDocument("foo", "", null);
				for(var i = 0; i < tmp.childNodes.length; i++) {
					xmlDoc.importNode(tmp.childNodes.item(i), true);
				}
				return xmlDoc;	//	DOMDocument
			}
			// FIXME: probably not a good idea to have to return an HTML fragment
			// FIXME: the tmp.doc.firstChild is as tested from IE, so it may not
			// work that way across the board
			return ((tmp.document)&&
				(tmp.document.firstChild ?  tmp.document.firstChild : tmp));	//	DOMDocument
		}
	}
	return null;
}

dojo.dom.prependChild = function(/* Element */node, /* Element */parent) {
	// summary
	//	prepends node to parent's children nodes
	if(parent.firstChild) {
		parent.insertBefore(node, parent.firstChild);
	} else {
		parent.appendChild(node);
	}
	return true;	//	boolean
}

dojo.dom.insertBefore = function(/* Node */node, /* Node */ref, /* boolean? */force){
	//	summary
	//	Try to insert node before ref
	if (force != true &&
		(node === ref || node.nextSibling === ref)){ return false; }
	var parent = ref.parentNode;
	parent.insertBefore(node, ref);
	return true;	//	boolean
}

dojo.dom.insertAfter = function(/* Node */node, /* Node */ref, /* boolean? */force){
	//	summary
	//	Try to insert node after ref
	var pn = ref.parentNode;
	if(ref == pn.lastChild){
		if((force != true)&&(node === ref)){
			return false;	//	boolean
		}
		pn.appendChild(node);
	}else{
		return this.insertBefore(node, ref.nextSibling, force);	//	boolean
	}
	return true;	//	boolean
}

dojo.dom.insertAtPosition = function(/* Node */node, /* Node */ref, /* string */position){
	//	summary
	//	attempt to insert node in relation to ref based on position
	if((!node)||(!ref)||(!position)){ 
		return false;	//	boolean 
	}
	switch(position.toLowerCase()){
		case "before":
			return dojo.dom.insertBefore(node, ref);	//	boolean
		case "after":
			return dojo.dom.insertAfter(node, ref);		//	boolean
		case "first":
			if(ref.firstChild){
				return dojo.dom.insertBefore(node, ref.firstChild);	//	boolean
			}else{
				ref.appendChild(node);
				return true;	//	boolean
			}
			break;
		default: // aka: last
			ref.appendChild(node);
			return true;	//	boolean
	}
}

dojo.dom.insertAtIndex = function(/* Node */node, /* Element */containingNode, /* number */insertionIndex){
	//	summary
	//	insert node into child nodes nodelist of containingNode at insertionIndex.
	var siblingNodes = containingNode.childNodes;

	// if there aren't any kids yet, just add it to the beginning

	if (!siblingNodes.length){
		containingNode.appendChild(node);
		return true;	//	boolean
	}

	// otherwise we need to walk the childNodes
	// and find our spot

	var after = null;

	for(var i=0; i<siblingNodes.length; i++){

		var sibling_index = siblingNodes.item(i)["getAttribute"] ? parseInt(siblingNodes.item(i).getAttribute("dojoinsertionindex")) : -1;

		if (sibling_index < insertionIndex){
			after = siblingNodes.item(i);
		}
	}

	if (after){
		// add it after the node in {after}

		return dojo.dom.insertAfter(node, after);	//	boolean
	}else{
		// add it to the start

		return dojo.dom.insertBefore(node, siblingNodes.item(0));	//	boolean
	}
}
	
dojo.dom.textContent = function(/* Node */node, /* string */text){
	//	summary
	//	implementation of the DOM Level 3 attribute; scan node for text
	if (arguments.length>1) {
		var _document = dojo.doc();
		dojo.dom.replaceChildren(node, _document.createTextNode(text));
		return text;	//	string
	} else {
		if(node.textContent != undefined){ //FF 1.5
			return node.textContent;	//	string
		}
		var _result = "";
		if (node == null) { return _result; }
		for (var i = 0; i < node.childNodes.length; i++) {
			switch (node.childNodes[i].nodeType) {
				case 1: // ELEMENT_NODE
				case 5: // ENTITY_REFERENCE_NODE
					_result += dojo.dom.textContent(node.childNodes[i]);
					break;
				case 3: // TEXT_NODE
				case 2: // ATTRIBUTE_NODE
				case 4: // CDATA_SECTION_NODE
					_result += node.childNodes[i].nodeValue;
					break;
				default:
					break;
			}
		}
		return _result;	//	string
	}
}

dojo.dom.hasParent = function (/* Node */node) {
	//	summary
	//	returns whether or not node is a child of another node.
	return node && node.parentNode && dojo.dom.isNode(node.parentNode);	//	boolean
}

/**
 * Examples:
 *
 * myFooNode = <foo />
 * isTag(myFooNode, "foo"); // returns "foo"
 * isTag(myFooNode, "bar"); // returns ""
 * isTag(myFooNode, "FOO"); // returns ""
 * isTag(myFooNode, "hey", "foo", "bar"); // returns "foo"
**/
dojo.dom.isTag = function(/* Node */node /* ... */) {
	//	summary
	//	determines if node has any of the provided tag names and returns the tag name that matches, empty string otherwise.
	if(node && node.tagName) {
		for(var i=1; i<arguments.length; i++){
			if(node.tagName==String(arguments[i])){
				return String(arguments[i]);	//	string
			}
		}
	}
	return "";	//	string
}

dojo.dom.setAttributeNS = function(/* Element */elem, /* string */namespaceURI, /* string */attrName, /* string */attrValue){
	//	summary
	//	implementation of DOM2 setAttributeNS that works cross browser.
	if(elem == null || ((elem == undefined)&&(typeof elem == "undefined"))){
		dojo.raise("No element given to dojo.dom.setAttributeNS");
	}
	
	if(!((elem.setAttributeNS == undefined)&&(typeof elem.setAttributeNS == "undefined"))){ // w3c
		elem.setAttributeNS(namespaceURI, attrName, attrValue);
	}else{ // IE
		// get a root XML document
		var ownerDoc = elem.ownerDocument;
		var attribute = ownerDoc.createNode(
			2, // node type
			attrName,
			namespaceURI
		);
		
		// set value
		attribute.nodeValue = attrValue;
		
		// attach to element
		elem.setAttributeNode(attribute);
	}
}

__CPAN_FILE__ src/hostenv_wsh.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
 * WSH
 */

dojo.hostenv.name_ = 'wsh';

// make jsc shut up (so can sanity check)
/*@cc_on
@if (@_jscript_version >= 7)
var WScript;
@end
@*/

// make sure we are in right environment
if(typeof WScript == 'undefined'){
	dojo.raise("attempt to use WSH host environment when no WScript global");
}

dojo.hostenv.println = WScript.Echo;

dojo.hostenv.getCurrentScriptUri = function(){
	return WScript.ScriptFullName();
}

dojo.hostenv.getText = function(fpath){
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	var istream = fso.OpenTextFile(fpath, 1); // iomode==1 means read only
	if(!istream){
		return null;
	}
	var contents = istream.ReadAll();
	istream.Close();
	return contents;
}

dojo.hostenv.exit = function(exitcode){ WScript.Quit(exitcode); }

__CPAN_FILE__ src/AdapterRegistry.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.AdapterRegistry");
dojo.require("dojo.lang.func");

dojo.AdapterRegistry = function(/*boolean, optional*/returnWrappers){
	// summary:
	//		A registry to make contextual calling/searching easier.
	// description:
	//		Objects of this class keep list of arrays in the form [name, check,
	//		wrap, directReturn] that are used to determine what the contextual
	//		result of a set of checked arguments is. All check/wrap functions
	//		in this registry should be of the same arity.
	this.pairs = [];
	this.returnWrappers = returnWrappers || false;
}

dojo.lang.extend(dojo.AdapterRegistry, {
	register: function(	/*string*/ name, /*function*/ check, /*function*/ wrap, 
						/*boolean, optional*/ directReturn, 
						/*boolean, optional*/ override){
		// summary: 
		//		register a check function to determine if the wrap function or
		//		object gets selected
		// name: a way to identify this matcher.
		// check:
		//		a function that arguments are passed to from the adapter's
		//		match() function.  The check function should return true if the
		//		given arguments are appropriate for the wrap function.
		// directReturn:
		//		If directReturn is true, the value passed in for wrap will be
		//		returned instead of being called. Alternately, the
		//		AdapterRegistry can be set globally to "return not call" using
		//		the returnWrappers property. Either way, this behavior allows
		//		the registry to act as a "search" function instead of a
		//		function interception library.
		// override:
		//		If override is given and true, the check function will be given
		//		highest priority. Otherwise, it will be the lowest priority
		//		adapter.

		var type = (override) ? "unshift" : "push";
		this.pairs[type]([name, check, wrap, directReturn]);
	},

	match: function(/* ... */){
        // summary:
		//		Find an adapter for the given arguments. If no suitable adapter
		//		is found, throws an exception. match() accepts any number of
		//		arguments, all of which are passed to all matching functions
		//		from the registered pairs.
		for(var i = 0; i < this.pairs.length; i++){
			var pair = this.pairs[i];
			if(pair[1].apply(this, arguments)){
				if((pair[3])||(this.returnWrappers)){
					return pair[2];
				}else{
					return pair[2].apply(this, arguments);
				}
			}
		}
		throw new Error("No match found");
		// dojo.raise("No match found");
	},

	unregister: function(name){
		// summary: Remove a named adapter from the registry

		// FIXME: this is kind of a dumb way to handle this. On a large
		// registry this will be slow-ish and we can use the name as a lookup
		// should we choose to trade memory for speed.
		for(var i = 0; i < this.pairs.length; i++){
			var pair = this.pairs[i];
			if(pair[0] == name){
				this.pairs.splice(i, 1);
				return true;
			}
		}
		return false;
	}
});

__CPAN_FILE__ src/hostenv_svg.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

//	hostenv_svg
if(typeof window == 'undefined'){
	dojo.raise("attempt to use adobe svg hostenv when no window object");
}
dojo.debug = function(){ 
	if (!djConfig.isDebug) { return; }
	var args = arguments;
	var isJUM = dj_global["jum"];
	var s = isJUM ? "": "DEBUG: ";
	for (var i = 0; i < args.length; ++i){ s += args[i]; }
	if (isJUM){ // this seems to be the only way to get JUM to "play nice"
		jum.debug(s);
	} else{ 
		dojo.hostenv.println(s);
	}
};

//	set up dojo.render.
dojo.render.name = navigator.appName;
dojo.render.ver = parseFloat(navigator.appVersion, 10);
switch(navigator.platform){
	case "MacOS":
		dojo.render.os.osx =  true;
		break;
	case "Linux":
		dojo.render.os.linux =  true;
		break;
	case "Windows":
		dojo.render.os.win =  true;
		break;
	default:
		dojo.render.os.linux = true;
		break;
};
dojo.render.svg.capable = true;
dojo.render.svg.support.builtin = true;
//	FIXME the following two is a big-ass hack for now.
dojo.render.svg.moz = ((navigator.userAgent.indexOf("Gecko") >= 0) && (!((navigator.appVersion.indexOf("Konqueror") >= 0) || (navigator.appVersion.indexOf("Safari") >= 0))));
dojo.render.svg.adobe = (window.parseXML != null);

//	agent-specific implementations.

//	from old hostenv_adobesvg.
dojo.hostenv.startPackage("dojo.hostenv");
dojo.hostenv.println = function(s){ 
	try {
		var ti = document.createElement("text");
		ti.setAttribute("x","50");
		ti.setAttribute("y", (25 + 15 * document.getElementsByTagName("text").length));
		ti.appendChild(document.createTextNode(s));
		document.documentElement.appendChild(ti);
	} catch(e){ }
};
dojo.hostenv.name_ = "svg";

//	expected/defined by bootstrap1.js
dojo.hostenv.setModulePrefix = function(module, prefix){ };
dojo.hostenv.getModulePrefix = function(module){ };
dojo.hostenv.getTextStack = [];
dojo.hostenv.loadUriStack = [];
dojo.hostenv.loadedUris = [];
dojo.hostenv.modules_ = {};
dojo.hostenv.modulesLoadedFired = false;
dojo.hostenv.modulesLoadedListeners = [];
dojo.hostenv.getText = function(uri, cb, data){ 
	if (!cb) var cb = function(result){ window.alert(result); };
	if (!data) {
		window.getUrl(uri, cb);
	} else {
		window.postUrl(uri, data, cb);
	}
};
dojo.hostenv.getLibaryScriptUri = function(){ };

dojo.hostenv.loadUri = function(uri){ };
dojo.hostenv.loadUriAndCheck = function(uri, module){ };

//	aliased in loader.js, don't ignore
//	we are going to kill loadModule for the first round of SVG stuff, and include stuff manually.
dojo.hostenv.loadModule = function(moduleName){
	//	just like startPackage, but this time we're just checking to make sure it exists already.
	var a = moduleName.split(".");
	var currentObj = window;
	var s = [];
	for (var i = 0; i < a.length; i++){
		if (a[i] == "*") continue;
		s.push(a[i]);
		if (!currentObj[a[i]]){
			dojo.raise("dojo.require('" + moduleName + "'): module does not exist.");
		} else currentObj = currentObj[a[i]];
	}
	return; 
};
dojo.hostenv.startPackage = function(moduleName){
	var a = moduleName.split(".");
	var currentObj = window;
	var s = [];
	for (var i = 0; i < a.length; i++){
		if (a[i] == "*") continue;
		s.push(a[i]);
		if (!currentObj[a[i]]) currentObj[a[i]] = {};
		currentObj = currentObj[a[i]];
	}
	return; 
};

//	wrapper objects for ASVG
if (window.parseXML){
	window.XMLSerialzer = function(){
		//	based on WebFX RichTextControl getXHTML() function.
		function nodeToString(n, a) {
			function fixText(s) { return String(s).replace(/\&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;"); }
			function fixAttribute(s) { return fixText(s).replace(/\"/g, "&quot;"); }
			switch (n.nodeType) {
				case 1:	{	//	ELEMENT
					var name = n.nodeName;
					a.push("<" + name);
					for (var i = 0; i < n.attributes.length; i++) {
						if (n.attributes.item(i).specified) {
							a.push(" " + n.attributes.item(i).nodeName.toLowerCase() + "=\"" + fixAttribute(n.attributes.item(i).nodeValue) + "\"");
						}
					}
					if (n.canHaveChildren || n.hasChildNodes()) {
						a.push(">");
						for (var i = 0; i < n.childNodes.length; i++) nodeToString(n.childNodes.item(i), a);
						a.push("</" + name + ">\n");
					} else a.push(" />\n");
					break;
				}
				case 3: {	//	TEXT
					a.push(fixText(n.nodeValue));
					break;
				}
				case 4: {	//	CDATA
					a.push("<![CDA" + "TA[\n" + n.nodeValue + "\n]" + "]>");
					break;
				}
				case 7:{	//	PROCESSING INSTRUCTION
					a.push(n.nodeValue);
					if (/(^<\?xml)|(^<\!DOCTYPE)/.test(n.nodeValue)) a.push("\n");
					break;
				}
				case 8:{	//	COMMENT
					a.push("<!-- " + n.nodeValue + " -->\n");
					break;
				}
				case 9:		//	DOCUMENT
				case 11:{	//	DOCUMENT FRAGMENT
					for (var i = 0; i < n.childNodes.length; i++) nodeToString(n.childNodes.item(i), a);
					break;
				}
				default:{
					a.push("<!--\nNot Supported:\n\n" + "nodeType: " + n.nodeType + "\nnodeName: " + n.nodeName + "\n-->");
				}
			}
		}
		this.serializeToString = function(node){
			var a = [];
			nodeToString(node, a);
			return a.join("");
		};
	};

	window.DOMParser = function(){
		//	mimetype is basically ignored
		this.parseFromString = function(s){
			return parseXML(s, window.document);
		}
	};

	window.XMLHttpRequest = function(){
		//	we ignore the setting and getting of content-type.
		var uri = null;
		var method = "POST";
		var isAsync = true;	
		var cb = function(d){
			this.responseText = d.content;
			try {
				this.responseXML = parseXML(this.responseText, window.document);
			} catch(e){}
			this.status = "200";
			this.statusText = "OK";
			if (!d.success) {
				this.status = "500";
				this.statusText = "Internal Server Error";
			}
			this.onload();
			this.onreadystatechange();
		};
		this.onload = function(){};
		this.readyState = 4;
		this.onreadystatechange = function(){};
		this.status = 0;
		this.statusText = "";
		this.responseBody = null;
		this.responseStream = null;
		this.responseXML = null;
		this.responseText = null;
		this.abort = function(){ return; };
		this.getAllResponseHeaders = function(){ return []; };
		this.getResponseHeader = function(n){ return null; };
		this.setRequestHeader = function(nm, val){ };
		this.open = function(meth, url, async){ 
			method = meth;
			uri = url;
		};
		this.send = function(data){
			var d = data || null;
			if (method == "GET") getURL(uri, cb);
			else postURL(uri, data, cb);
		};
	};
}

__CPAN_FILE__ src/math.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.math");

dojo.math.degToRad = function(/* float */x) {
	//	summary
	//	Converts degrees to radians.
	return (x*Math.PI) / 180; 	//	float
}
dojo.math.radToDeg = function(/* float */x) { 
	//	summary
	//	Converts radians to degrees.
	return (x*180) / Math.PI; 	//	float
}

dojo.math.factorial = function(/* integer */n){
	//	summary
	//	Returns n!
	if(n<1){ return 0; }
	var retVal = 1;
	for(var i=1;i<=n;i++){ retVal *= i; }
	return retVal;	//	integer
}

dojo.math.permutations = function(/* integer */n, /* integer */k) {
	//	summary
	//	The number of ways of obtaining an ordered subset of k elements from a set of n elements
	if(n==0 || k==0) return 1;
	return (dojo.math.factorial(n) / dojo.math.factorial(n-k));	//	float
}

dojo.math.combinations = function (/* integer */n, /* integer */r) {
	//	summary
	//	The number of ways of picking n unordered outcomes from r possibilities
	if(n==0 || r==0) return 1;
	return (dojo.math.factorial(n) / (dojo.math.factorial(n-r) * dojo.math.factorial(r)));	//	float
}

dojo.math.bernstein = function(/* float */t, /* float */n, /* float */i) {
	//	summary
	//	Calculates a weighted average based on the Bernstein theorem.
	return (dojo.math.combinations(n,i) * Math.pow(t,i) * Math.pow(1-t,n-i));	//	float
}

dojo.math.gaussianRandom = function(){
	//	summary
	//	Returns random numbers with a Gaussian distribution, with the mean set at 0 and the variance set at 1.
	var k = 2;
	do {
		var i = 2 * Math.random() - 1;
		var j = 2 * Math.random() - 1;
		k = i * i + j * j;
	} while (k >= 1);
	k = Math.sqrt((-2 * Math.log(k)) / k);
	return i * k;	//	float
}

dojo.math.mean = function() {
	//	summary
	//	Calculates the mean of an Array of numbers.
	var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments;
	var mean = 0;
	for (var i = 0; i < array.length; i++) { mean += array[i]; }
	return mean / array.length;	//	float
}

dojo.math.round = function(/* float */number, /* integer */places) {
	//	summary
	//	Extends Math.round by adding a second argument specifying the number of decimal places to round to.
	// TODO: add support for significant figures
	if (!places) { var shift = 1; }
	else { var shift = Math.pow(10, places); }
	return Math.round(number * shift) / shift;	//	float
}

dojo.math.sd = dojo.math.standardDeviation = function(/* array */){
	//	summary
	//	Calculates the standard deviation of an Array of numbers
	var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments;
	return Math.sqrt(dojo.math.variance(array));	//	float
}

dojo.math.variance = function(/* array */) {
	//	summary
	//	Calculates the variance of an Array of numbers
	var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments;
	var mean = 0, squares = 0;
	for (var i = 0; i < array.length; i++) {
		mean += array[i];
		squares += Math.pow(array[i], 2);
	}
	return (squares / array.length) - Math.pow(mean / array.length, 2);	//	float
}

dojo.math.range = function(/* integer */a, /* integer */b, /* integer */step) {
	//	summary
	//	implementation of Python's range()
    if(arguments.length < 2) {
        b = a;
        a = 0;
    }
    if(arguments.length < 3) {
        step = 1;
    }

    var range = [];
    if(step > 0) {
        for(var i = a; i < b; i += step) {
            range.push(i);
        }
    } else if(step < 0) {
        for(var i = a; i > b; i += step) {
            range.push(i);
        }
    } else {
        throw new Error("dojo.math.range: step must be non-zero");
    }
    return range;	//	array
}

__CPAN_FILE__ src/a11y.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.a11y");

dojo.require("dojo.uri.*");
dojo.require("dojo.html.common");

dojo.a11y = {
	// imgPath: String path to the test image for determining if images are displayed or not
	// doAccessibleCheck: Boolean if true will perform check for need to create accessible widgets
	// accessible: Boolean uninitialized when null (accessible check has not been performed)
	//   if true generate accessible widgets
	imgPath:dojo.uri.dojoUri("src/widget/templates/images"),
	doAccessibleCheck: true,
	accessible: null,		

	checkAccessible: function(){ 
	// summary: 
	//		perform check for accessibility if accessibility checking is turned
	//		on and the accessibility test has not been performed yet
		if(this.accessible === null){ 
			this.accessible = false; //default
			if(this.doAccessibleCheck == true){ 
				this.accessible = this.testAccessible();
			}
		}
		return this.accessible; /* Boolean */
	},
	
	testAccessible: function(){
	// summary: 
	//		Always perform the accessibility check to determine if high 
	//		contrast mode is on or display of images are turned off. Currently only checks 
	//		in IE and Mozilla. 
		this.accessible = false; //default
		if (dojo.render.html.ie || dojo.render.html.mozilla){
			var div = document.createElement("div");
			//div.style.color="rgb(153,204,204)";
			div.style.backgroundImage = "url(\"" + this.imgPath + "/tab_close.gif\")";
			// must add to hierarchy before can view currentStyle below
			dojo.body().appendChild(div);
			// in FF and IE the value for the current background style of the added div
			// will be "none" in high contrast mode
			// in FF the return value will be url(invalid-url:) when running over http 
			var bkImg = null;
			if (window.getComputedStyle  ) {
				var cStyle = getComputedStyle(div, ""); 
				bkImg = cStyle.getPropertyValue("background-image");
			}else{
				bkImg = div.currentStyle.backgroundImage;
			}
			var bUseImgElem = false;
			if (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )) {
				this.accessible = true;
			}
			/*
			if(this.accessible == false && document.images){
				// test if images are off in IE
				var testImg = new Image();
				if(testImg.fileSize) {
					testImg.src = this.imgPath + "/tab_close.gif";
					if(testImg.fileSize < 0){ 
						this.accessible = true;
					}
				}	
			}*/
			dojo.body().removeChild(div);
		}
		return this.accessible; /* Boolean */
	},
	
	setCheckAccessible: function(/* Boolean */ bTest){ 
	// summary: 
	//		Set whether or not to check for accessibility mode.  Default value
	//		of module is true - perform check for accessibility modes. 
	//		bTest: Boolean - true to check; false to turn off checking
		this.doAccessibleCheck = bTest;
	},

	setAccessibleMode: function(){
	// summary:
	//		perform the accessibility check and sets the correct mode to load 
	//		a11y widgets. Only runs if test for accessiiblity has not been performed yet. 
	//		Call testAccessible() to force the test.
		if (this.accessible === null){
			if (this.checkAccessible()){
				dojo.render.html.prefixes.unshift("a11y");
			}
		}
		return this.accessible; /* Boolean */
	}
};

//dojo.hostenv.modulesLoadedListeners.unshift(function() { dojo.a11y.setAccessibleMode(); });
//dojo.event.connect("before", dojo.hostenv, "makeWidgets", dojo.a11y, "setAccessibleMode");

__CPAN_FILE__ src/event.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.event");

dojo.require("dojo.event.*");
dojo.deprecated("dojo.event", "replaced by dojo.event.*", "0.5");

__CPAN_FILE__ src/hostenv_browser.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

if (typeof window != 'undefined') {

// attempt to figure out the path to dojo if it isn't set in the config
(function() {
	// before we get any further with the config options, try to pick them out
	// of the URL. Most of this code is from NW
	if(djConfig.allowQueryConfig){
		var baseUrl = document.location.toString(); // FIXME: use location.query instead?
		var params = baseUrl.split("?", 2);
		if(params.length > 1){
			var paramStr = params[1];
			var pairs = paramStr.split("&");
			for(var x in pairs){
				var sp = pairs[x].split("=");
				// FIXME: is this eval dangerous?
				if((sp[0].length > 9)&&(sp[0].substr(0, 9) == "djConfig.")){
					var opt = sp[0].substr(9);
					try{
						djConfig[opt]=eval(sp[1]);
					}catch(e){
						djConfig[opt]=sp[1];
					}
				}
			}
		}
	}

	if(((djConfig["baseScriptUri"] == "")||(djConfig["baseRelativePath"] == "")) &&(document && document.getElementsByTagName)){
		var scripts = document.getElementsByTagName("script");
		var rePkg = /(__package__|dojo|bootstrap1)\.js([\?\.]|$)/i;
		for(var i = 0; i < scripts.length; i++) {
			var src = scripts[i].getAttribute("src");
			if(!src) { continue; }
			var m = src.match(rePkg);
			if(m) {
				var root = src.substring(0, m.index);
				if(src.indexOf("bootstrap1") > -1) { root += "../"; }
				if(!this["djConfig"]) { djConfig = {}; }
				if(djConfig["baseScriptUri"] == "") { djConfig["baseScriptUri"] = root; }
				if(djConfig["baseRelativePath"] == "") { djConfig["baseRelativePath"] = root; }
				break;
			}
		}
	}

	// fill in the rendering support information in dojo.render.*
	var dr = dojo.render;
	var drh = dojo.render.html;
	var drs = dojo.render.svg;
	var dua = (drh.UA = navigator.userAgent);
	var dav = (drh.AV = navigator.appVersion);
	var t = true;
	var f = false;
	drh.capable = t;
	drh.support.builtin = t;

	dr.ver = parseFloat(drh.AV);
	dr.os.mac = dav.indexOf("Macintosh") >= 0;
	dr.os.win = dav.indexOf("Windows") >= 0;
	// could also be Solaris or something, but it's the same browser
	dr.os.linux = dav.indexOf("X11") >= 0;

	drh.opera = dua.indexOf("Opera") >= 0;
	drh.khtml = (dav.indexOf("Konqueror") >= 0)||(dav.indexOf("Safari") >= 0);
	drh.safari = dav.indexOf("Safari") >= 0;
	var geckoPos = dua.indexOf("Gecko");
	drh.mozilla = drh.moz = (geckoPos >= 0)&&(!drh.khtml);
	if (drh.mozilla) {
		// gecko version is YYYYMMDD
		drh.geckoVersion = dua.substring(geckoPos + 6, geckoPos + 14);
	}
	drh.ie = (document.all)&&(!drh.opera);
	drh.ie50 = drh.ie && dav.indexOf("MSIE 5.0")>=0;
	drh.ie55 = drh.ie && dav.indexOf("MSIE 5.5")>=0;
	drh.ie60 = drh.ie && dav.indexOf("MSIE 6.0")>=0;
	drh.ie70 = drh.ie && dav.indexOf("MSIE 7.0")>=0;

	var cm = document["compatMode"];
	drh.quirks = (cm == "BackCompat")||(cm == "QuirksMode")||drh.ie55||drh.ie50;

	// TODO: is the HTML LANG attribute relevant?
	dojo.locale = dojo.locale || (drh.ie ? navigator.userLanguage : navigator.language).toLowerCase();

	dr.vml.capable=drh.ie;
	drs.capable = f;
	drs.support.plugin = f;
	drs.support.builtin = f;
	var tdoc = window["document"];
	var tdi = tdoc["implementation"];

	if((tdi)&&(tdi["hasFeature"])&&(tdi.hasFeature("org.w3c.dom.svg", "1.0"))){
		drs.capable = t;
		drs.support.builtin = t;
		drs.support.plugin = f;
	}
	// webkits after 420 support SVG natively. The test string is "AppleWebKit/420+"
	if(drh.safari){
		var tmp = dua.split("AppleWebKit/")[1];
		var ver = parseFloat(tmp.split(" ")[0]);
		if(ver >= 420){
			drs.capable = t;
			drs.support.builtin = t;
			drs.support.plugin = f;
		}
	}
})();

dojo.hostenv.startPackage("dojo.hostenv");

dojo.render.name = dojo.hostenv.name_ = 'browser';
dojo.hostenv.searchIds = [];

// These are in order of decreasing likelihood; this will change in time.
dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];

dojo.hostenv.getXmlhttpObject = function(){
    var http = null;
	var last_e = null;
	try{ http = new XMLHttpRequest(); }catch(e){}
    if(!http){
		for(var i=0; i<3; ++i){
			var progid = dojo.hostenv._XMLHTTP_PROGIDS[i];
			try{
				http = new ActiveXObject(progid);
			}catch(e){
				last_e = e;
			}

			if(http){
				dojo.hostenv._XMLHTTP_PROGIDS = [progid];  // so faster next time
				break;
			}
		}

		/*if(http && !http.toString) {
			http.toString = function() { "[object XMLHttpRequest]"; }
		}*/
	}

	if(!http){
		return dojo.raise("XMLHTTP not available", last_e);
	}

	return http;
}

/**
 * Read the contents of the specified uri and return those contents.
 *
 * @param uri A relative or absolute uri. If absolute, it still must be in the
 * same "domain" as we are.
 *
 * @param async_cb If not specified, load synchronously. If specified, load
 * asynchronously, and use async_cb as the progress handler which takes the
 * xmlhttp object as its argument. If async_cb, this function returns null.
 *
 * @param fail_ok Default false. If fail_ok and !async_cb and loading fails,
 * return null instead of throwing.
 */
dojo.hostenv._blockAsync = false;
dojo.hostenv.getText = function(uri, async_cb, fail_ok){
	// need to block async callbacks from snatching this thread as the result
	// of an async callback might call another sync XHR, this hangs khtml forever
	// hostenv._blockAsync must also be checked in BrowserIO's watchInFlight()
	// NOTE: must be declared before scope switches ie. this.getXmlhttpObject()
	if(!async_cb){ this._blockAsync = true; }

	var http = this.getXmlhttpObject();

	function isDocumentOk(http){
		var stat = http["status"];
		// allow a 304 use cache, needed in konq (is this compliant with the http spec?)
		return Boolean((!stat)||((200 <= stat)&&(300 > stat))||(stat==304));
	}

	if(async_cb){
		var _this = this, timer = null, gbl = dojo.global();
		var xhr = dojo.evalObjPath("dojo.io.XMLHTTPTransport");
		http.onreadystatechange = function(){
			if(timer){ gbl.clearTimeout(timer); timer = null; }
			if(_this._blockAsync || (xhr && xhr._blockAsync)){
				timer = gbl.setTimeout(function () { http.onreadystatechange.apply(this); }, 10);
			}else{
				if(4==http.readyState){
					if(isDocumentOk(http)){
						// dojo.debug("LOADED URI: "+uri);
						async_cb(http.responseText);
					}
				}
			}
		}
	}

	http.open('GET', uri, async_cb ? true : false);
	try{
		http.send(null);
		if(async_cb){
			return null;
		}
		if(!isDocumentOk(http)){
			var err = Error("Unable to load "+uri+" status:"+ http.status);
			err.status = http.status;
			err.responseText = http.responseText;
			throw err;
		}
	}catch(e){
		this._blockAsync = false;
		if((fail_ok)&&(!async_cb)){
			return null;
		}else{
			throw e;
		}
	}

	this._blockAsync = false;
	return http.responseText;
}

/*
 * It turns out that if we check *right now*, as this script file is being loaded,
 * then the last script element in the window DOM is ourselves.
 * That is because any subsequent script elements haven't shown up in the document
 * object yet.
 */
 /*
function dj_last_script_src() {
    var scripts = window.document.getElementsByTagName('script');
    if(scripts.length < 1){
		dojo.raise("No script elements in window.document, so can't figure out my script src");
	}
    var script = scripts[scripts.length - 1];
    var src = script.src;
    if(!src){
		dojo.raise("Last script element (out of " + scripts.length + ") has no src");
	}
    return src;
}

if(!dojo.hostenv["library_script_uri_"]){
	dojo.hostenv.library_script_uri_ = dj_last_script_src();
}
*/

dojo.hostenv.defaultDebugContainerId = 'dojoDebug';
dojo.hostenv._println_buffer = [];
dojo.hostenv._println_safe = false;
dojo.hostenv.println = function (line){
	if(!dojo.hostenv._println_safe){
		dojo.hostenv._println_buffer.push(line);
	}else{
		try {
			var console = document.getElementById(djConfig.debugContainerId ?
				djConfig.debugContainerId : dojo.hostenv.defaultDebugContainerId);
			if(!console) { console = dojo.body(); }

			var div = document.createElement("div");
			div.appendChild(document.createTextNode(line));
			console.appendChild(div);
		} catch (e) {
			try{
				// safari needs the output wrapped in an element for some reason
				document.write("<div>" + line + "</div>");
			}catch(e2){
				window.status = line;
			}
		}
	}
}

dojo.addOnLoad(function(){
	dojo.hostenv._println_safe = true;
	while(dojo.hostenv._println_buffer.length > 0){
		dojo.hostenv.println(dojo.hostenv._println_buffer.shift());
	}
});

function dj_addNodeEvtHdlr(node, evtName, fp, capture){
	var oldHandler = node["on"+evtName] || function(){};
	node["on"+evtName] = function(){
		fp.apply(node, arguments);
		oldHandler.apply(node, arguments);
	}
	return true;
}

//	BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
function dj_load_init(e){
	// allow multiple calls, only first one will take effect
	// A bug in khtml calls events callbacks for document for event which isnt supported
	// for example a created contextmenu event calls DOMContentLoaded, workaround
	var type = (e && e.type) ? e.type.toLowerCase() : "load";
	if(arguments.callee.initialized || (type!="domcontentloaded" && type!="load")){ return; }
	arguments.callee.initialized = true;
	if(typeof(_timer) != 'undefined'){
		clearInterval(_timer);
		delete _timer;
	}

	var initFunc = function(){
		//perform initialization
		if(dojo.render.html.ie){
			dojo.hostenv.makeWidgets();
		}
	};

	if(dojo.hostenv.inFlightCount == 0){
		initFunc();
		dojo.hostenv.modulesLoaded();
	}else{
		dojo.addOnLoad(initFunc);
	}
}

//	START DOMContentLoaded
// Mozilla and Opera 9 expose the event we could use
if(document.addEventListener){
	if(dojo.render.html.opera || (dojo.render.html.moz && !djConfig.delayMozLoadingFix)){
		document.addEventListener("DOMContentLoaded", dj_load_init, null);
	}

	//	mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
	//  also used for Mozilla because of trac #1640
	window.addEventListener("load", dj_load_init, null);
}

// 	for Internet Explorer. readyState will not be achieved on init call, but dojo doesn't need it
//	however, we'll include it because we don't know if there are other functions added that might.
//	Note that this has changed because the build process strips all comments--including conditional
//		ones.
if(dojo.render.html.ie && dojo.render.os.win){
	document.attachEvent("onreadystatechange", function(e){
		if(document.readyState == "complete"){
			dj_load_init();
		}
	});
}

if (/(WebKit|khtml)/i.test(navigator.userAgent)) { // sniff
    var _timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
            dj_load_init(); // call the onload handler
        }
    }, 10);
}
//	END DOMContentLoaded

// IE WebControl hosted in an application can fire "beforeunload" and "unload"
// events when control visibility changes, causing Dojo to unload too soon. The
// following code fixes the problem
// Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155
if(dojo.render.html.ie){
	dj_addNodeEvtHdlr(window, "beforeunload", function(){
		dojo.hostenv._unloading = true;
		window.setTimeout(function() {
			dojo.hostenv._unloading = false;
		}, 0);
	});
}

dj_addNodeEvtHdlr(window, "unload", function(){
	dojo.hostenv.unloaded();
	if((!dojo.render.html.ie)||(dojo.render.html.ie && dojo.hostenv._unloading)){
		dojo.hostenv.unloaded();
	}
});

dojo.hostenv.makeWidgets = function(){
	// you can put searchIds in djConfig and dojo.hostenv at the moment
	// we should probably eventually move to one or the other
	var sids = [];
	if(djConfig.searchIds && djConfig.searchIds.length > 0) {
		sids = sids.concat(djConfig.searchIds);
	}
	if(dojo.hostenv.searchIds && dojo.hostenv.searchIds.length > 0) {
		sids = sids.concat(dojo.hostenv.searchIds);
	}

	if((djConfig.parseWidgets)||(sids.length > 0)){
		if(dojo.evalObjPath("dojo.widget.Parse")){
			// we must do this on a delay to avoid:
			//	http://www.shaftek.org/blog/archives/000212.html
			// (IE bug)
				var parser = new dojo.xml.Parse();
				if(sids.length > 0){
					for(var x=0; x<sids.length; x++){
						var tmpNode = document.getElementById(sids[x]);
						if(!tmpNode){ continue; }
						var frag = parser.parseElement(tmpNode, null, true);
						dojo.widget.getParser().createComponents(frag);
					}
				}else if(djConfig.parseWidgets){
					var frag  = parser.parseElement(dojo.body(), null, true);
					dojo.widget.getParser().createComponents(frag);
				}
		}
	}
}

dojo.addOnLoad(function(){
	if(!dojo.render.html.ie) {
		dojo.hostenv.makeWidgets();
	}
});

try {
	if (dojo.render.html.ie) {
		document.namespaces.add("v","urn:schemas-microsoft-com:vml");
		document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
	}
} catch (e) { }

// stub, over-ridden by debugging code. This will at least keep us from
// breaking when it's not included
dojo.hostenv.writeIncludes = function(){}

//TODOC:  HOW TO DOC THIS?
// @global: dj_currentDocument
// summary:
//		Current document object. 'dj_currentDocument' can be modified for temporary context shifting.
// description:
//    dojo.doc() returns dojo.currentDocument.
//		Refer to dojo.doc() rather than referring to 'window.document' to ensure your
//		code runs correctly in managed contexts.
if(!dj_undef("document", this)){
	dj_currentDocument = this.document;
}

dojo.doc = function(){
	// summary:
	//		return the document object associated with the dojo.global()
	return dj_currentDocument;
}

dojo.body = function(){
	// summary:
	//		return the body object associated with dojo.doc()
	// Note: document.body is not defined for a strict xhtml document
	return dojo.doc().body || dojo.doc().getElementsByTagName("body")[0];
}

dojo.byId = function(id, doc){
	if((id)&&((typeof id == "string")||(id instanceof String))){
		if (!doc) { doc = dj_currentDocument; }
		var ele = doc.getElementById(id);
		// workaround bug in IE and Opera 8.2 where getElementById returns wrong element
		if (ele && (ele.id != id) && doc.all) {
			ele = null;
			// get all matching elements with this id
			eles = doc.all[id];
			if (eles) {
				// if more than 1, choose first with the correct id
				if (eles.length) {
					for (var i=0; i < eles.length; i++) {
						if (eles[i].id == id) {
							ele = eles[i];
							break;
						}
					}
				// return 1 and only element
				} else { ele = eles; }
			}
		}
		return ele;
	}
	return id; // assume it's a node
}

dojo.setContext = function(/*Object*/globalObject, /*Object*/ globalDocument){
	dj_currentContext = globalObject;
	dj_currentDocument = globalDocument;
};

dojo._fireCallback = function(callback, context, cbArguments) {
	if((context)&&((typeof callback == "string")||(callback instanceof String))){
		callback=context[callback];
	}
	return (context ? callback.apply(context, cbArguments || [ ]) : callback());
}

dojo.withGlobal = function(/*Object*/globalObject, /*Function*/callback, /*Object?*/thisObject, /*Array?*/cbArguments){
	// summary:
	//		Call callback with globalObject as dojo.global() and globalObject.document
	//		as dojo.doc(). If provided, globalObject will be executed in the context of
	//		object thisObject
	// description:
	//		When callback() returns or throws an error, the dojo.global() and dojo.doc() will
	//		be restored to its previous state.
	var rval;
	var oldGlob = dj_currentContext;
	var oldDoc = dj_currentDocument;
	try{
		dojo.setContext(globalObject, globalObject.document);
		rval = dojo._fireCallback(callback, thisObject, cbArguments);
	}finally{
		dojo.setContext(oldGlob, oldDoc);
	}
	return rval;
}

dojo.withDoc = function (/*Object*/documentObject, /*Function*/callback, /*Object?*/thisObject, /*Array?*/cbArguments) {
	// summary:
	//		Call callback with documentObject as dojo.doc(). If provided, callback will be executed
	//		in the context of object thisObject
	// description:
	//		When callback() returns or throws an error, the dojo.doc() will
	//		be restored to its previous state.
	var rval;
	var oldDoc = dj_currentDocument;
	try{
		dj_currentDocument = documentObject;
		rval = dojo._fireCallback(callback, thisObject, cbArguments);
	}finally{
		dj_currentDocument = oldDoc;
	}
	return rval;
}

} //if (typeof window != 'undefined')

__CPAN_FILE__ src/iCalendar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.cal.iCalendar");
dojo.deprecated("dojo.icalendar", "use dojo.cal.iCalendar isntead", "0.5");

__CPAN_FILE__ src/profile.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.profile");

// summary:
//		provides a manual profiling utility that can be used to gather relative
//		timing data.


// FIXME: need to tie into the event system or provide a closure-based way to
// watch timings of functions without manually instrumenting them.
// FIXME: need to make the dump() function work in command line environments

dojo.profile = {
	_profiles: {},
	_pns: [],

	start:function(/*String*/ name){
		// summary:
		//		start an iteration for the profiling target with the specified
		//		name. If a previously started iteration has not yet been ended
		//		for this name, it's automatically closed out and a new
		//		iteration begun.
		// name:
		//		a unique name to identify the thing being profiled
		if(!this._profiles[name]){
			this._profiles[name] = {iters: 0, total: 0};
			this._pns[this._pns.length] = name;
		}else{
			if(this._profiles[name]["start"]){
				this.end(name);
			}
		}
		this._profiles[name].end = null;
		this._profiles[name].start = new Date();
	},

	end:function(/*String*/ name){
		// summary:
		//		closes a timing loop for the named profiling target
		// name:
		//		a unique name to identify the thing being profiled. The name
		//		passed to end() should be the same as that passed to start()
		var ed = new Date();
		if((this._profiles[name])&&(this._profiles[name]["start"])){
			with(this._profiles[name]){
				end = ed;
				total += (end - start);
				start = null;
				iters++;
			}
		}else{
			// oops! bad call to end(), what should we do here?
			return true;
		}
	},

	dump:function(/*boolean*/ appendToDoc){
		// summary:
		//		output profiling data to an HTML table, optionally adding it to
		//		the bottom of the document. If profiling data has already been
		//		generated and appended to the document, it's replaced with the
		//		new data.
		// appendToDoc:
		//		optional. Defautls to "false". Should profiling information be
		//		added to the document?
		var tbl = document.createElement("table");
		with(tbl.style){
			border = "1px solid black";
			borderCollapse = "collapse";
		}
		var hdr = tbl.createTHead();
		var hdrtr = hdr.insertRow(0);
		// document.createElement("tr");
		var cols = ["Identifier","Calls","Total","Avg"];
		for(var x=0; x<cols.length; x++){
			var ntd = hdrtr.insertCell(x);
			with(ntd.style){
				backgroundColor = "#225d94";
				color = "white";
				borderBottom = "1px solid black";
				borderRight = "1px solid black";
				fontFamily = "tahoma";
				fontWeight = "bolder";
				paddingLeft = paddingRight = "5px";
			}
			ntd.appendChild(document.createTextNode(cols[x]));
		}

		for(var x=0; x < this._pns.length; x++){
			var prf = this._profiles[this._pns[x]];
			this.end(this._pns[x]);
			if(prf.iters>0){
				var bdytr = tbl.insertRow(true);
				var vals = [this._pns[x], prf.iters, prf.total, parseInt(prf.total/prf.iters)];
				for(var y=0; y<vals.length; y++){
					var cc = bdytr.insertCell(y);
					cc.appendChild(document.createTextNode(vals[y]));
					with(cc.style){
						borderBottom = "1px solid gray";
						paddingLeft = paddingRight = "5px";
						if(x%2){
							backgroundColor = "#e1f1ff";
						}
						if(y>0){
							textAlign = "right";
							borderRight = "1px solid gray";
						}else{
							borderRight = "1px solid black";
						}
					}
				}
			}
		}

		if(appendToDoc){
			var ne = document.createElement("div");
			ne.id = "profileOutputTable";
			with(ne.style){
				fontFamily = "Courier New, monospace";
				fontSize = "12px";
				lineHeight = "16px";
				borderTop = "1px solid black";
				padding = "10px";
			}
			if(document.getElementById("profileOutputTable")){
				dojo.body().replaceChild(ne, document.getElementById("profileOutputTable"));
			}else{
				dojo.body().appendChild(ne);
			}
			ne.appendChild(tbl);
		}

		return tbl; // DOMNode
	}
}

dojo.profile.stop = dojo.profile.end;

__CPAN_FILE__ src/flash.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.flash");

dojo.require("dojo.string.*");
dojo.require("dojo.uri.*");
dojo.require("dojo.html.common");

/** 
		The goal of dojo.flash is to make it easy to extend Flash's capabilities
		into an AJAX/DHTML environment. Robust, performant, reliable 
		JavaScript/Flash communication is harder than most realize when they
		delve into the topic, especially if you want it
		to work on Internet Explorer, Firefox, and Safari, and to be able to
		push around hundreds of K of information quickly. Dojo.flash makes it
		possible to support these platforms; you have to jump through a few
		hoops to get its capabilites, but if you are a library writer 
		who wants to bring Flash's storage or streaming sockets ability into
		DHTML, for example, then dojo.flash is perfect for you.
  
		Dojo.flash provides an easy object for interacting with the Flash plugin. 
		This object provides methods to determine the current version of the Flash
		plugin (dojo.flash.info); execute Flash instance methods 
		independent of the Flash version
		being used (dojo.flash.comm); write out the necessary markup to 
		dynamically insert a Flash object into the page (dojo.flash.Embed; and 
		do dynamic installation and upgrading of the current Flash plugin in 
		use (dojo.flash.Install).
		
		To use dojo.flash, you must first wait until Flash is finished loading 
		and initializing before you attempt communication or interaction. 
		To know when Flash is finished use dojo.event.connect:
		
		dojo.event.connect(dojo.flash, "loaded", myInstance, "myCallback");
		
		Then, while the page is still loading provide the file name
		and the major version of Flash that will be used for Flash/JavaScript
		communication (see "Flash Communication" below for information on the 
		different kinds of Flash/JavaScript communication supported and how they 
		depend on the version of Flash installed):
		
		dojo.flash.setSwf({flash6: "src/storage/storage_flash6.swf",
											 flash8: "src/storage/storage_flash8.swf"});
		
		This will cause dojo.flash to pick the best way of communicating
		between Flash and JavaScript based on the platform.
		
		If no SWF files are specified, then Flash is not initialized.
		
		Your Flash must use DojoExternalInterface to expose Flash methods and
		to call JavaScript; see "Flash Communication" below for details.
		
		setSwf can take an optional 'visible' attribute to control whether
		the Flash object is visible or not on the page; the default is visible:
		
		dojo.flash.setSwf({flash6: "src/storage/storage_flash6.swf",
											 flash8: "src/storage/storage_flash8.swf",
											 visible: false});
		
		Once finished, you can query Flash version information:
		
		dojo.flash.info.version
		
		Or can communicate with Flash methods that were exposed:
		
		var results = dojo.flash.comm.sayHello("Some Message");
		
		Only string values are currently supported for both arguments and
		for return results. Everything will be cast to a string on both
		the JavaScript and Flash sides.
		
		-------------------
		Flash Communication
		-------------------
		
		dojo.flash allows Flash/JavaScript communication in 
		a way that can pass large amounts of data back and forth reliably and
		very fast. The dojo.flash
		framework encapsulates the specific way in which this communication occurs,
		presenting a common interface to JavaScript irrespective of the underlying
		Flash version.
		
		There are currently three major ways to do Flash/JavaScript communication
		in the Flash community:
		
		1) Flash 6+ - Uses Flash methods, such as SetVariable and TCallLabel,
		and the fscommand handler to do communication. Strengths: Very fast,
		mature, and can send extremely large amounts of data; can do
		synchronous method calls. Problems: Does not work on Safari; works on 
		Firefox/Mac OS X only if Flash 8 plugin is installed; cryptic to work with.
		
		2) Flash 8+ - Uses ExternalInterface, which provides a way for Flash
		methods to register themselves for callbacks from JavaScript, and a way
		for Flash to call JavaScript. Strengths: Works on Safari; elegant to
		work with; can do synchronous method calls. Problems: Extremely buggy 
		(fails if there are new lines in the data, for example); performance
		degrades drastically in O(n^2) time as data grows; locks up the browser while
		it is communicating; does not work in Internet Explorer if Flash
		object is dynamically added to page with document.writeln, DOM methods,
		or innerHTML.
		
		3) Flash 6+ - Uses two seperate Flash applets, one that we 
		create over and over, passing input data into it using the PARAM tag, 
		which then uses a Flash LocalConnection to pass the data to the main Flash
		applet; communication back to Flash is accomplished using a getURL
		call with a javascript protocol handler, such as "javascript:myMethod()".
		Strengths: the most cross browser, cross platform pre-Flash 8 method
		of Flash communication known; works on Safari. Problems: Timing issues;
		clunky and complicated; slow; can only send very small amounts of
		data (several K); all method calls are asynchronous.
		
		dojo.flash.comm uses only the first two methods. This framework
		was created primarily for dojo.storage, which needs to pass very large
		amounts of data synchronously and reliably across the Flash/JavaScript
		boundary. We use the first method, the Flash 6 method, on all platforms
		that support it, while using the Flash 8 ExternalInterface method
		only on Safari with some special code to help correct ExternalInterface's
		bugs.
		
		Since dojo.flash needs to have two versions of the Flash
		file it wants to generate, a Flash 6 and a Flash 8 version to gain
		true cross-browser compatibility, several tools are provided to ease
		development on the Flash side.
		
		In your Flash file, if you want to expose Flash methods that can be
		called, use the DojoExternalInterface class to register methods. This
		class is an exact API clone of the standard ExternalInterface class, but
		can work in Flash 6+ browsers. Under the covers it uses the best
		mechanism to do communication:
		
		class HelloWorld{
			function HelloWorld(){
				// Initialize the DojoExternalInterface class
				DojoExternalInterface.initialize();
				
				// Expose your methods
				DojoExternalInterface.addCallback("sayHello", this, this.sayHello);
				
				// Tell JavaScript that you are ready to have method calls
				DojoExternalInterface.loaded();
				
				// Call some JavaScript
				var resultsReady = function(results){
					trace("Received the following results from JavaScript: " + results);
				}
				DojoExternalInterface.call("someJavaScriptMethod", resultsReady, 
																	 someParameter);
			}
			
			function sayHello(){ ... }
			
			static main(){ ... }
		}
		
		DojoExternalInterface adds two new functions to the ExternalInterface
		API: initialize() and loaded(). initialize() must be called before
		any addCallback() or call() methods are run, and loaded() must be
		called after you are finished adding your callbacks. Calling loaded()
		will fire the dojo.flash.loaded() event, so that JavaScript can know that
		Flash has finished loading and adding its callbacks, and can begin to
		interact with the Flash file.
		
		To generate your SWF files, use the ant task
		"buildFlash". You must have the open source Motion Twin ActionScript 
		compiler (mtasc) installed and in your path to use the "buildFlash"
		ant task; download and install mtasc from http://www.mtasc.org/.
		
		
		
		buildFlash usage:
		
		ant buildFlash -Ddojo.flash.file=../tests/flash/HelloWorld.as
		
		where "dojo.flash.file" is the relative path to your Flash 
		ActionScript file.
		
		This will generate two SWF files, one ending in _flash6.swf and the other
		ending in _flash8.swf in the same directory as your ActionScript method:
		
		HelloWorld_flash6.swf
		HelloWorld_flash8.swf
		
		Initialize dojo.flash with the filename and Flash communication version to
		use during page load; see the documentation for dojo.flash for details:
		
		dojo.flash.setSwf({flash6: "tests/flash/HelloWorld_flash6.swf",
											 flash8: "tests/flash/HelloWorld_flash8.swf"});
		
		Now, your Flash methods can be called from JavaScript as if they are native
		Flash methods, mirrored exactly on the JavaScript side:
		
		dojo.flash.comm.sayHello();
		
		Only Strings are supported being passed back and forth currently.
		
		JavaScript to Flash communication is synchronous; i.e., results are returned
		directly from the method call:
		
		var results = dojo.flash.comm.sayHello();
		
		Flash to JavaScript communication is asynchronous due to limitations in
		the underlying technologies; you must use a results callback to handle
		results returned by JavaScript in your Flash AS files:
		
		var resultsReady = function(results){
			trace("Received the following results from JavaScript: " + results);
		}
		DojoExternalInterface.call("someJavaScriptMethod", resultsReady);
		
		
		
		-------------------
		Notes
		-------------------
		
		If you have both Flash 6 and Flash 8 versions of your file:
		
		dojo.flash.setSwf({flash6: "tests/flash/HelloWorld_flash6.swf",
											 flash8: "tests/flash/HelloWorld_flash8.swf"});
											 
		but want to force the browser to use a certain version of Flash for
		all platforms (for testing, for example), use the djConfig
		variable 'forceFlashComm' with the version number to force:
		
		var djConfig = { forceFlashComm: 6 };
		
		Two values are currently supported, 6 and 8, for the two styles of
		communication described above. Just because you force dojo.flash
		to use a particular communication style is no guarantee that it will
		work; for example, Flash 8 communication doesn't work in Internet
		Explorer due to bugs in Flash, and Flash 6 communication does not work
		in Safari. It is best to let dojo.flash determine the best communication
		mechanism, and to use the value above only for debugging the dojo.flash
		framework itself.
		
		Also note that dojo.flash can currently only work with one Flash object
		on the page; it and the API do not yet support multiple Flash objects on
		the same page.
		
		We use some special tricks to get decent, linear performance
		out of Flash 8's ExternalInterface on Safari; see the blog
		post 
		http://codinginparadise.org/weblog/2006/02/how-to-speed-up-flash-8s.html
		for details.
		
		Your code can detect whether the Flash player is installing or having
		its version revved in two ways. First, if dojo.flash detects that
		Flash installation needs to occur, it sets dojo.flash.info.installing
		to true. Second, you can detect if installation is necessary with the
		following callback:
		
		dojo.event.connect(dojo.flash, "installing", myInstance, "myCallback");
		
		You can use this callback to delay further actions that might need Flash;
		when installation is finished the full page will be refreshed and the
		user will be placed back on your page with Flash installed.
		
		Two utility methods exist if you want to add loading and installing
		listeners without creating dependencies on dojo.event; these are
		'addLoadingListener' and 'addInstallingListener'.
		
		-------------------
		Todo/Known Issues
		-------------------

		There are several tasks I was not able to do, or did not need to fix
		to get dojo.storage out:		
		
		* When using Flash 8 communication, Flash method calls to JavaScript
		are not working properly; serialization might also be broken for certain
		invalid characters when it is Flash invoking JavaScript methods.
		The Flash side needs to have more sophisticated serialization/
		deserialization mechanisms like JavaScript currently has. The
		test_flash2.html unit tests should also be updated to have much more
		sophisticated Flash to JavaScript unit tests, including large
		amounts of data.
		
		* On Internet Explorer, after doing a basic install, the page is
		not refreshed or does not detect that Flash is now available. The way
		to fix this is to create a custom small Flash file that is pointed to
		during installation; when it is finished loading, it does a callback
		that says that Flash installation is complete on IE, and we can proceed
		to initialize the dojo.flash subsystem.
		
		@author Brad Neuberg, bkn3@columbia.edu
*/

dojo.flash = {
	flash6_version: null,
	flash8_version: null,
	ready: false,
	_visible: true,
	_loadedListeners: new Array(),
	_installingListeners: new Array(),
	
	/** Sets the SWF files and versions we are using. */
	setSwf: function(fileInfo){
		//dojo.debug("setSwf");
		if(fileInfo == null || dojo.lang.isUndefined(fileInfo)){
			return;
		}
		
		if(fileInfo.flash6 != null && !dojo.lang.isUndefined(fileInfo.flash6)){
			this.flash6_version = fileInfo.flash6;
		}
		
		if(fileInfo.flash8 != null && !dojo.lang.isUndefined(fileInfo.flash8)){
			this.flash8_version = fileInfo.flash8;
		}
		
		if(!dojo.lang.isUndefined(fileInfo.visible)){
			this._visible = fileInfo.visible;
		}
		
		// initialize ourselves		
		this._initialize();
	},
	
	/** Returns whether we are using Flash 6 for communication on this platform. */
	useFlash6: function(){
		if(this.flash6_version == null){
			return false;
		}else if (this.flash6_version != null && dojo.flash.info.commVersion == 6){
			// if we have a flash 6 version of this SWF, and this browser supports 
			// communicating using Flash 6 features...
			return true;
		}else{
			return false;
		}
	},
	
	/** Returns whether we are using Flash 8 for communication on this platform. */
	useFlash8: function(){
		if(this.flash8_version == null){
			return false;
		}else if (this.flash8_version != null && dojo.flash.info.commVersion == 8){
			// if we have a flash 8 version of this SWF, and this browser supports
			// communicating using Flash 8 features...
			return true;
		}else{
			return false;
		}
	},
	
	/** Adds a listener to know when Flash is finished loading. 
			Useful if you don't want a dependency on dojo.event. */
	addLoadedListener: function(listener){
		this._loadedListeners.push(listener);
	},

	/** Adds a listener to know if Flash is being installed. 
			Useful if you don't want a dependency on dojo.event. */
	addInstallingListener: function(listener){
		this._installingListeners.push(listener);
	},	
	
	/** 
			A callback when the Flash subsystem is finished loading and can be
			worked with. To be notified when Flash is finished loading, connect
			your callback to this method using the following:
			
			dojo.event.connect(dojo.flash, "loaded", myInstance, "myCallback");
	*/
	loaded: function(){
		//dojo.debug("dojo.flash.loaded");
		dojo.flash.ready = true;
		if(dojo.flash._loadedListeners.length > 0){
			for(var i = 0;i < dojo.flash._loadedListeners.length; i++){
				dojo.flash._loadedListeners[i].call(null);
			}
		}
	},
	
	/** 
			A callback to know if Flash is currently being installed or
			having its version revved. To be notified if Flash is installing, connect
			your callback to this method using the following:
			
			dojo.event.connect(dojo.flash, "installing", myInstance, "myCallback");
	*/
	installing: function(){
	 //dojo.debug("installing");
	 if(dojo.flash._installingListeners.length > 0){
			for(var i = 0; i < dojo.flash._installingListeners.length; i++){
				dojo.flash._installingListeners[i].call(null);
			}
		}
	},
	
	/** Initializes dojo.flash. */
	_initialize: function(){
		//dojo.debug("dojo.flash._initialize");
		// see if we need to rev or install Flash on this platform
		var installer = new dojo.flash.Install();
		dojo.flash.installer = installer;

		if(installer.needed() == true){		
			installer.install();
		}else{
			//dojo.debug("Writing object out");
			// write the flash object into the page
			dojo.flash.obj = new dojo.flash.Embed(this._visible);
			dojo.flash.obj.write(dojo.flash.info.commVersion);
			
			// initialize the way we do Flash/JavaScript communication
			dojo.flash.comm = new dojo.flash.Communicator();
		}
	}
};


/** 
		A class that helps us determine whether Flash is available,
		it's major and minor versions, and what Flash version features should
		be used for Flash/JavaScript communication. Parts of this code
		are adapted from the automatic Flash plugin detection code autogenerated 
		by the Macromedia Flash 8 authoring environment. 
		
		An instance of this class can be accessed on dojo.flash.info after
		the page is finished loading.
		
		This constructor must be called before the page is finished loading. 
*/
dojo.flash.Info = function(){
	// Visual basic helper required to detect Flash Player ActiveX control 
	// version information on Internet Explorer
	if(dojo.render.html.ie){
		document.writeln('<script language="VBScript" type="text/vbscript"\>');
		document.writeln('Function VBGetSwfVer(i)');
		document.writeln('  on error resume next');
		document.writeln('  Dim swControl, swVersion');
		document.writeln('  swVersion = 0');
		document.writeln('  set swControl = CreateObject("ShockwaveFlash.ShockwaveFlash." + CStr(i))');
		document.writeln('  if (IsObject(swControl)) then');
		document.writeln('    swVersion = swControl.GetVariable("$version")');
		document.writeln('  end if');
		document.writeln('  VBGetSwfVer = swVersion');
		document.writeln('End Function');
		document.writeln('</script\>');
	}
	
	this._detectVersion();
	this._detectCommunicationVersion();
}

dojo.flash.Info.prototype = {
	/** The full version string, such as "8r22". */
	version: -1,
	
	/** 
			The major, minor, and revisions of the plugin. For example, if the
			plugin is 8r22, then the major version is 8, the minor version is 0,
			and the revision is 22. 
	*/
	versionMajor: -1,
	versionMinor: -1,
	versionRevision: -1,
	
	/** Whether this platform has Flash already installed. */
	capable: false,
	
	/** 
			The major version number for how our Flash and JavaScript communicate.
			This can currently be the following values:
			6 - We use a combination of the Flash plugin methods, such as SetVariable
			and TCallLabel, along with fscommands, to do communication.
			8 - We use the ExternalInterface API. 
			-1 - For some reason neither method is supported, and no communication
			is possible. 
	*/
	commVersion: 6,
	
	/** Set if we are in the middle of a Flash installation session. */
	installing: false,
	
	/** 
			Asserts that this environment has the given major, minor, and revision
			numbers for the Flash player. Returns true if the player is equal
			or above the given version, false otherwise.
			
			Example: To test for Flash Player 7r14:
			
			dojo.flash.info.isVersionOrAbove(7, 0, 14)
	*/
	isVersionOrAbove: function(reqMajorVer, reqMinorVer, reqVer){
		// make the revision a decimal (i.e. transform revision 14 into
		// 0.14
		reqVer = parseFloat("." + reqVer);
		
		if(this.versionMajor >= reqMajorVer && this.versionMinor >= reqMinorVer
			 && this.versionRevision >= reqVer){
			return true;
		}else{
			return false;
		}
	},
	
	_detectVersion: function(){
		var versionStr;
		
		// loop backwards through the versions until we find the newest version	
		for(var testVersion = 25; testVersion > 0; testVersion--){
			if(dojo.render.html.ie){
				versionStr = VBGetSwfVer(testVersion);
			}else{
				versionStr = this._JSFlashInfo(testVersion);		
			}
				
			if(versionStr == -1 ){
				this.capable = false; 
				return;
			}else if(versionStr != 0){
				var versionArray;
				if(dojo.render.html.ie){
					var tempArray = versionStr.split(" ");
					var tempString = tempArray[1];
					versionArray = tempString.split(",");
				}else{
					versionArray = versionStr.split(".");
				}
					
				this.versionMajor = versionArray[0];
				this.versionMinor = versionArray[1];
				this.versionRevision = versionArray[2];
				
				// 7.0r24 == 7.24
				var versionString = this.versionMajor + "." + this.versionRevision;
				this.version = parseFloat(versionString);
				
				this.capable = true;
				
				break;
			}
		}
	},
	
	/** 
			JavaScript helper required to detect Flash Player PlugIn version 
			information. Internet Explorer uses a corresponding Visual Basic
			version to interact with the Flash ActiveX control. 
	*/
	_JSFlashInfo: function(testVersion){
		// NS/Opera version >= 3 check for Flash plugin in plugin array
		if(navigator.plugins != null && navigator.plugins.length > 0){
			if(navigator.plugins["Shockwave Flash 2.0"] || 
				 navigator.plugins["Shockwave Flash"]){
				var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
				var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
				var descArray = flashDescription.split(" ");
				var tempArrayMajor = descArray[2].split(".");
				var versionMajor = tempArrayMajor[0];
				var versionMinor = tempArrayMajor[1];
				if(descArray[3] != ""){
					var tempArrayMinor = descArray[3].split("r");
				}else{
					var tempArrayMinor = descArray[4].split("r");
				}
				var versionRevision = tempArrayMinor[1] > 0 ? tempArrayMinor[1] : 0;
				var version = versionMajor + "." + versionMinor + "." 
											+ versionRevision;
											
				return version;
			}
		}
		
		return -1;
	},
	
	/** 
			Detects the mechanisms that should be used for Flash/JavaScript 
			communication, setting 'commVersion' to either 6 or 8. If the value is
			6, we use Flash Plugin 6+ features, such as GetVariable, TCallLabel,
			and fscommand, to do Flash/JavaScript communication; if the value is
			8, we use the ExternalInterface API for communication. 
	*/
	_detectCommunicationVersion: function(){
		if(this.capable == false){
			this.commVersion = null;
			return;
		}
		
		// detect if the user has over-ridden the default flash version
		if (typeof djConfig["forceFlashComm"] != "undefined" &&
				typeof djConfig["forceFlashComm"] != null){
			this.commVersion = djConfig["forceFlashComm"];
			return;
		}
		
		// we prefer Flash 6 features over Flash 8, because they are much faster
		// and much less buggy
		
		// at this point, we don't have a flash file to detect features on,
		// so we need to instead look at the browser environment we are in
		if(dojo.render.html.safari == true || dojo.render.html.opera == true){
			this.commVersion = 8;
		}else{
			this.commVersion = 6;
		}
	}
};

/** A class that is used to write out the Flash object into the page. */
dojo.flash.Embed = function(visible){
	this._visible = visible;
}

dojo.flash.Embed.prototype = {
	/** 
			The width of this Flash applet. The default is the minimal width
			necessary to show the Flash settings dialog. 
	*/
	width: 215,
	
	/** 
			The height of this Flash applet. The default is the minimal height
			necessary to show the Flash settings dialog. 
	*/
	height: 138,
	
	/** The id of the Flash object. */
	id: "flashObject",
	
	/** Controls whether this is a visible Flash applet or not. */
	_visible: true,

	protocol: function(){
		switch(window.location.protocol){
			case "https:":
				return "https";
				break;
			default:
				return "http";
				break;
		}
	},
	
	/** 
			Writes the Flash into the page. This must be called before the page
			is finished loading. 
			@param flashVer The Flash version to write.
			@param doExpressInstall Whether to write out Express Install
			information. Optional value; defaults to false.
	*/
	
	write: function(flashVer, doExpressInstall){
		//dojo.debug("write");
		if(dojo.lang.isUndefined(doExpressInstall)){
			doExpressInstall = false;
		}
		
		// determine our container div's styling
		var containerStyle = new dojo.string.Builder();
		containerStyle.append("width: " + this.width + "px; ");
		containerStyle.append("height: " + this.height + "px; ");
		if(this._visible == false){
			containerStyle.append("position: absolute; ");
			containerStyle.append("z-index: 10000; ");
			containerStyle.append("top: -1000px; ");
			containerStyle.append("left: -1000px; ");
		}
		containerStyle = containerStyle.toString();

		// figure out the SWF file to get and how to write out the correct HTML
		// for this Flash version
		var objectHTML;
		var swfloc;
		// Flash 6
		if(flashVer == 6){
			swfloc = dojo.flash.flash6_version;
			var dojoPath = djConfig.baseRelativePath;
			swfloc = swfloc + "?baseRelativePath=" + escape(dojoPath);
			objectHTML = 
						  '<embed id="' + this.id + '" src="' + swfloc + '" '
						+ '    quality="high" bgcolor="#ffffff" '
						+ '    width="' + this.width + '" height="' + this.height + '" '
						+ '    name="' + this.id + '" '
						+ '    align="middle" allowScriptAccess="sameDomain" '
						+ '    type="application/x-shockwave-flash" swLiveConnect="true" '
						+ '    pluginspage="'
						+ this.protocol()
						+ '://www.macromedia.com/go/getflashplayer">';
		}else{ // Flash 8
			swfloc = dojo.flash.flash8_version;
			var swflocObject = swfloc;
			var swflocEmbed = swfloc;
			var dojoPath = djConfig.baseRelativePath;
			if(doExpressInstall){
				// the location to redirect to after installing
				var redirectURL = escape(window.location);
				document.title = document.title.slice(0, 47) + " - Flash Player Installation";
				var docTitle = escape(document.title);
				swflocObject += "?MMredirectURL=" + redirectURL
				                + "&MMplayerType=ActiveX"
				                + "&MMdoctitle=" + docTitle
								+ "&baseRelativePath=" + escape(dojoPath);
				swflocEmbed += "?MMredirectURL=" + redirectURL 
								+ "&MMplayerType=PlugIn"
								+ "&baseRelativePath=" + escape(dojoPath);
			}

			if(swflocEmbed.indexOf("?") == -1){
				swflocEmbed +=  "?baseRelativePath="+escape(dojoPath)+"' ";
			}
			
			objectHTML =
				'<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '
				  + 'codebase="'
					+ this.protocol()
					+ '://fpdownload.macromedia.com/pub/shockwave/cabs/flash/'
					+ 'swflash.cab#version=8,0,0,0" '
				  + 'width="' + this.width + '" '
				  + 'height="' + this.height + '" '
				  + 'id="' + this.id + '" '
				  + 'align="middle"> '
				  + '<param name="allowScriptAccess" value="sameDomain" /> '
				  + '<param name="movie" value="' + swflocObject + '" /> '
				  + '<param name="quality" value="high" /> '
				  + '<param name="bgcolor" value="#ffffff" /> '
				  + '<embed src="' + swflocEmbed + "' "
				  + 'quality="high" '
				  + 'bgcolor="#ffffff" '
				  + 'width="' + this.width + '" '
				  + 'height="' + this.height + '" '
				  + 'id="' + this.id + '" '
				  + 'name="' + this.id + '" '
				  + 'swLiveConnect="true" '
				  + 'align="middle" '
				  + 'allowScriptAccess="sameDomain" '
				  + 'type="application/x-shockwave-flash" '
				  + 'pluginspage="'
					+ this.protocol()
					+'://www.macromedia.com/go/getflashplayer" />'
				+ '</object>';
		}

		// now write everything out
		objectHTML = '<div id="' + this.id + 'Container" style="' + containerStyle + '"> '
						+ objectHTML
					 + '</div>';
		document.writeln(objectHTML);
	},  
	
	/** Gets the Flash object DOM node. */
	get: function(){
		//return (dojo.render.html.ie) ? window[this.id] : document[this.id];
		
		// more robust way to get Flash object; version above can break
		// communication on IE sometimes
		return document.getElementById(this.id);
	},
	
	/** Sets the visibility of this Flash object. */
	setVisible: function(visible){
		var container = dojo.byId(this.id + "Container");
		if(visible == true){
			container.style.visibility = "visible";
		}else{
			container.style.position = "absolute";
			container.style.x = "-1000px";
			container.style.y = "-1000px";
			container.style.visibility = "hidden";
		}
	},
	
	/** Centers the flash applet on the page. */
	center: function(){
		var elementWidth = this.width;
		var elementHeight = this.height;

		var scroll_offset = dojo.html.getScroll().offset;
		var viewport_size = dojo.html.getViewport();

		// compute the centered position    
		var x = scroll_offset.x + (viewport_size.width - elementWidth) / 2;
		var y = scroll_offset.y + (viewport_size.height - elementHeight) / 2; 

		// set the centered position
		var container = dojo.byId(this.id + "Container");
		container.style.top = y + "px";
		container.style.left = x + "px";
	}
};


/** 
		A class that is used to communicate between Flash and JavaScript in 
		a way that can pass large amounts of data back and forth reliably,
		very fast, and with synchronous method calls. This class encapsulates the 
		specific way in which this communication occurs,
		presenting a common interface to JavaScript irrespective of the underlying
		Flash version.
*/
dojo.flash.Communicator = function(){
	if(dojo.flash.useFlash6()){
		this._writeFlash6();
	}else if (dojo.flash.useFlash8()){
		this._writeFlash8();
	}
}

dojo.flash.Communicator.prototype = {
	_writeFlash6: function(){
		var id = dojo.flash.obj.id;
		
		// global function needed for Flash 6 callback;
		// we write it out as a script tag because the VBScript hook for IE
		// callbacks does not work properly if this function is evalled() from
		// within the Dojo system
		document.writeln('<script language="JavaScript">');
		document.writeln('  function ' + id + '_DoFSCommand(command, args){ ');
		document.writeln('    dojo.flash.comm._handleFSCommand(command, args); ');
		document.writeln('}');
		document.writeln('</script>');
		
		// hook for Internet Explorer to receive FSCommands from Flash
		if(dojo.render.html.ie){
			document.writeln('<SCRIPT LANGUAGE=VBScript\> ');
			document.writeln('on error resume next ');
			document.writeln('Sub ' + id + '_FSCommand(ByVal command, ByVal args)');
			document.writeln(' call ' + id + '_DoFSCommand(command, args)');
			document.writeln('end sub');
			document.writeln('</SCRIPT\> ');
		}
	},
	
	_writeFlash8: function(){
		// nothing needs to be written out for Flash 8 communication; 
		// happens automatically
	},
	
	/** Flash 6 communication. */
	
	/** Handles fscommand's from Flash to JavaScript. Flash 6 communication. */
	_handleFSCommand: function(command, args){
		//dojo.debug("fscommand, command="+command+", args="+args);
		// Flash 8 on Mac/Firefox precedes all commands with the string "FSCommand:";
		// strip it off if it is present
		if(command != null && !dojo.lang.isUndefined(command)
			&& /^FSCommand:(.*)/.test(command) == true){
			command = command.match(/^FSCommand:(.*)/)[1];
		}
		 
		if(command == "addCallback"){ // add Flash method for JavaScript callback
			this._fscommandAddCallback(command, args);
		}else if(command == "call"){ // Flash to JavaScript method call
			this._fscommandCall(command, args);
		}else if(command == "fscommandReady"){ // see if fscommands are ready
			this._fscommandReady();
		}
	},
	
	/** Handles registering a callable Flash function. Flash 6 communication. */
	_fscommandAddCallback: function(command, args){
		var functionName = args;
			
		// do a trick, where we link this function name to our wrapper
		// function, _call, that does the actual JavaScript to Flash call
		var callFunc = function(){
			return dojo.flash.comm._call(functionName, arguments);
		};			
		dojo.flash.comm[functionName] = callFunc;
		
		// indicate that the call was successful
		dojo.flash.obj.get().SetVariable("_succeeded", true);
	},
	
	/** Handles Flash calling a JavaScript function. Flash 6 communication. */
	_fscommandCall: function(command, args){
		var plugin = dojo.flash.obj.get();
		var functionName = args;
		
		// get the number of arguments to this method call and build them up
		var numArgs = parseInt(plugin.GetVariable("_numArgs"));
		var flashArgs = new Array();
		for(var i = 0; i < numArgs; i++){
			var currentArg = plugin.GetVariable("_" + i);
			flashArgs.push(currentArg);
		}
		
		// get the function instance; we technically support more capabilities
		// than ExternalInterface, which can only call global functions; if
		// the method name has a dot in it, such as "dojo.flash.loaded", we
		// eval it so that the method gets run against an instance
		var runMe;
		if(functionName.indexOf(".") == -1){ // global function
			runMe = window[functionName];
		}else{
			// instance function
			runMe = eval(functionName);
		}
		
		// make the call and get the results
		var results = null;
		if(!dojo.lang.isUndefined(runMe) && runMe != null){
			results = runMe.apply(null, flashArgs);
		}
		
		// return the results to flash
		plugin.SetVariable("_returnResult", results);
	},
	
	/** Reports that fscommands are ready to run if executed from Flash. */
	_fscommandReady: function(){
		var plugin = dojo.flash.obj.get();
		plugin.SetVariable("fscommandReady", "true");
	},
	
	/** 
			The actual function that will execute a JavaScript to Flash call; used
			by the Flash 6 communication method. 
	*/
	_call: function(functionName, args){
		// we do JavaScript to Flash method calls by setting a Flash variable
		// "_functionName" with the function name; "_numArgs" with the number
		// of arguments; and "_0", "_1", etc for each numbered argument. Flash
		// reads these, executes the function call, and returns the result
		// in "_returnResult"
		var plugin = dojo.flash.obj.get();
		plugin.SetVariable("_functionName", functionName);
		plugin.SetVariable("_numArgs", args.length);
		for(var i = 0; i < args.length; i++){
			// unlike Flash 8's ExternalInterface, Flash 6 has no problem with
			// any special characters _except_ for the null character \0; double
			// encode this so the Flash side never sees it, but we can get it 
			// back if the value comes back to JavaScript
			var value = args[i];
			value = value.replace(/\0/g, "\\0");
			
			plugin.SetVariable("_" + i, value);
		}
		
		// now tell Flash to execute this method using the Flash Runner
		plugin.TCallLabel("/_flashRunner", "execute");
		
		// get the results
		var results = plugin.GetVariable("_returnResult");
		
		// we double encoded all null characters as //0 because Flash breaks
		// if they are present; turn the //0 back into /0
		results = results.replace(/\\0/g, "\0");
		
		return results;
	},
	
	/** Flash 8 communication. */
	
	/** 
			Registers the existence of a Flash method that we can call with
			JavaScript, using Flash 8's ExternalInterface. 
	*/
	_addExternalInterfaceCallback: function(methodName){
		var wrapperCall = function(){
			// some browsers don't like us changing values in the 'arguments' array, so
			// make a fresh copy of it
			var methodArgs = new Array(arguments.length);
			for(var i = 0; i < arguments.length; i++){
				methodArgs[i] = arguments[i];
			}
			return dojo.flash.comm._execFlash(methodName, methodArgs);
		};
		
		dojo.flash.comm[methodName] = wrapperCall;
	},
	
	/** 
			Encodes our data to get around ExternalInterface bugs.
			Flash 8 communication.
	*/
	_encodeData: function(data){
		// double encode all entity values, or they will be mis-decoded
		// by Flash when returned
		var entityRE = /\&([^;]*)\;/g;
		data = data.replace(entityRE, "&amp;$1;");
		
		// entity encode XML-ish characters, or Flash's broken XML serializer
		// breaks
		data = data.replace(/</g, "&lt;");
		data = data.replace(/>/g, "&gt;");
		
		// transforming \ into \\ doesn't work; just use a custom encoding
		data = data.replace("\\", "&custom_backslash;&custom_backslash;");
		
		data = data.replace(/\n/g, "\\n");
		data = data.replace(/\r/g, "\\r");
		data = data.replace(/\f/g, "\\f");
		data = data.replace(/\0/g, "\\0"); // null character
		data = data.replace(/\'/g, "\\\'");
		data = data.replace(/\"/g, '\\\"');
		
		return data;
	},
	
	/** 
			Decodes our data to get around ExternalInterface bugs.
			Flash 8 communication.
	*/
	_decodeData: function(data){
		if(data == null || typeof data == "undefined"){
			return data;
		}
		
		// certain XMLish characters break Flash's wire serialization for
		// ExternalInterface; these are encoded on the 
		// DojoExternalInterface side into a custom encoding, rather than
		// the standard entity encoding, because otherwise we won't be able to
		// differentiate between our own encoding and any entity characters
		// that are being used in the string itself
		data = data.replace(/\&custom_lt\;/g, "<");
		data = data.replace(/\&custom_gt\;/g, ">");
		
		// Unfortunately, Flash returns us our String with special characters
		// like newlines broken into seperate characters. So if \n represents
		// a new line, Flash returns it as "\" and "n". This means the character
		// is _not_ a newline. This forces us to eval() the string to cause
		// escaped characters to turn into their real special character values.
		data = eval('"' + data + '"');
		
		return data;
	},
	
	/** 
			Sends our method arguments over to Flash in chunks in order to
			have ExternalInterface's performance not be O(n^2).
			Flash 8 communication.
	*/
	_chunkArgumentData: function(value, argIndex){
		var plugin = dojo.flash.obj.get();
		
		// cut up the string into pieces, and push over each piece one
		// at a time
		var numSegments = Math.ceil(value.length / 1024);
		for(var i = 0; i < numSegments; i++){
			var startCut = i * 1024;
			var endCut = i * 1024 + 1024;
			if(i == (numSegments - 1)){
				endCut = i * 1024 + value.length;
			}
			
			var piece = value.substring(startCut, endCut);
			
			// encode each piece seperately, rather than the entire
			// argument data, because ocassionally a special 
			// character, such as an entity like &foobar;, will fall between
			// piece boundaries, and we _don't_ want to encode that value if
			// it falls between boundaries, or else we will end up with incorrect
			// data when we patch the pieces back together on the other side
			piece = this._encodeData(piece);
			
			// directly use the underlying CallFunction method used by
			// ExternalInterface, which is vastly faster for large strings
			// and lets us bypass some Flash serialization bugs
			plugin.CallFunction('<invoke name="chunkArgumentData" '
														+ 'returntype="javascript">'
														+ '<arguments>'
														+ '<string>' + piece + '</string>'
														+ '<number>' + argIndex + '</number>'
														+ '</arguments>'
														+ '</invoke>');
		}
	},
	
	/** 
			Gets our method return data in chunks for better performance.
			Flash 8 communication.
	*/
	_chunkReturnData: function(){
		var plugin = dojo.flash.obj.get();
		
		var numSegments = plugin.getReturnLength();
		var resultsArray = new Array();
		for(var i = 0; i < numSegments; i++){
			// directly use the underlying CallFunction method used by
			// ExternalInterface, which is vastly faster for large strings
			var piece = 
					plugin.CallFunction('<invoke name="chunkReturnData" '
															+ 'returntype="javascript">'
															+ '<arguments>'
															+ '<number>' + i + '</number>'
															+ '</arguments>'
															+ '</invoke>');
															
			// remove any leading or trailing JavaScript delimiters, which surround
			// our String when it comes back from Flash since we bypass Flash's
			// deserialization routines by directly calling CallFunction on the
			// plugin
			if(piece == '""' || piece == "''"){
				piece = "";
			}else{
				piece = piece.substring(1, piece.length-1);
			}
		
			resultsArray.push(piece);
		}
		var results = resultsArray.join("");
		
		return results;
	},
	
	/** 
			Executes a Flash method; called from the JavaScript wrapper proxy we
			create on dojo.flash.comm.
			Flash 8 communication.
	*/
	_execFlash: function(methodName, methodArgs){
		var plugin = dojo.flash.obj.get();
				
		// begin Flash method execution
		plugin.startExec();
		
		// set the number of arguments
		plugin.setNumberArguments(methodArgs.length);
		
		// chunk and send over each argument
		for(var i = 0; i < methodArgs.length; i++){
			this._chunkArgumentData(methodArgs[i], i);
		}
		
		// execute the method
		plugin.exec(methodName);
														
		// get the return result
		var results = this._chunkReturnData();
		
		// decode the results
		results = this._decodeData(results);
		
		// reset everything
		plugin.endExec();
		
		return results;

	}
}

/** 
		Figures out the best way to automatically install the Flash plugin
		for this browser and platform. Also determines if installation or
		revving of the current plugin is needed on this platform.
*/
dojo.flash.Install = function(){
}

dojo.flash.Install.prototype = {
	/** 
			Determines if installation or revving of the current plugin is 
			needed. 
	*/
	needed: function(){
		// do we even have flash?
		if(dojo.flash.info.capable == false){
			return true;
		}

		// are we on the Mac? Safari needs Flash version 8 to do Flash 8
		// communication, while Firefox/Mac needs Flash 8 to fix bugs it has
		// with Flash 6 communication
		if(dojo.render.os.mac == true && !dojo.flash.info.isVersionOrAbove(8, 0, 0)){
			return true;
		}

		// other platforms need at least Flash 6 or above
		if(!dojo.flash.info.isVersionOrAbove(6, 0, 0)){
			return true;
		}

		// otherwise we don't need installation
		return false;
	},

	/** Performs installation or revving of the Flash plugin. */
	install: function(){
		//dojo.debug("install");
		// indicate that we are installing
		dojo.flash.info.installing = true;
		dojo.flash.installing();
		
		if(dojo.flash.info.capable == false){ // we have no Flash at all
			//dojo.debug("Completely new install");
			// write out a simple Flash object to force the browser to prompt
			// the user to install things
			var installObj = new dojo.flash.Embed(false);
			installObj.write(8); // write out HTML for Flash 8 version+
		}else if(dojo.flash.info.isVersionOrAbove(6, 0, 65)){ // Express Install
			//dojo.debug("Express install");
			var installObj = new dojo.flash.Embed(false);
			installObj.write(8, true); // write out HTML for Flash 8 version+
			installObj.setVisible(true);
			installObj.center();
		}else{ // older Flash install than version 6r65
			alert("This content requires a more recent version of the Macromedia "
						+" Flash Player.");
			window.location.href = + dojo.flash.Embed.protocol() +
						"://www.macromedia.com/go/getflashplayer";
		}
	},
	
	/** 
			Called when the Express Install is either finished, failed, or was
			rejected by the user.
	*/
	_onInstallStatus: function(msg){
		if (msg == "Download.Complete"){
			// Installation is complete.
			dojo.flash._initialize();
		}else if(msg == "Download.Cancelled"){
			alert("This content requires a more recent version of the Macromedia "
						+" Flash Player.");
			window.location.href = dojo.flash.Embed.protocol() +
						"://www.macromedia.com/go/getflashplayer";
		}else if (msg == "Download.Failed"){
			// The end user failed to download the installer due to a network failure
			alert("There was an error downloading the Flash Player update. "
						+ "Please try again later, or visit macromedia.com to download "
						+ "the latest version of the Flash plugin.");
		}	
	}
}

// find out if Flash is installed
dojo.flash.info = new dojo.flash.Info();

// vim:ts=4:noet:tw=0:

__CPAN_DIR__ src/rpc
__CPAN_FILE__ src/rpc/Deferred.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.rpc.Deferred");
dojo.require("dojo.Deferred");

dojo.deprecated("dojo.rpc.Deferred", "replaced by dojo.Deferred", "0.6");
dojo.rpc.Deferred = dojo.Deferred;
dojo.rpc.Deferred.prototype = dojo.Deferred.prototype;

__CPAN_FILE__ src/rpc/YahooService.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.rpc.YahooService");
dojo.require("dojo.rpc.RpcService");
dojo.require("dojo.rpc.JsonService");
dojo.require("dojo.json");
dojo.require("dojo.uri.*");
dojo.require("dojo.io.ScriptSrcIO");

dojo.rpc.YahooService = function(appId){
	this.appId = appId;
	if(!appId){
		this.appId = "dojotoolkit";
		dojo.debug(	"please initialize the YahooService class with your own",
					"application ID. Using the default may cause problems during",
					"deployment of your application");
	}
	this.connect(dojo.uri.dojoUri("src/rpc/yahoo.smd"));
	this.strictArgChecks = false;
}

dojo.inherits(dojo.rpc.YahooService, dojo.rpc.JsonService);

dojo.lang.extend(dojo.rpc.YahooService, {
	strictArgChecks: false,

	bind: function(method, parameters, deferredRequestHandler, url){
		//summary
		//Yahoo RPC bind method. Takes remote method, parameters, deferred,
		//and a url and sends of a ScriptSrcIO request to connect to Yahoo
		//services crossplatform
		var params = parameters;
		if(	(dojo.lang.isArrayLike(parameters))&&
			(parameters.length == 1)){
			params = parameters[0];
		}
		params.output = "json";
		params.appid= this.appId;
		dojo.io.bind({
			url: url||this.serviceUrl,
			transport: "ScriptSrcTransport",
			// FIXME: need to get content interpolation fixed
			content: params,
			jsonParamName: "callback",
			mimetype: "text/json",
			load: this.resultCallback(deferredRequestHandler),
			error: this.errorCallback(deferredRequestHandler),
			preventCache: true
		});
	}
});

__CPAN_FILE__ src/rpc/yahoo.smd
{
	"SMDVersion":".1",
	"objectName":"yahoo",
	"serviceType":"JSON-P",
	"methods":[
		//
		// MAPS 
		//
		{
			// http://developer.yahoo.com/maps/rest/V1/mapImage.html
			"name":"mapImage",
			"serviceURL": "http://api.local.yahoo.com/MapsService/V1/mapImage",
			"parameters":[
				{ "name":"street", "type":"STRING" },
				{ "name":"city", "type":"STRING" },
				{ "name":"zip", "type":"INTEGER" },
				{ "name":"location", "type":"STRING" },
				{ "name":"longitude", "type":"FLOAT" },
				{ "name":"latitude", "type":"FLOAT" },
				{ "name":"image_type", "type":"STRING" },
				{ "name":"image_width", "type":"INTEGER" },
				{ "name":"image_height", "type":"INTEGER" },
				{ "name":"zoom", "type":"INTEGER" },
				{ "name":"radius", "type":"INTEGER" }
			]
		},
		{
			// http://developer.yahoo.com/traffic/rest/V1/index.html
			"name":"trafficData",
			"serviceURL": "http://api.local.yahoo.com/MapsService/V1/trafficData",
			"parameters":[
				{ "name":"street", "type":"STRING" },
				{ "name":"city", "type":"STRING" },
				{ "name":"zip", "type":"INTEGER" },
				{ "name":"location", "type":"STRING" },
				{ "name":"longitude", "type":"FLOAT" },
				{ "name":"latitude", "type":"FLOAT" },
				{ "name":"severity", "type":"INTEGER" },
				{ "name":"include_map", "type":"INTEGER" },
				{ "name":"image_type", "type":"STRING" },
				{ "name":"image_width", "type":"INTEGER" },
				{ "name":"image_height", "type":"INTEGER" },
				{ "name":"zoom", "type":"INTEGER" },
				{ "name":"radius", "type":"INTEGER" }
			]
		},
		/*
			// Yahoo's geocoding service is f'd for JSON and Y! advises that it
			// may not be returning
		{
			// http://developer.yahoo.com/maps/rest/V1/geocode.html
			"name":"geocode",
			"serviceURL": "http://api.local.yahoo.com/MapsService/V1/geocode",
			"parameters":[
				{ "name":"street", "type":"STRING" },
				{ "name":"city", "type":"STRING" },
				{ "name":"zip", "type":"INTEGER" },
				{ "name":"location", "type":"STRING" }
			]
		},
		*/
		//
		// LOCAL SEARCH
		//
		{
			// http://developer.yahoo.com/search/local/V3/localSearch.html
			"name":"localSearch",
			"serviceURL": "http://api.local.yahoo.com/LocalSearchService/V3/localSearch",
			"parameters":[
				{ "name":"street", "type":"STRING" },
				{ "name":"city", "type":"STRING" },
				{ "name":"zip", "type":"INTEGER" },
				{ "name":"location", "type":"STRING" },
				{ "name":"listing_id", "type":"STRING" },
				{ "name":"sort", "type":"STRING" }, // "relevence", "title", "distance", or "rating"
				{ "name":"start", "type":"INTEGER" },
				{ "name":"radius", "type":"FLOAT" },
				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
				{ "name":"longitude", "type":"FLOAT" },
				{ "name":"latitude", "type":"FLOAT" },
				{ "name":"category", "type":"INTEGER" },
				{ "name":"omit_category", "type":"INTEGER" },
				{ "name":"minimum_rating", "type":"INTEGER" }
			]
		},
		//
		// WEB SEARCH
		//

		// NOTE: contextual search and term extraction are not stubbed out
		// becaues I'm not sure if we can POST via script src inclusion method
		{
			// http://developer.yahoo.com/search/web/V1/webSearch.html 
			"name":"webSearch",
			"serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/webSearch",
			"parameters":[
				{ "name":"query", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // defaults to "all"
				{ "name":"region", "type":"STRING" }, // defaults to "us"
				{ "name":"results", "type":"INTEGER" }, // defaults to 10
				{ "name":"start", "type":"INTEGER" }, // defaults to 1
				{ "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls"
				{ "name":"adult_ok", "type":"INTEGER" }, // defaults to null
				{ "name":"similar_ok", "type":"INTEGER" }, // defaults to null
				{ "name":"language", "type":"STRING" }, // defaults to null
				{ "name":"country", "type":"STRING" }, // defaults to null
				{ "name":"site", "type":"STRING" }, // defaults to null
				{ "name":"subscription", "type":"STRING" }, // defaults to null
				{ "name":"license", "type":"STRING" } // defaults to "any"
			]
		},
		{
			// http://developer.yahoo.com/search/web/V1/spellingSuggestion.html
			"name":"spellingSuggestion",
			"serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/spellingSuggestion",
			"parameters":[ { "name":"query", "type":"STRING" } ]
		},
		{
			// http://developer.yahoo.com/search/web/V1/relatedSuggestion.html
			"name":"spellingSuggestion",
			"serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/relatedSuggestion",
			"parameters":[
				{ "name":"query", "type":"STRING" },
				{ "name":"results", "type":"INTEGER" } // 1-50, defaults to 10
			]
		},
		//
		// IMAGE SEARCH
		//
		{
			// http://developer.yahoo.com/search/image/V1/imageSearch.html
			"name":"imageSearch",
			"serviceURL": "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch",
			"parameters":[
				{ "name":"query", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
				{ "name":"results", "type":"INTEGER" }, // defaults to 10
				{ "name":"start", "type":"INTEGER" }, // defaults to 1
				{ "name":"format", "type":"STRING" }, // defaults to "any", can be "bmp", "gif", "jpeg", or "png"
				{ "name":"adult_ok", "type":"INTEGER" }, // defaults to null
				{ "name":"coloration", "type":"STRING" }, // "any", "color", or "bw"
				{ "name":"site", "type":"STRING" } // defaults to null
			]
		},
		//
		// SITE EXPLORER
		//
		{
			// http://developer.yahoo.com/search/siteexplorer/V1/inlinkData.html 
			"name":"inlinkData",
			"serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/inlinkData",
			"parameters":[
				{ "name":"query", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
				{ "name":"entire_site", "type":"INTEGER" }, // defaults to null
				{ "name":"omit_inlinks", "type":"STRING" }, // "domain" or "subdomain", defaults to null
				{ "name":"results", "type":"INTEGER" }, // defaults to 50
				{ "name":"start", "type":"INTEGER" }, // defaults to 1
				{ "name":"site", "type":"STRING" } // defaults to null
			]
		},
		{
			// http://developer.yahoo.com/search/siteexplorer/V1/pageData.html
			"name":"pageData",
			"serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/pageData",
			"parameters":[
				{ "name":"query", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
				{ "name":"domain_only", "type":"INTEGER" }, // defaults to null
				{ "name":"results", "type":"INTEGER" }, // defaults to 50
				{ "name":"start", "type":"INTEGER" }, // defaults to 1
				{ "name":"site", "type":"STRING" } // defaults to null
			]
		},
		//
		// MUSIC SEARCH
		//
		{
			// http://developer.yahoo.com/search/audio/V1/artistSearch.html
			"name":"artistSearch",
			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/artistSearch",
			"parameters":[
				{ "name":"artist", "type":"STRING" },
				{ "name":"artistid", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
				{ "name":"start", "type":"INTEGER" } // defaults to 1
			]
		},
		{
			// http://developer.yahoo.com/search/audio/V1/albumSearch.html
			"name":"albumSearch",
			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/albumSearch",
			"parameters":[
				{ "name":"artist", "type":"STRING" },
				{ "name":"artistid", "type":"STRING" },
				{ "name":"album", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
				{ "name":"start", "type":"INTEGER" } // defaults to 1
			]
		},
		{
			// http://developer.yahoo.com/search/audio/V1/songSearch.html
			"name":"songSearch",
			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songSearch",
			"parameters":[
				{ "name":"artist", "type":"STRING" },
				{ "name":"artistid", "type":"STRING" },
				{ "name":"album", "type":"STRING" },
				{ "name":"albumid", "type":"STRING" },
				{ "name":"song", "type":"STRING" },
				{ "name":"songid", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
				{ "name":"start", "type":"INTEGER" } // defaults to 1
			]
		},
		{
			// http://developer.yahoo.com/search/audio/V1/songDownloadLocation.html
			"name":"songDownloadLocation",
			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songDownloadLocation",
			"parameters":[
				{ "name":"songid", "type":"STRING" },
				// "source" can contain:
				//	audiolunchbox artistdirect buymusic dmusic
				//	emusic epitonic garageband itunes yahoo
				//	livedownloads mp34u msn musicmatch mapster passalong
				//	rhapsody soundclick theweb
				{ "name":"source", "type":"STRING" },
				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
				{ "name":"start", "type":"INTEGER" } // defaults to 1
			]
		},
		//
		// NEWS SEARCH
		//
		{
			// http://developer.yahoo.com/search/news/V1/newsSearch.html
			"name":"newsSearch",
			"serviceURL": "http://api.search.yahoo.com/NewsSearchService/V1/newsSearch",
			"parameters":[
				{ "name":"query", "type":"STRING" },
				{ "name":"type", "type":"STRING" }, // defaults to "all"
				{ "name":"results", "type":"INTEGER" }, // defaults to 10
				{ "name":"start", "type":"INTEGER" }, // defaults to 1
				{ "name":"sort", "type":"STRING" }, // "rank" or "date"
				{ "name":"language", "type":"STRING" }, // defaults to null
				{ "name":"site", "type":"STRING" } // defaults to null
			]
		}
		/*
		{
			// 
			"name":"",
			"serviceURL": "",
			"parameters":[
				{ "name":"street", "type":"STRING" },
			]
		}
		*/
	]
}

__CPAN_FILE__ src/rpc/RpcService.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.rpc.RpcService");
dojo.require("dojo.io.*");
dojo.require("dojo.json");
dojo.require("dojo.lang.func");
dojo.require("dojo.Deferred");

dojo.rpc.RpcService = function(url){
	// summary
	// constructor for rpc base class
	if(url){
		this.connect(url);
	}
}

dojo.lang.extend(dojo.rpc.RpcService, {

	strictArgChecks: true,
	serviceUrl: "",

	parseResults: function(obj){
		// summary
		// parse the results coming back from an rpc request.  
   		// this base implementation, just returns the full object
		// subclasses should parse and only return the actual results
		return obj;
	},

	errorCallback: function(/* dojo.Deferred */ deferredRequestHandler){
		// summary
		// create callback that calls the Deferres errback method
		return function(type, e){
			deferredRequestHandler.errback(new Error(e.message));
		}
	},

	resultCallback: function(/* dojo.Deferred */ deferredRequestHandler){
		// summary
		// create callback that calls the Deferred's callback method
		var tf = dojo.lang.hitch(this, 
			function(type, obj, e){
				if (obj["error"]!=null) {
					var err = new Error(obj.error);
					err.id = obj.id;
					deferredRequestHandler.errback(err);
				} else {
					var results = this.parseResults(obj);
					deferredRequestHandler.callback(results); 
				}
			}
		);
		return tf;
	},


	generateMethod: function(/*string*/ method, /*array*/ parameters, /*string*/ url){
		// summary
		// generate the local bind methods for the remote object
		return dojo.lang.hitch(this, function(){
			var deferredRequestHandler = new dojo.Deferred();

			// if params weren't specified, then we can assume it's varargs
			if( (this.strictArgChecks) &&
				(parameters != null) &&
				(arguments.length != parameters.length)
			){
				// put error stuff here, no enough params
				dojo.raise("Invalid number of parameters for remote method.");
			} else {
				this.bind(method, arguments, deferredRequestHandler, url);
			}

			return deferredRequestHandler;
		});
	},

	processSmd: function(/*json*/ object){
		// summary
		// callback method for reciept of a smd object.  Parse the smd and
		// generate functions based on the description
		dojo.debug("RpcService: Processing returned SMD.");
		if(object.methods){
			dojo.lang.forEach(object.methods, function(m){
				if(m && m["name"]){
					dojo.debug("RpcService: Creating Method: this.", m.name, "()");
					this[m.name] = this.generateMethod(	m.name,
														m.parameters, 
														m["url"]||m["serviceUrl"]||m["serviceURL"]);
					if(dojo.lang.isFunction(this[m.name])){
						dojo.debug("RpcService: Successfully created", m.name, "()");
					}else{
						dojo.debug("RpcService: Failed to create", m.name, "()");
					}
				}
			}, this);
		}

		this.serviceUrl = object.serviceUrl||object.serviceURL;
		dojo.debug("RpcService: Dojo RpcService is ready for use.");
	},

	connect: function(/*String*/ smdUrl){
		// summary
		// connect to a remote url and retrieve a smd object
		dojo.debug("RpcService: Attempting to load SMD document from:", smdUrl);
		dojo.io.bind({
			url: smdUrl,
			mimetype: "text/json",
			load: dojo.lang.hitch(this, function(type, object, e){ return this.processSmd(object); }),
			sync: true
		});		
	}
});

__CPAN_FILE__ src/rpc/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [["dojo.rpc.JsonService", false, false]]
});
dojo.provide("dojo.rpc.*");

__CPAN_FILE__ src/rpc/JotService.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.rpc.JotService");
dojo.require("dojo.rpc.RpcService"); dojo.require("dojo.rpc.JsonService"); dojo.require("dojo.json"); dojo.rpc.JotService = function(){
	this.serviceUrl = "/_/jsonrpc";
}

dojo.inherits(dojo.rpc.JotService, dojo.rpc.JsonService);

dojo.lang.extend(dojo.rpc.JotService, {
	bind: function(method, parameters, deferredRequestHandler, url){
		//summary
		//Jot bind method. Takes remote method, parameters, deferred,
		//and a url, calls createRequest to make a Jot RPC envelope and
		//passes that off with bind.  
		dojo.io.bind({
			url: url||this.serviceUrl,
			content: {
				json: this.createRequest(method, parameters)
			},
			method: "POST",
			mimetype: "text/json",
			load: this.resultCallback(deferredRequestHandler),
			error: this.errorCallback(deferredRequestHandler),
			preventCache: true
		});
	},

	createRequest: function(method, params){
		//summary
		//create the json portion of the Jot request
		var req = { "params": params, "method": method, "id": this.lastSubmissionId++ };
		return dojo.json.serialize(req);
	}
});

__CPAN_FILE__ src/rpc/JsonService.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.rpc.JsonService");
dojo.require("dojo.rpc.RpcService");
dojo.require("dojo.io.*");
dojo.require("dojo.json");
dojo.require("dojo.lang.common");

dojo.rpc.JsonService = function(args){
	// passing just the URL isn't terribly useful. It's expected that at
	// various times folks will want to specify:
	//	- just the serviceUrl (for use w/ remoteCall())
	//	- the text of the SMD to evaluate
	// 	- a raw SMD object
	//	- the SMD URL
	if(args){
		if(dojo.lang.isString(args)){
			// we assume it's an SMD file to be processed, since this was the
			// earlier function signature

			// FIXME: also accept dojo.uri.Uri objects?
			this.connect(args);
		}else{
			// otherwise we assume it's an arguments object with the following
			// (optional) properties:
			//	- serviceUrl
			//	- strictArgChecks
			//	- smdUrl
			//	- smdStr
			//	- smdObj
			if(args["smdUrl"]){
				this.connect(args.smdUrl);
			}
			if(args["smdStr"]){
				this.processSmd(dj_eval("("+args.smdStr+")"));
			}
			if(args["smdObj"]){
				this.processSmd(args.smdObj);
			}
			if(args["serviceUrl"]){
				this.serviceUrl = args.serviceUrl;
			}
			if(typeof args["strictArgChecks"] != "undefined"){
				this.strictArgChecks = args.strictArgChecks;
			}
		}
	}
}

dojo.inherits(dojo.rpc.JsonService, dojo.rpc.RpcService);

dojo.extend(dojo.rpc.JsonService, {

	bustCache: false,
	
	contentType: "application/json-rpc",

	lastSubmissionId: 0,

	callRemote: function(method, params){
		//summary
		// call an arbitrary remote method without requiring it
		// to be predefined with SMD
		var deferred = new dojo.Deferred();
		this.bind(method, params, deferred);
		return deferred;
	},

	bind: function(method, parameters, deferredRequestHandler, url){
		//summary
		//JSON-RPC bind method. Takes remote method, parameters, deferred,
		//and a url, calls createRequest to make a JSON-RPC envelope and
		//passes that off with bind.

		dojo.io.bind({
			url: url||this.serviceUrl,
			postContent: this.createRequest(method, parameters),
			method: "POST",
			contentType: this.contentType,
			mimetype: "text/json",
			load: this.resultCallback(deferredRequestHandler),
			error: this.errorCallback(deferredRequestHandler),
			preventCache:this.bustCache 
		});
	},

	createRequest: function(method, params){
		//summary
		//create a JSON-RPC envelope for the request
		var req = { "params": params, "method": method, "id": ++this.lastSubmissionId };
		var data = dojo.json.serialize(req);
		dojo.debug("JsonService: JSON-RPC Request: " + data);
		return data;
	},

	parseResults: function(obj){
		//summary
		//parse the result envelope and pass the results back to 
		// to the callback function
		if(!obj){ return; }
		if (obj["Result"]!=null){ 
			return obj["Result"]; 
		}else if(obj["result"]!=null){ 
			return obj["result"]; 
		}else if(obj["ResultSet"]){
			return obj["ResultSet"];
		}else{
			return obj;
		}
	}
});

__CPAN_DIR__ src/validate
__CPAN_FILE__ src/validate/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.common");

dojo.require("dojo.regexp");


dojo.validate.isText = function(/*String*/value, /*Object?*/flags){
// summary:
//	Checks if a string has non whitespace characters. 
//	Parameters allow you to constrain the length.
//
// value: A string
// flags: {length: Number, minlength: Number, maxlength: Number}
//    flags.length  If set, checks if there are exactly flags.length number of characters.
//    flags.minlength  If set, checks if there are at least flags.minlength number of characters.
//    flags.maxlength  If set, checks if there are at most flags.maxlength number of characters.

	flags = (typeof flags == "object") ? flags : {};

	// test for text
	if(/^\s*$/.test(value)){ return false; } // Boolean

	// length tests
	if(typeof flags.length == "number" && flags.length != value.length){ return false; } // Boolean
	if(typeof flags.minlength == "number" && flags.minlength > value.length){ return false; } // Boolean
	if(typeof flags.maxlength == "number" && flags.maxlength < value.length){ return false; } // Boolean

	return true; // Boolean
}

dojo.validate.isInteger = function(/*String*/value, /*Object?*/flags){
// summary:
//	Validates whether a string is in an integer format
//
// value  A string
// flags  {signed: Boolean|[true,false], separator: String}
//    flags.signed  The leading plus-or-minus sign.  Can be true, false, or [true, false].
//      Default is [true, false], (i.e. sign is optional).
//    flags.separator  The character used as the thousands separator.  Default is no separator.
//      For more than one symbol use an array, e.g. [",", ""], makes ',' optional.

	var re = new RegExp("^" + dojo.regexp.integer(flags) + "$");
	return re.test(value); // Boolean
}

dojo.validate.isRealNumber = function(/*String*/value, /*Object?*/flags){
// summary:
//	Validates whether a string is a real valued number. 
//	Format is the usual exponential notation.
//
// value: A string
// flags: {places: Number, decimal: String, exponent: Boolean|[true,false], eSigned: Boolean|[true,false], ...}
//    flags.places  The integer number of decimal places.
//      If not given, the decimal part is optional and the number of places is unlimited.
//    flags.decimal  The character used for the decimal point.  Default is ".".
//    flags.exponent  Express in exponential notation.  Can be true, false, or [true, false].
//      Default is [true, false], (i.e. the exponential part is optional).
//    flags.eSigned  The leading plus-or-minus sign on the exponent.  Can be true, false, 
//      or [true, false].  Default is [true, false], (i.e. sign is optional).
//    flags in regexp.integer can be applied.

	var re = new RegExp("^" + dojo.regexp.realNumber(flags) + "$");
	return re.test(value); // Boolean
}

dojo.validate.isCurrency = function(/*String*/value, /*Object?*/flags){
// summary:
//	Validates whether a string denotes a monetary value. 
// value: A string
// flags: {signed:Boolean|[true,false], symbol:String, placement:String, separator:String,
//	fractional:Boolean|[true,false], decimal:String}
//    flags.signed  The leading plus-or-minus sign.  Can be true, false, or [true, false].
//      Default is [true, false], (i.e. sign is optional).
//    flags.symbol  A currency symbol such as Yen "ï¿½", Pound "ï¿½", or the Euro sign "ï¿½".  
//      Default is "$".  For more than one symbol use an array, e.g. ["$", ""], makes $ optional.
//    flags.placement  The symbol can come "before" the number or "after".  Default is "before".
//    flags.separator  The character used as the thousands separator. The default is ",".
//    flags.fractional  The appropriate number of decimal places for fractional currency (e.g. cents)
//      Can be true, false, or [true, false].  Default is [true, false], (i.e. cents are optional).
//    flags.decimal  The character used for the decimal point.  Default is ".".

	var re = new RegExp("^" + dojo.regexp.currency(flags) + "$");
	return re.test(value); // Boolean
}

dojo.validate.isInRange = function(/*String*/value, /*Object?*/flags){
//summary:
//	Validates whether a string denoting an integer, 
//	real number, or monetary value is between a max and min. 
//
// value: A string
// flags: {max:Number, min:Number, decimal:String}
//    flags.max  A number, which the value must be less than or equal to for the validation to be true.
//    flags.min  A number, which the value must be greater than or equal to for the validation to be true.
//    flags.decimal  The character used for the decimal point.  Default is ".".

	//stripping the seperator allows NaN to perform as expected, if no separator, we assume ','
	//once i18n support is ready for this, instead of assuming, we default to i18n's recommended value
	value = value.replace((dojo.lang.has(flags,'separator'))?flags.separator:',','');
	if(isNaN(value)){
		return false; // Boolean
	}
	// assign default values to missing paramters
	flags = (typeof flags == "object") ? flags : {};
	var max = (typeof flags.max == "number") ? flags.max : Infinity;
	var min = (typeof flags.min == "number") ? flags.min : -Infinity;
	var dec = (typeof flags.decimal == "string") ? flags.decimal : ".";
	
	// splice out anything not part of a number
	var pattern = "[^" + dec + "\\deE+-]";
	value = value.replace(RegExp(pattern, "g"), "");

	// trim ends of things like e, E, or the decimal character
	value = value.replace(/^([+-]?)(\D*)/, "$1");
	value = value.replace(/(\D*)$/, "");

	// replace decimal with ".". The minus sign '-' could be the decimal!
	pattern = "(\\d)[" + dec + "](\\d)";
	value = value.replace(RegExp(pattern, "g"), "$1.$2");

	value = Number(value);
	if ( value < min || value > max ) { return false; } // Boolean

	return true; // Boolean
}

dojo.validate.isNumberFormat = function(/*String*/value, /*Object?*/flags){
// summary:
//	Validates any sort of number based format
//
// description:
//	Use it for phone numbers, social security numbers, zip-codes, etc.
//	The value can be validated against one format or one of multiple formats.
//
//  Format
//    #        Stands for a digit, 0-9.
//    ?        Stands for an optional digit, 0-9 or nothing.
//    All other characters must appear literally in the expression.
//
//  Example   
//    "(###) ###-####"       ->   (510) 542-9742
//    "(###) ###-#### x#???" ->   (510) 542-9742 x153
//    "###-##-####"          ->   506-82-1089       i.e. social security number
//    "#####-####"           ->   98225-1649        i.e. zip code
//
// value: A string
// flags: {format:String}
//    flags.format  A string or an Array of strings for multiple formats.

	var re = new RegExp("^" + dojo.regexp.numberFormat(flags) + "$", "i");
	return re.test(value); // Boolean
}

dojo.validate.isValidLuhn = function(/*String*/value){
//summary: Compares value against the Luhn algorithm to verify its integrity
	var sum, parity, curDigit;
	if(typeof value!='string'){
		value = String(value);
	}
	value = value.replace(/[- ]/g,''); //ignore dashes and whitespaces
	parity = value.length%2;
	sum=0;
	for(var i=0;i<value.length;i++){
		curDigit = parseInt(value.charAt(i));
		if(i%2==parity){
			curDigit*=2;
		}
		if(curDigit>9){
			curDigit-=9;
		}
		sum+=curDigit;
	}
	return !(sum%10);
}

/**
	Procedural API Description

		The main aim is to make input validation expressible in a simple format.
		You define profiles which declare the required and optional fields and any constraints they might have.
		The results are provided as an object that makes it easy to handle missing and invalid input.

	Usage

		var results = dojo.validate.check(form, profile);

	Profile Object

		var profile = {
			// filters change the field value and are applied before validation.
			trim: ["tx1", "tx2"],
			uppercase: ["tx9"],
			lowercase: ["tx5", "tx6", "tx7"],
			ucfirst: ["tx10"],
			digit: ["tx11"],

			// required input fields that are blank will be reported missing.
			// required radio button groups and drop-down lists with no selection will be reported missing.
			// checkbox groups and selectboxes can be required to have more than one value selected.
			// List required fields by name and use this notation to require more than one value: {checkboxgroup: 2}, {selectboxname: 3}.
			required: ["tx7", "tx8", "pw1", "ta1", "rb1", "rb2", "cb3", "s1", {"doubledip":2}, {"tripledip":3}],

			// dependant/conditional fields are required if the target field is present and not blank.
			// At present only textbox, password, and textarea fields are supported.
			dependencies:	{
				cc_exp: "cc_no",	
				cc_type: "cc_no",	
			},

			// Fields can be validated using any boolean valued function.  
			// Use arrays to specify parameters in addition to the field value.
			constraints: {
				field_name1: myValidationFunction,
				field_name2: dojo.validate.isInteger,
				field_name3: [myValidationFunction, additional parameters],
				field_name4: [dojo.validate.isValidDate, "YYYY.MM.DD"],
				field_name5: [dojo.validate.isEmailAddress, false, true],
			},

			// Confirm is a sort of conditional validation.
			// It associates each field in its property list with another field whose value should be equal.
			// If the values are not equal, the field in the property list is reported as Invalid. Unless the target field is blank.
			confirm: {
				email_confirm: "email",	
				pw2: "pw1",	
			}
		};

	Results Object

		isSuccessful(): Returns true if there were no invalid or missing fields, else it returns false.
		hasMissing():  Returns true if the results contain any missing fields.
		getMissing():  Returns a list of required fields that have values missing.
		isMissing(field):  Returns true if the field is required and the value is missing.
		hasInvalid():  Returns true if the results contain fields with invalid data.
		getInvalid():  Returns a list of fields that have invalid values.
		isInvalid(field):  Returns true if the field has an invalid value.

*/

__CPAN_FILE__ src/validate/us.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.us");
dojo.require("dojo.validate.common");

dojo.validate.us.isCurrency = function(/*String*/value, /*Object?*/flags){
	// summary: Validates U.S. currency
	// value: the representation to check
	// flags: flags in validate.isCurrency can be applied.
	return dojo.validate.isCurrency(value, flags); // Boolean
}


dojo.validate.us.isState = function(/*String*/value, /*Object?*/flags){
	// summary: Validates US state and territory abbreviations.
	//
	// value: A two character string
	// flags: An object
	//    flags.allowTerritories  Allow Guam, Puerto Rico, etc.  Default is true.
	//    flags.allowMilitary  Allow military 'states', e.g. Armed Forces Europe (AE).  Default is true.

	var re = new RegExp("^" + dojo.regexp.us.state(flags) + "$", "i");
	return re.test(value); // Boolean
}

dojo.validate.us.isPhoneNumber = function(/*String*/value){
	// summary: Validates 10 US digit phone number for several common formats
	// value: The telephone number string

	var flags = {
		format: [
			"###-###-####",
			"(###) ###-####",
			"(###) ### ####",
			"###.###.####",
			"###/###-####",
			"### ### ####",
			"###-###-#### x#???",
			"(###) ###-#### x#???",
			"(###) ### #### x#???",
			"###.###.#### x#???",
			"###/###-#### x#???",
			"### ### #### x#???",
			"##########"
		]
	};

	return dojo.validate.isNumberFormat(value, flags); // Boolean
}

dojo.validate.us.isSocialSecurityNumber = function(/*String*/value){
// summary: Validates social security number
	var flags = {
		format: [
			"###-##-####",
			"### ## ####",
			"#########"
		]
	};

	return dojo.validate.isNumberFormat(value, flags); // Boolean
}

dojo.validate.us.isZipCode = function(/*String*/value){
// summary: Validates U.S. zip-code
	var flags = {
		format: [
			"#####-####",
			"##### ####",
			"#########",
			"#####"
		]
	};

	return dojo.validate.isNumberFormat(value, flags); // Boolean
}

__CPAN_FILE__ src/validate/de.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.de");
dojo.require("dojo.validate.common");

dojo.validate.isGermanCurrency = function(/*String*/value) {
	//summary: checks to see if 'value' is a valid representation of German currency (Euros)
	var flags = {
		symbol: "\u20AC",
		placement: "after",
		signPlacement: "begin", //TODO: this is really locale-dependent.  Will get fixed in v0.5 currency rewrite. 
		decimal: ",",
		separator: "."
	};
	return dojo.validate.isCurrency(value, flags); // Boolean
}



__CPAN_FILE__ src/validate/jp.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.jp");
dojo.require("dojo.validate.common");

dojo.validate.isJapaneseCurrency = function(/*String*/value) {
	//summary: checks to see if 'value' is a valid representation of Japanese currency
	var flags = {
		symbol: "\u00a5",
		fractional: false
	};
	return dojo.validate.isCurrency(value, flags); // Boolean
}



__CPAN_FILE__ src/validate/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.validate");
dojo.kwCompoundRequire({
	common:		["dojo.validate.check", 
						"dojo.validate.datetime", 
						"dojo.validate.de", 
						"dojo.validate.jp", 
						"dojo.validate.us", 
						"dojo.validate.web" 
	]
});
dojo.provide("dojo.validate.*");

__CPAN_FILE__ src/validate/datetime.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.datetime");
dojo.require("dojo.validate.common");

/**
  Validates a time value in any International format.
  The value can be validated against one format or one of multiple formats.

  Format
  h        12 hour, no zero padding.
  hh       12 hour, has leading zero.
  H        24 hour, no zero padding.
  HH       24 hour, has leading zero.
  m        minutes, no zero padding.
  mm       minutes, has leading zero.
  s        seconds, no zero padding.
  ss       seconds, has leading zero.
  All other characters must appear literally in the expression.

  Example
    "h:m:s t"  ->   2:5:33 PM
    "HH:mm:ss" ->  14:05:33

  @param value  A string.
  @param flags  An object.
    flags.format  A string or an array of strings.  Default is "h:mm:ss t".
    flags.amSymbol  The symbol used for AM.  Default is "AM".
    flags.pmSymbol  The symbol used for PM.  Default is "PM".
  @return  true or false
*/
dojo.validate.isValidTime = function(value, flags) {
	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
	var re = new RegExp("^" + dojo.regexp.time(flags) + "$", "i");
	return re.test(value);
}

/**
  Validates 12-hour time format.
  Zero-padding is not allowed for hours, required for minutes and seconds.
  Seconds are optional.

  @param value  A string.
  @return  true or false
*/
dojo.validate.is12HourTime = function(value) {
	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
	return dojo.validate.isValidTime(value, {format: ["h:mm:ss t", "h:mm t"]});
}

/**
  Validates 24-hour military time format.
  Zero-padding is required for hours, minutes, and seconds.
  Seconds are optional.

  @param value  A string.
  @return  true or false
*/
dojo.validate.is24HourTime = function(value) {
	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
	return dojo.validate.isValidTime(value, {format: ["HH:mm:ss", "HH:mm"]} );
}

/**
  Returns true if the date conforms to the format given and is a valid date. Otherwise returns false.

  @param dateValue  A string for the date.
  @param format  A string, default is  "MM/DD/YYYY".
  @return  true or false

  Accepts any type of format, including ISO8601.
  All characters in the format string are treated literally except the following tokens:

  YYYY - matches a 4 digit year
  M - matches a non zero-padded month
  MM - matches a zero-padded month
  D -  matches a non zero-padded date
  DD -  matches a zero-padded date
  DDD -  matches an ordinal date, 001-365, and 366 on leapyear
  ww - matches week of year, 01-53
  d - matches day of week, 1-7

  Examples: These are all today's date.

  Date          Format
  2005-W42-3    YYYY-Www-d
  2005-292      YYYY-DDD
  20051019      YYYYMMDD
  10/19/2005    M/D/YYYY
  19.10.2005    D.M.YYYY
*/
dojo.validate.isValidDate = function(dateValue, format) {
	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
	// Default is the American format
	if (typeof format == "object" && typeof format.format == "string"){ format = format.format; }
	if (typeof format != "string") { format = "MM/DD/YYYY"; }

	// Create a literal regular expression based on format
	var reLiteral = format.replace(/([$^.*+?=!:|\/\\\(\)\[\]\{\}])/g, "\\$1");

	// Convert all the tokens to RE elements
	reLiteral = reLiteral.replace( "YYYY", "([0-9]{4})" );
	reLiteral = reLiteral.replace( "MM", "(0[1-9]|10|11|12)" );
	reLiteral = reLiteral.replace( "M", "([1-9]|10|11|12)" );
	reLiteral = reLiteral.replace( "DDD", "(00[1-9]|0[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6])" );
	reLiteral = reLiteral.replace( "DD", "(0[1-9]|[12][0-9]|30|31)" );
	reLiteral = reLiteral.replace( "D", "([1-9]|[12][0-9]|30|31)" );
	reLiteral = reLiteral.replace( "ww", "(0[1-9]|[1-4][0-9]|5[0-3])" );
	reLiteral = reLiteral.replace( "d", "([1-7])" );

	// Anchor pattern to begining and end of string
	reLiteral = "^" + reLiteral + "$";

	// Dynamic RE that parses the original format given
	var re = new RegExp(reLiteral);
	
	// Test if date is in a valid format
	if (!re.test(dateValue))  return false;

	// Parse date to get elements and check if date is valid
	// Assume valid values for date elements not given.
	var year = 0, month = 1, date = 1, dayofyear = 1, week = 1, day = 1;

	// Capture tokens
	var tokens = format.match( /(YYYY|MM|M|DDD|DD|D|ww|d)/g );

	// Capture date values
	var values = re.exec(dateValue);

	// Match up tokens with date values
	for (var i = 0; i < tokens.length; i++) {
		switch (tokens[i]) {
		case "YYYY":
			year = Number(values[i+1]); break;
		case "M":
		case "MM":
			month = Number(values[i+1]); break;
		case "D":
		case "DD":
			date = Number(values[i+1]); break;
		case "DDD":
			dayofyear = Number(values[i+1]); break;
		case "ww":
			week = Number(values[i+1]); break;
		case "d":
			day = Number(values[i+1]); break;
		}
	}

	// Leap years are divisible by 4, but not by 100, unless by 400
	var leapyear = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));

	// 31st of a month with 30 days
	if (date == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) return false; 

	// February 30th or 31st
	if (date >= 30 && month == 2) return false; 

	// February 29th outside a leap year
	if (date == 29 && month == 2 && !leapyear) return false; 
	if (dayofyear == 366 && !leapyear)  return false;

	return true;
}

__CPAN_FILE__ src/validate/web.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.web");
dojo.require("dojo.validate.common");

dojo.validate.isIpAddress = function(/*String*/value, /*Object?*/flags) {
	// summary: Validates an IP address
	//
	// description:
	//  Supports 5 formats for IPv4: dotted decimal, dotted hex, dotted octal, decimal and hexadecimal.
	//  Supports 2 formats for Ipv6.
	//
	// value  A string.
	// flags  An object.  All flags are boolean with default = true.
	//    flags.allowDottedDecimal  Example, 207.142.131.235.  No zero padding.
	//    flags.allowDottedHex  Example, 0x18.0x11.0x9b.0x28.  Case insensitive.  Zero padding allowed.
	//    flags.allowDottedOctal  Example, 0030.0021.0233.0050.  Zero padding allowed.
	//    flags.allowDecimal  Example, 3482223595.  A decimal number between 0-4294967295.
	//    flags.allowHex  Example, 0xCF8E83EB.  Hexadecimal number between 0x0-0xFFFFFFFF.
	//      Case insensitive.  Zero padding allowed.
	//    flags.allowIPv6   IPv6 address written as eight groups of four hexadecimal digits.
	//    flags.allowHybrid   IPv6 address written as six groups of four hexadecimal digits
	//      followed by the usual 4 dotted decimal digit notation of IPv4. x:x:x:x:x:x:d.d.d.d

	var re = new RegExp("^" + dojo.regexp.ipAddress(flags) + "$", "i");
	return re.test(value); // Boolean
}


dojo.validate.isUrl = function(/*String*/value, /*Object?*/flags) {
	// summary: Checks if a string could be a valid URL
	// value: A string
	// flags: An object
	//    flags.scheme  Can be true, false, or [true, false]. 
	//      This means: required, not allowed, or either.
	//    flags in regexp.host can be applied.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	var re = new RegExp("^" + dojo.regexp.url(flags) + "$", "i");
	return re.test(value); // Boolean
}

dojo.validate.isEmailAddress = function(/*String*/value, /*Object?*/flags) {
	// summary: Checks if a string could be a valid email address
	//
	// value: A string
	// flags: An object
	//    flags.allowCruft  Allow address like <mailto:foo@yahoo.com>.  Default is false.
	//    flags in regexp.host can be applied.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	var re = new RegExp("^" + dojo.regexp.emailAddress(flags) + "$", "i");
	return re.test(value); // Boolean
}

dojo.validate.isEmailAddressList = function(/*String*/value, /*Object?*/flags) {
	// summary: Checks if a string could be a valid email address list.
	//
	// value  A string.
	// flags  An object.
	//    flags.listSeparator  The character used to separate email addresses.  Default is ";", ",", "\n" or " ".
	//    flags in regexp.emailAddress can be applied.
	//    flags in regexp.host can be applied.
	//    flags in regexp.ipAddress can be applied.
	//    flags in regexp.tld can be applied.

	var re = new RegExp("^" + dojo.regexp.emailAddressList(flags) + "$", "i");
	return re.test(value); // Boolean
}

dojo.validate.getEmailAddressList = function(/*String*/value, /*Object?*/flags) {
	// summary: Check if value is an email address list. If an empty list
	//  is returned, the value didn't pass the test or it was empty.
	//
	// value: A string
	// flags: An object (same as dojo.validate.isEmailAddressList)

	if(!flags) { flags = {}; }
	if(!flags.listSeparator) { flags.listSeparator = "\\s;,"; }

	if ( dojo.validate.isEmailAddressList(value, flags) ) {
		return value.split(new RegExp("\\s*[" + flags.listSeparator + "]\\s*")); // Array
	}
	return []; // Array
}

__CPAN_FILE__ src/validate/creditCard.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide('dojo.validate.creditCard');

dojo.require("dojo.lang.common");
dojo.require("dojo.validate.common");

/*
	Validates Credit Cards using account number rules in conjunction with the Luhn algorightm
	
 */

dojo.validate.isValidCreditCard = function(value,ccType){
	//checks if type matches the # scheme, and if Luhn checksum is accurate (unless its an Enroute card, the checkSum is skipped)
	if(value&&ccType&&((ccType.toLowerCase()=='er'||dojo.validate.isValidLuhn(value))&&(dojo.validate.isValidCreditCardNumber(value,ccType.toLowerCase())))){
			return true;
	}
	return false;
}
dojo.validate.isValidCreditCardNumber = function(value,ccType) {
	//only checks if the # matches the pattern for that card or any card types if none is specified
	//value == CC #, white spaces and dashes are ignored
	//ccType is of the values in cardinfo -- if Omitted it it returns a | delimited string of matching card types, or false if no matches found
	if(typeof value!='string'){
		value = String(value);
	}
	value = value.replace(/[- ]/g,''); //ignore dashes and whitespaces
	/* 	FIXME: not sure on all the abbreviations for credit cards,below is what each stands for atleast to my knowledge
		mc: Mastercard
		ec: Eurocard
		vi: Visa
		ax: American Express
		dc: Diners Club
		bl: Carte Blanch
		di: Discover
		jcb: JCB
		er: Enroute
	 */
	var results=[];
	var cardinfo = {
		'mc':'5[1-5][0-9]{14}','ec':'5[1-5][0-9]{14}','vi':'4([0-9]{12}|[0-9]{15})',
		'ax':'3[47][0-9]{13}', 'dc':'3(0[0-5][0-9]{11}|[68][0-9]{12})',
		'bl':'3(0[0-5][0-9]{11}|[68][0-9]{12})','di':'6011[0-9]{12}',
		'jcb':'(3[0-9]{15}|(2131|1800)[0-9]{11})','er':'2(014|149)[0-9]{11}'
	};
	if(ccType&&dojo.lang.has(cardinfo,ccType.toLowerCase())){
		return Boolean(value.match(cardinfo[ccType.toLowerCase()])); // boolean
	}else{
		for(var p in cardinfo){
			if(value.match('^'+cardinfo[p]+'$')!=null){
				results.push(p);
			}
		}
		return (results.length)?results.join('|'):false; // string | boolean
	}	
}

dojo.validate.isValidCvv = function(value, ccType) {
	if(typeof value!='string'){
		value=String(value);
	}
	var format;
	switch (ccType.toLowerCase()){
		case 'mc':
		case 'ec':
		case 'vi':
		case 'di':
			format = '###';
			break;
		case 'ax':
			format = '####';
			break;
		default:
			return false;
	}
	var flags = {format:format};
	//FIXME? Why does isNumberFormat take an object for flags when its only parameter is either a string or an array inside the object?
	if ((value.length == format.length)&&(dojo.validate.isNumberFormat(value, flags))){
		return true;
	}
	return false;
}
__CPAN_FILE__ src/validate/check.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.validate.check");
dojo.require("dojo.validate.common");
dojo.require("dojo.lang.common");

dojo.validate.check = function(/*HTMLFormElement*/form, /*Object*/profile){
	// summary: validates user input of an HTML form based on input profile
	//
	// description:
	//	returns an object that contains several methods summarizing the results of the validation
	//
	// form: form to be validated
	// profile: specifies how the form fields are to be validated
	// {trim:Array, uppercase:Array, lowercase:Array, ucfirst:Array, digit:Array,
	//	required:Array, dependencies:Object, constraints:Object, confirm:Object}

	// Essentially private properties of results object
	var missing = [];
	var invalid = [];

	// results object summarizes the validation
	var results = {
		isSuccessful: function() {return ( !this.hasInvalid() && !this.hasMissing() );},
		hasMissing: function() {return ( missing.length > 0 );},
		getMissing: function() {return missing;},
		isMissing: function(elemname) {
			for(var i = 0; i < missing.length; i++){
				if(elemname == missing[i]){ return true; }
			}
			return false;
		},
		hasInvalid: function() {return ( invalid.length > 0 );},
		getInvalid: function() {return invalid;},
		isInvalid: function(elemname){
			for(var i = 0; i < invalid.length; i++){
				if(elemname == invalid[i]){ return true; }
			}
			return false;
		}
	};

	// Filters are applied before fields are validated.
	// Trim removes white space at the front and end of the fields.
	if(profile.trim instanceof Array){
		for(var i = 0; i < profile.trim.length; i++){
			var elem = form[profile.trim[i]];
			if(elem.type != "text" && elem.type != "textarea" && elem.type != "password"){ continue; }
			elem.value = elem.value.replace(/(^\s*|\s*$)/g, "");
		}
	}
	// Convert to uppercase
	if(profile.uppercase instanceof Array){
		for(var i = 0; i < profile.uppercase.length; i++){
			var elem = form[profile.uppercase[i]];
			if(elem.type != "text" && elem.type != "textarea" && elem.type != "password"){ continue; }
			elem.value = elem.value.toUpperCase();
		}
	}
	// Convert to lowercase
	if(profile.lowercase instanceof Array){
		for (var i = 0; i < profile.lowercase.length; i++){
			var elem = form[profile.lowercase[i]];
			if(elem.type != "text" && elem.type != "textarea" && elem.type != "password"){ continue; }
			elem.value = elem.value.toLowerCase();
		}
	}
	// Uppercase first letter
	if(profile.ucfirst instanceof Array){
		for(var i = 0; i < profile.ucfirst.length; i++){
			var elem = form[profile.ucfirst[i]];
			if(elem.type != "text" && elem.type != "textarea" && elem.type != "password"){ continue; }
			elem.value = elem.value.replace(/\b\w+\b/g, function(word) { return word.substring(0,1).toUpperCase() + word.substring(1).toLowerCase(); });
		}
	}
	// Remove non digits characters from the input.
	if(profile.digit instanceof Array){
		for(var i = 0; i < profile.digit.length; i++){
			var elem = form[profile.digit[i]];
			if(elem.type != "text" && elem.type != "textarea" && elem.type != "password"){ continue; }
			elem.value = elem.value.replace(/\D/g, "");
		}
	}

	// See if required input fields have values missing.
	if(profile.required instanceof Array){
		for(var i = 0; i < profile.required.length; i++){ 
			if(!dojo.lang.isString(profile.required[i])){ continue; }
			var elem = form[profile.required[i]];
			// Are textbox, textarea, or password fields blank.
			if((elem.type == "text" || elem.type == "textarea" || elem.type == "password") && /^\s*$/.test(elem.value)){	
				missing[missing.length] = elem.name;
			}
			// Does drop-down box have option selected.
			else if((elem.type == "select-one" || elem.type == "select-multiple") 
						&& (elem.selectedIndex == -1 
						|| /^\s*$/.test(elem.options[elem.selectedIndex].value))){
				missing[missing.length] = elem.name;
			}
			// Does radio button group (or check box group) have option checked.
			else if(elem instanceof Array){
				var checked = false;
				for(var j = 0; j < elem.length; j++){
					if (elem[j].checked) { checked = true; }
				}
				if(!checked){	
					missing[missing.length] = elem[0].name;
				}
			}
		}
	}

	// See if checkbox groups and select boxes have x number of required values.
	if(profile.required instanceof Array){
		for (var i = 0; i < profile.required.length; i++){ 
			if(!dojo.lang.isObject(profile.required[i])){ continue; }
			var elem, numRequired;
			for(var name in profile.required[i]){ 
				elem = form[name]; 
				numRequired = profile.required[i][name];
			}
			// case 1: elem is a check box group
			if(elem instanceof Array){
				var checked = 0;
				for(var j = 0; j < elem.length; j++){
					if(elem[j].checked){ checked++; }
				}
				if(checked < numRequired){	
					missing[missing.length] = elem[0].name;
				}
			}
			// case 2: elem is a select box
			else if(elem.type == "select-multiple" ){
				var selected = 0;
				for(var j = 0; j < elem.options.length; j++){
					if (elem.options[j].selected && !/^\s*$/.test(elem.options[j].value)) { selected++; }
				}
				if(selected < numRequired){	
					missing[missing.length] = elem.name;
				}
			}
		}
	}

	// Dependent fields are required when the target field is present (not blank).
	// Todo: Support dependent and target fields that are radio button groups, or select drop-down lists.
	// Todo: Make the dependency based on a specific value of the target field.
	// Todo: allow dependent fields to have several required values, like {checkboxgroup: 3}.
	if(dojo.lang.isObject(profile.dependencies) || dojo.lang.isObject(profile.dependancies)){
		if(profile["dependancies"]){
			dojo.deprecated("dojo.validate.check", "profile 'dependancies' is deprecated, please use "
							+ "'dependencies'", "0.5");
			profile.dependencies=profile.dependancies;
		}
		// properties of dependencies object are the names of dependent fields to be checked
		for(name in profile.dependencies){
			var elem = form[name];	// the dependent element
			if(elem.type != "text" && elem.type != "textarea" && elem.type != "password"){ continue; } // limited support
			if(/\S+/.test(elem.value)){ continue; }	// has a value already
			if(results.isMissing(elem.name)){ continue; }	// already listed as missing
			var target = form[profile.dependencies[name]];
			if(target.type != "text" && target.type != "textarea" && target.type != "password"){ continue; }	// limited support
			if(/^\s*$/.test(target.value)){ continue; }	// skip if blank
			missing[missing.length] = elem.name;	// ok the dependent field is missing
		}
	}

	// Find invalid input fields.
	if(dojo.lang.isObject(profile.constraints)){
		// constraint properties are the names of fields to bevalidated
		for(name in profile.constraints){
			var elem = form[name];
			if(	(elem.type != "text")&&
				(elem.type != "textarea")&&
				(elem.type != "password")){
				continue;
			}
			// skip if blank - its optional unless required, in which case it
			// is already listed as missing.
			if(/^\s*$/.test(elem.value)){ continue; }

			var isValid = true;
			// case 1: constraint value is validation function
			if(dojo.lang.isFunction(profile.constraints[name])){
				isValid = profile.constraints[name](elem.value);
			}else if(dojo.lang.isArray(profile.constraints[name])){
				// handle nested arrays for multiple constraints
				if(dojo.lang.isArray(profile.constraints[name][0])){
					for (var i=0; i<profile.constraints[name].length; i++){
						isValid = dojo.validate.evaluateConstraint(profile, profile.constraints[name][i], name, elem);
						if(!isValid){ break; }
					}
				}else{
					// case 2: constraint value is array, first elem is function,
					// tail is parameters
					isValid = dojo.validate.evaluateConstraint(profile, profile.constraints[name], name, elem);
				}
			}

			if(!isValid){	
				invalid[invalid.length] = elem.name;
			}
		}
	}

	// Find unequal confirm fields and report them as Invalid.
	if(dojo.lang.isObject(profile.confirm)){
		for(name in profile.confirm){
			var elem = form[name];	// the confirm element
			var target = form[profile.confirm[name]];
			if ( (elem.type != "text" && elem.type != "textarea" && elem.type != "password") 
				||(target.type != elem.type)
				||(target.value == elem.value)	// it's valid
				||(results.isInvalid(elem.name))// already listed as invalid
				||(/^\s*$/.test(target.value)))	// skip if blank - only confirm if target has a value
			{
				continue; 
			}	
			invalid[invalid.length] = elem.name;
		}
	}

	return results; // Object
}

//TODO: evaluateConstraint doesn't use profile or fieldName args?
dojo.validate.evaluateConstraint=function(profile, /*Array*/constraint, fieldName, elem){
	// summary:
	//	Evaluates dojo.validate.check() constraints that are specified as array
	//	arguments
	//
	// description: The arrays are expected to be in the format of:
	//      constraints:{
	//              fieldName: [functionToCall, param1, param2, etc.],
	//              fieldName: [[functionToCallFirst, param1],[functionToCallSecond,param2]]
	//      }
	// 
	//  This function evaluates a single array function in the format of:
	//      [functionName, argument1, argument2, etc]
	// 
	//  The function will be parsed out and evaluated against the incoming parameters.
	//
	// profile: The dojo.validate.check() profile that this evaluation is against.
	// constraint: The single [] array of function and arguments for the function.
	// fieldName: The form dom name of the field being validated.
	// elem: The form element field.

 	var isValidSomething = constraint[0];
	var params = constraint.slice(1);
	params.unshift(elem.value);
	if(typeof isValidSomething != "undefined"){
		return isValidSomething.apply(null, params);
	}
	return false; // Boolean
}

__CPAN_DIR__ src/animation
__CPAN_FILE__ src/animation/Timer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.animation.Timer");
dojo.require("dojo.lang.timing.Timer");

dojo.deprecated("dojo.animation.Timer is now dojo.lang.timing.Timer", "0.5");

dojo.animation.Timer = dojo.lang.timing.Timer;

__CPAN_FILE__ src/animation/Animation.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.animation.Animation");
dojo.require("dojo.animation.AnimationEvent");

dojo.require("dojo.lang.func");
dojo.require("dojo.math");
dojo.require("dojo.math.curves");

dojo.deprecated("dojo.animation.Animation is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");

/*
Animation package based off of Dan Pupius' work on Animations:
http://pupius.co.uk/js/Toolkit.Drawing.js
*/

dojo.animation.Animation = function(/*dojo.math.curves.* */ curve, /*int*/ duration, /*Decimal?*/ accel, /*int?*/ repeatCount, /*int?*/ rate) {
	// summary: Animation object iterates a set of numbers over a curve for a given amount of time, calling 'onAnimate' at each step.
	// curve: Curve to animate over.
	// duration: Duration of the animation, in milliseconds.
	// accel: Either an integer or curve representing amount of acceleration. (?)  Default is linear acceleration.
	// repeatCount: Number of times to repeat the animation.  Default is 0.
	// rate: Time between animation steps, in milliseconds.  Default is 25.
	// description: Calls the following events: "onBegin", "onAnimate", "onEnd", "onPlay", "onPause", "onStop"
	// 				If the animation implements a "handler" function, that will be called before each event is called.

	if(dojo.lang.isArray(curve)) {
		// curve: Array
		// id: i
		curve = new dojo.math.curves.Line(curve[0], curve[1]);
	}
	this.curve = curve;
	this.duration = duration;
	this.repeatCount = repeatCount || 0;
	this.rate = rate || 25;
	if(accel) {
		// accel: Decimal
		// id: j
		if(dojo.lang.isFunction(accel.getValue)) {
			// accel: dojo.math.curves.CatmullRom
			// id: k
			this.accel = accel;
		} else {
			var i = 0.35*accel+0.5;	// 0.15 <= i <= 0.85
			this.accel = new dojo.math.curves.CatmullRom([[0], [i], [1]], 0.45);
		}
	}
}

dojo.lang.extend(dojo.animation.Animation, {
	// public properties
	curve: null,
	duration: 0,
	repeatCount: 0,
	accel: null,

	// events
	onBegin: null,
	onAnimate: null,
	onEnd: null,
	onPlay: null,
	onPause: null,
	onStop: null,
	handler: null,

	// "private" properties
	_animSequence: null,
	_startTime: null,
	_endTime: null,
	_lastFrame: null,
	_timer: null,
	_percent: 0,
	_active: false,
	_paused: false,
	_startRepeatCount: 0,

	// public methods
	play: function(/*Boolean?*/ gotoStart) {
		// summary:  Play the animation.
		// goToStart: If true, will restart the animation from the beginning.  
		//				Otherwise, starts from current play counter.
		// description: Sends an "onPlay" event to any observers.
		//				Also sends an "onBegin" event if starting from the beginning.
		if( gotoStart ) {
			clearTimeout(this._timer);
			this._active = false;
			this._paused = false;
			this._percent = 0;
		} else if( this._active && !this._paused ) {
			return;
		}

		this._startTime = new Date().valueOf();
		if( this._paused ) {
			this._startTime -= (this.duration * this._percent / 100);
		}
		this._endTime = this._startTime + this.duration;
		this._lastFrame = this._startTime;

		var e = new dojo.animation.AnimationEvent(this, null, this.curve.getValue(this._percent),
			this._startTime, this._startTime, this._endTime, this.duration, this._percent, 0);

		this._active = true;
		this._paused = false;

		if( this._percent == 0 ) {
			if(!this._startRepeatCount) {
				this._startRepeatCount = this.repeatCount;
			}
			e.type = "begin";
			if(typeof this.handler == "function") { this.handler(e); }
			if(typeof this.onBegin == "function") { this.onBegin(e); }
		}

		e.type = "play";
		if(typeof this.handler == "function") { this.handler(e); }
		if(typeof this.onPlay == "function") { this.onPlay(e); }

		if(this._animSequence) { this._animSequence._setCurrent(this); }

		this._cycle();
	},

	pause: function() {
		// summary: Temporarily stop the animation, leaving the play counter at the current location.
		// 			Resume later with sequence.play()
		// description: Sends an "onPause" AnimationEvent to any observers.
		clearTimeout(this._timer);
		if( !this._active ) { return; }
		this._paused = true;
		var e = new dojo.animation.AnimationEvent(this, "pause", this.curve.getValue(this._percent),
			this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent, 0);
		if(typeof this.handler == "function") { this.handler(e); }
		if(typeof this.onPause == "function") { this.onPause(e); }
	},

	playPause: function() {
		// summary: Toggle between play and paused states.
		if( !this._active || this._paused ) {
			this.play();
		} else {
			this.pause();
		}
	},

	gotoPercent: function(/*int*/ pct, /*Boolean*/ andPlay) {
		// summary: Set the play counter at a certain point in the animation.
		// pct: Point to set the play counter to, expressed as a percentage (0 to 100).
		// andPlay: If true, will start the animation at the counter automatically.
		clearTimeout(this._timer);
		this._active = true;
		this._paused = true;
		this._percent = pct;
		if( andPlay ) { this.play(); }
	},

	stop: function(/*Boolean?*/ gotoEnd) {
		// summary: Stop the animation.
		// gotoEnd: If true, will advance play counter to the end before sending the event.
		// description: Sends an "onStop" AnimationEvent to any observers.
		clearTimeout(this._timer);
		var step = this._percent / 100;
		if( gotoEnd ) {
			step = 1;
		}
		var e = new dojo.animation.AnimationEvent(this, "stop", this.curve.getValue(step),
			this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent);
		if(typeof this.handler == "function") { this.handler(e); }
		if(typeof this.onStop == "function") { this.onStop(e); }
		this._active = false;
		this._paused = false;
	},

	status: function() {
		// summary: Return the status of the animation.
		// description: Returns one of "playing", "paused" or "stopped".
		if( this._active ) {
			return this._paused ? "paused" : "playing";	/* String */
		} else {
			return "stopped";	/* String */
		}
	},

	// "private" methods
	_cycle: function() {
		// summary: Perform once 'cycle' or step of the animation.
		clearTimeout(this._timer);
		if( this._active ) {
			var curr = new Date().valueOf();
			var step = (curr - this._startTime) / (this._endTime - this._startTime);
			var fps = 1000 / (curr - this._lastFrame);
			this._lastFrame = curr;

			if( step >= 1 ) {
				step = 1;
				this._percent = 100;
			} else {
				this._percent = step * 100;
			}
			
			// Perform accelleration
			if(this.accel && this.accel.getValue) {
				step = this.accel.getValue(step);
			}

			var e = new dojo.animation.AnimationEvent(this, "animate", this.curve.getValue(step),
				this._startTime, curr, this._endTime, this.duration, this._percent, Math.round(fps));

			if(typeof this.handler == "function") { this.handler(e); }
			if(typeof this.onAnimate == "function") { this.onAnimate(e); }

			if( step < 1 ) {
				this._timer = setTimeout(dojo.lang.hitch(this, "_cycle"), this.rate);
			} else {
				e.type = "end";
				this._active = false;
				if(typeof this.handler == "function") { this.handler(e); }
				if(typeof this.onEnd == "function") { this.onEnd(e); }

				if( this.repeatCount > 0 ) {
					this.repeatCount--;
					this.play(true);
				} else if( this.repeatCount == -1 ) {
					this.play(true);
				} else {
					if(this._startRepeatCount) {
						this.repeatCount = this._startRepeatCount;
						this._startRepeatCount = 0;
					}
					if( this._animSequence ) {
						this._animSequence._playNext();
					}
				}
			}
		}
	}
});

__CPAN_FILE__ src/animation/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.animation.AnimationEvent",
		"dojo.animation.Animation",
		"dojo.animation.AnimationSequence"
	]
});
dojo.provide("dojo.animation.*");

dojo.deprecated("dojo.Animation.* is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");

__CPAN_FILE__ src/animation/AnimationSequence.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.animation.AnimationSequence");
dojo.require("dojo.animation.AnimationEvent");
dojo.require("dojo.animation.Animation");

dojo.deprecated("dojo.animation.AnimationSequence is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");

dojo.animation.AnimationSequence = function(/*int?*/ repeatCount){
	// summary: Sequence of Animations, played one after the other.
	// repeatCount: Number of times to repeat the entire sequence.  Default is 0 (play once only).
	// description: Calls the following events: "onBegin", "onEnd", "onNext"
	// 				If the animation implements a "handler" function, that will be called before each event is called.
	this._anims = [];
	this.repeatCount = repeatCount || 0;
}

dojo.lang.extend(dojo.animation.AnimationSequence, {
	repeatCount: 0,

	_anims: [],
	_currAnim: -1,

	onBegin: null,
	onEnd: null,
	onNext: null,
	handler: null,

	add: function() {
		// summary: Add one or more Animations to the sequence.
		// description:  args: Animations (dojo.animation.Animation) to add to the sequence.
		for(var i = 0; i < arguments.length; i++) {
			this._anims.push(arguments[i]);
			arguments[i]._animSequence = this;
		}
	},

	remove: function(/*dojo.animation.Animation*/ anim) {
		// summary: Remove one particular animation from the sequence.
		//	amim: Animation to remove.
		for(var i = 0; i < this._anims.length; i++) {
			if( this._anims[i] == anim ) {
				this._anims[i]._animSequence = null;
				this._anims.splice(i, 1);
				break;
			}
		}
	},

	removeAll: function() {
		// summary: Remove all animations from the sequence.
		for(var i = 0; i < this._anims.length; i++) {
			this._anims[i]._animSequence = null;
		}
		this._anims = [];
		this._currAnim = -1;
	},

	clear: function() {
		// summary: Remove all animations from the sequence.
		this.removeAll();
	},

	play: function(/*Boolean?*/ gotoStart) {
		// summary: Play the animation sequence.
		// gotoStart: If true, will start at the beginning of the first sequence.
		//				Otherwise, starts at the current play counter of the current animation.
		// description: Sends an "onBegin" event to any observers.
		if( this._anims.length == 0 ) { return; }
		if( gotoStart || !this._anims[this._currAnim] ) {
			this._currAnim = 0;
		}
		if( this._anims[this._currAnim] ) {
			if( this._currAnim == 0 ) {
				var e = {type: "begin", animation: this._anims[this._currAnim]};
				if(typeof this.handler == "function") { this.handler(e); }
				if(typeof this.onBegin == "function") { this.onBegin(e); }
			}
			this._anims[this._currAnim].play(gotoStart);
		}
	},

	pause: function() {
		// summary: temporarily stop the current animation.  Resume later with sequence.play()
		if( this._anims[this._currAnim] ) {
			this._anims[this._currAnim].pause();
		}
	},

	playPause: function() {
		// summary: Toggle between play and paused states.
		if( this._anims.length == 0 ) { return; }
		if( this._currAnim == -1 ) { this._currAnim = 0; }
		if( this._anims[this._currAnim] ) {
			this._anims[this._currAnim].playPause();
		}
	},

	stop: function() {
		// summary: Stop the current animation.
		if( this._anims[this._currAnim] ) {
			this._anims[this._currAnim].stop();
		}
	},

	status: function() {
		// summary: Return the status of the current animation.
		// description: Returns one of "playing", "paused" or "stopped".
		if( this._anims[this._currAnim] ) {
			return this._anims[this._currAnim].status();
		} else {
			return "stopped";
		}
	},

	_setCurrent: function(/*dojo.animation.Animation*/ anim) {
		// summary: Set the current animation.
		// anim: Animation to make current, must have already been added to the sequence.
		for(var i = 0; i < this._anims.length; i++) {
			if( this._anims[i] == anim ) {
				this._currAnim = i;
				break;
			}
		}
	},

	_playNext: function() {
		// summary: Play the next animation in the sequence.
		// description:  Sends an "onNext" event to any observers.
		//				 Also sends "onEnd" if the last animation is finished.
		if( this._currAnim == -1 || this._anims.length == 0 ) { return; }
		this._currAnim++;
		if( this._anims[this._currAnim] ) {
			var e = {type: "next", animation: this._anims[this._currAnim]};
			if(typeof this.handler == "function") { this.handler(e); }
			if(typeof this.onNext == "function") { this.onNext(e); }
			this._anims[this._currAnim].play(true);
		} else {
			var e = {type: "end", animation: this._anims[this._anims.length-1]};
			if(typeof this.handler == "function") { this.handler(e); }
			if(typeof this.onEnd == "function") { this.onEnd(e); }
			if(this.repeatCount > 0) {
				this._currAnim = 0;
				this.repeatCount--;
				this._anims[this._currAnim].play(true);
			} else if(this.repeatCount == -1) {
				this._currAnim = 0;
				this._anims[this._currAnim].play(true);
			} else {
				this._currAnim = -1;
			}
		}
	}
});

__CPAN_FILE__ src/animation/AnimationEvent.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.animation.AnimationEvent");
dojo.require("dojo.lang.common");

dojo.deprecated("dojo.animation.AnimationEvent is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");

dojo.animation.AnimationEvent = function(
				/*dojo.animation.Animation*/ animation, 
				/*String*/type, 
				/*int[] */ coords, 
				/*int*/ startTime, 
				/*int*/ currentTime, 
				/*int*/ endTime, 
				/*int*/ duration, 
				/*int*/ percent, 
				/*int?*/ fps) {
	// summary: Event sent at various points during an Animation.
	// animation: Animation throwing the event.
	// type: One of: "animate", "begin", "end", "play", "pause" or "stop".
	// coords: Current coordinates of the animation.
	// startTime: Time the animation was started, as milliseconds.
	// currentTime: Time the event was thrown, as milliseconds.
	// endTime: Time the animation is expected to complete, as milliseconds.
	// duration: Duration of the animation, in milliseconds.
	// percent: Percent of the animation that has completed, between 0 and 100.
	// fps: Frames currently shown per second.  (Only sent for "animate" event).
	// description: The AnimationEvent has public properties of the same name as
	//				 all constructor arguments, plus "x", "y" and "z".
	
	this.type = type; // "animate", "begin", "end", "play", "pause", "stop"
	this.animation = animation;

	this.coords = coords;
	this.x = coords[0];
	this.y = coords[1];
	this.z = coords[2];

	this.startTime = startTime;
	this.currentTime = currentTime;
	this.endTime = endTime;

	this.duration = duration;
	this.percent = percent;
	this.fps = fps;
};
dojo.extend(dojo.animation.AnimationEvent, {
	coordsAsInts: function() {
		// summary: Coerce the coordinates into integers.
		var cints = new Array(this.coords.length);
		for(var i = 0; i < this.coords.length; i++) {
			cints[i] = Math.round(this.coords[i]);
		}
		return cints;
	}
});

__CPAN_DIR__ src/debug
__CPAN_FILE__ src/debug/arrow_show.gif
GIF89a		Ä!/=)5*6$.",%4DZgt(8H&6F8HXAP_'3TaofrDSb*;Lht€q|ˆ,8!/<p|‡#1@#.(4ÿÿÿ!ù,		" †QbYF�YB†£bŒòjrTR`"À5¨“á%°¼0—W;
__CPAN_FILE__ src/debug/spacer.gif
GIF89a		÷@@@è×gÔˆ0ÿÿÿÔˆ*ç‘2¨ ÑPæàé$ç0‘2H ØØçL‘2H ØØç$‘ëéh�î‘8ÿÿÿ‘2‘«‘ëé¸éäéÜçdÝtuê¼�î�ûxÿÿÿ�ûqÝu!pÝu, ØØpéÜ@ê$éä@ê(HpéÜpÿÿÿè,Ý›‚çtHè(‚èŒÝ‚é@2ò€–Òæ‚°é@2S`è@è�‘È ÑHé\‘Q¨‘mé´è¸‘È ØÐé„‘QHèÔ‘È ØÐé ‘QH‘méäæ„Dº«Í0 ÑPÔˆýà0ç�ûl  ØØé@‘ÈH�ê‘Qá8‘mHr8H˜�ûq�Õ†�ç¼é`�çÈê�î�ûxÿÿèäê�î‘pÿÿÿ‘m‘	¼È ØØéÄ‘	’ ØØêÝíÝí b¦Èáb¦ÔéPH˜êD�î‘pÿÿÿ‘mÂÂÞáÂÂãHr8H˜ÝhªH˜H˜êPê ÿÿÿê¼Ã\”Á pÿÿÿÂÂãD•ÕH˜c c EµHHr8HÀê†Ôê†Ôê†Ôê†Ôpê Ýltê¨HÀHÀæà£æ‚°!ù,		H° Áƒ*\Èp`@;
__CPAN_FILE__ src/debug/Firebug.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.debug.Firebug");
dojo.deprecated("dojo.debug.Firebug is slated for removal in 0.5; use dojo.debug.console instead.", "0.5");

// summary
// Firebug Console logger.
// This package redirects the normal dojo debugging output to the firebug console.  It does
// so by sending the entire object to the console, rather than just overriding dojo.hostenv.println
// so that firebugs object inspector can be taken advantage of.

if (dojo.render.html.moz) {
	if (console && console.log) {
		var consoleLog = function() {
			if (!djConfig.isDebug) { return ; }

			var args = dojo.lang.toArray(arguments);
			args.splice(0,0, "DEBUG: ");
			console.log.apply(console, args);
		}

		dojo.debug = consoleLog;

		dojo.debugDeep=consoleLog;

		dojo.debugShallow=function(obj) {
			if (!djConfig.isDebug) { return; }

			if (dojo.lang.isArray(obj)) {
				console.log('Array: ', obj);
				for (var i=0; x<obj.length; i++) {
					console.log('    ', '['+i+']', obj[i]);
				}
			} else {
				console.log('Object: ', obj);
				var propNames = [];
				for (var prop in obj) {
					propNames.push(prop);
				}
				propNames.sort();
				dojo.lang.forEach(propNames, function(prop) {
					try {
						console.log('    ', prop, obj[prop]);
					} catch(e) {
						console.log('    ', prop, 'ERROR', e.message, e);
					}
				});
			}
		}

	} else {
		dojo.debug("dojo.debug.Firebug requires Firebug > 0.4");
	}
}

__CPAN_FILE__ src/debug/arrow_hide.gif
GIF89a		Ä)6'7H):K!/=)5%4C$/,9DSb%0)&5EO]kJXg;K[)9J )8HX .;$3Bdp|]jwÿÿÿ!ù,		  %Žd9VU1Ž°LVƒDO1c0IDRˆÉ¢‡!;
__CPAN_FILE__ src/debug/console.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.debug.console");
dojo.require("dojo.logging.ConsoleLogger");

// summary:
// 	Console logger, for use with FireFox Firebug, Safari and Opera's consoles.
// description:
//  This package redirects the normal dojo debugging output to the console log in modern browsers.
//  When using Firebug, it does this  by sending the entire object to the console, 
//	rather than just overriding dojo.hostenv.println, so that Firebug's interactive 
//	object inspector is available.
// see: http://www.joehewitt.com/software/firebug/docs.php

if (window.console) {
	if (console.info != null) {
		// using a later version of Firebug -- lots of fun stuff!
		
		dojo.hostenv.println = function() {
			// summary: Write all of the arguments to the Firebug console
			// description: Uses console.info() so that the (i) icon prints next to the debug line
			//	rather than munging the arguments by adding "DEBUG:" in front of them.
			//	This allows us to use Firebug's string handling to do interesting things
			if (!djConfig.isDebug)	{	 return;	}
			console.info.apply(console, arguments);
		}
		dojo.debug=dojo.hostenv.println;
		dojo.debugDeep = dojo.debug;

		dojo.debugShallow = function(/*Object*/ obj, /*Boolean?*/showMethods, /*Boolean?*/sort) {
			// summary:  Write first-level properties of obj to the console.
			//	obj:			Object or Array to debug
			//	showMethods:	Pass false to skip outputing methods of object, any other value will output them.
			//	sort:			Pass false to skip sorting properties, any other value will sort.
			if (!djConfig.isDebug) { return; }

			showMethods = (showMethods != false);
			sort = (sort != false);

			// handle null or something without a constructor (in which case we don't know the type)
			if (obj == null || obj.constructor == null) {
				return dojo.debug(obj);
			}
	
			// figure out type via a standard constructor (Object, String, Date, etc)
			var type = obj.declaredClass;
			if (type == null) {
				type = obj.constructor.toString().match(/function\s*(.*)\(/);
				if (type) {	type = type[1]	};
			}
			// if we got a viable type, use Firebug's interactive property dump feature
			if (type) {
				if (type == "String" || type == "Number") {
					return dojo.debug(type+": ", obj);
				}
				if (showMethods && !sort) {
					var sortedObj = obj;
				} else {
					var propNames = [];
					if (showMethods) {
						for (var prop in obj) {	
							propNames.push(prop);
						}
					} else {
						for (var prop in obj) {	
							if (typeof obj[prop] != "function") { propNames.push(prop);	}
							else dojo.debug(prop);
						}					
					}
					if (sort) propNames.sort();
					var sortedObj = {};
					dojo.lang.forEach(propNames, function(prop) {
						sortedObj[prop] = obj[prop];
					});
				}

				return dojo.debug(type+": %o\n%2.o",obj,sortedObj);
			}
		
			// otherwise just output the constructor + object, 
			//	which is nice for a DOM element, etc
			return dojo.debug(obj.constructor + ": ", obj);
		}
		
	} else if (console.log != null) {
		// using Safari or an old version of Firebug
		dojo.hostenv.println=function() {
			if (!djConfig.isDebug) { return ; }
			// make sure we're only writing a single string to Safari's console
			var args = dojo.lang.toArray(arguments);
			console.log("DEBUG: " + args.join(" "));
		}
		dojo.debug=dojo.hostenv.println;
	} else {
		// not supported
		dojo.debug("dojo.debug.console requires Firebug > 0.4");
	}
} else if (dojo.render.html.opera) {
	// using Opera 8.0 or later
	if (opera && opera.postError) {
		dojo.hostenv.println=opera.postError;
		// summary:  hook debugging up to Opera's postError routine
	} else {
		dojo.debug("dojo.debug.Opera requires Opera > 8.0");
	}
}


__CPAN_FILE__ src/debug/deep.html
<html>
<head>
<title>Deep Debugger</title>
<script>

var tableRows = {};
var tableCels = {};
var tableObjs = {};
var tablesBuilt = {};
var tableShows = {};
var tableHides = {};

// IE: nodes w/id need to be redeclared or getElementById is b0rked
var frame = null;

window.onload = function(){
	// if IE loads this page too quickly (instantly) then 
	// window.debugVar might not have been set
	window.setTimeout(startMeUp, 100);
}

function startMeUp(){
	frame = document.getElementById('frame');
	// GET string 
	var index = location.search.split("=").pop();
	var debugObj = window.opener.dojo.debugDeep;
	var debugVar = debugObj.debugVars[index] || window.debugVar;
	buildTable('root', frame, debugVar);
}

function buildTable(path, parent, obj){
	var keys = [];
	var vals = [];
	for(var prop in obj){
		keys.push(prop);
		try {
			vals[prop] = obj[prop];
		} catch(E) {
			vals[prop] = 'ERROR: ' + E.message;
		}
	}
	keys.sort(keySorter);

	if (!keys.length){

		var div = document.createElement('div');
		div.appendChild(document.createTextNode('Object has no properties.'));

		parent.appendChild(div);
		return;
	}


	var t = document.createElement('table');
	t.border = "1";

	var tb = document.createElement('tbody');
	t.appendChild(tb);


	for(var i = 0; i < keys.length; i++) {
		buildTableRow(path+'-'+keys[i], tb, keys[i], vals[keys[i]]);
	}

	if (path == 'root'){
		//t.style.width = '90%';
	}
	t.style.width = '100%';

	parent.appendChild(t);

	tablesBuilt[path] = true;
}

function buildTableRow(path, tb, name, value) {

	var simpleType = typeof(value);
	var createSubrow = (simpleType == 'object');
	var complexType = simpleType;

	if (simpleType == 'object'){
		var cls = getConstructorClass(value);
		if (cls){
			if (cls == 'Object'){
			}else if (cls == 'Array'){
				complexType = 'array';
			}else{
				complexType += ' ('+cls+')';
			}
		}
	}

/*var tr1 = document.createElement('tr');
	var td1 = document.createElement('td');
	var td2 = document.createElement('td');
	var td3 = document.createElement('td');
	var td4 = document.createElement('td');*/

	var row = tb.rows.length;
	var tr1 = tb.insertRow(row++);
	var td1 = tr1.insertCell(0);
	var td2 = tr1.insertCell(1);
	var td3 = tr1.insertCell(2);
	var td4 = tr1.insertCell(3);
	
	tr1.style.verticalAlign = 'top';
	td1.style.verticalAlign = 'middle';

	td1.className = 'propPlus';
	td2.className = 'propName';
	td3.className = 'propType';
	td4.className = 'propVal';

	//tr1.appendChild(td1);
	//tr1.appendChild(td2);
	//tr1.appendChild(td3);
	//tr1.appendChild(td4);

	if (createSubrow){
		var img1 = document.createElement('img');
		img1.width = 9;
		img1.height = 9;
		img1.src = 'arrow_show.gif';
		var a1 = document.createElement('a');
		a1.appendChild(img1);
		a1.href = '#';
		a1.onclick = function(){ showTableRow(path); return false; };

		var img2 = document.createElement('img');
		img2.width = 9;
		img2.height = 9;
		img2.src = 'arrow_hide.gif';
		var a2 = document.createElement('a');
		a2.appendChild(img2);
		a2.href = '#';
		a2.onclick = function(){ hideTableRow(path); return false; };
		a2.style.display = 'none';

		tableShows[path] = a1;
		tableHides[path] = a2;

		td1.appendChild(a1);
		td1.appendChild(a2);
	}else{
		var img = document.createElement('img');
		img.width = 9;
		img.height = 9;
		img.src = 'spacer.gif';

		td1.appendChild(img);
	}

	td2.appendChild(document.createTextNode(name));
	td3.appendChild(document.createTextNode(complexType));
	td4.appendChild(buildPreBlock(value));

	//tb.appendChild(tr1);

	if (createSubrow){
		var tr2 = tb.insertRow(row++);
		var td5 = tr2.insertCell(0);
		var td6 = tr2.insertCell(1);
		
		//var tr2 = document.createElement('tr');
		//var td5 = document.createElement('td');
		//var td6 = document.createElement('td');

		td5.innerHTML = '&nbsp;';
		//td6.innerHTML = '&nbsp;';

		td6.colSpan = '3';

		tr2.appendChild(td5);
		tr2.appendChild(td6);

		tr2.style.display = 'none';

		tb.appendChild(tr2);

		tableRows[path] = tr2;
		tableCels[path] = td6;
		tableObjs[path] = value;
	}
}

function showTableRow(path){

	var tr = tableRows[path];
	var td = tableCels[path];
	var a1 = tableShows[path];
	var a2 = tableHides[path];

	if (!tablesBuilt[path]){

		//alert('building table for '+path);
		buildTable(path, td, tableObjs[path]);
	}

	tr.style.display = 'table-row';

	a1.style.display = 'none';
	a2.style.display = 'inline';
}

function hideTableRow(path){

	var tr = tableRows[path];
	var a1 = tableShows[path];
	var a2 = tableHides[path];

	tr.style.display = 'none';

	a1.style.display = 'inline';
	a2.style.display = 'none';
}

function buildPreBlock(value){

	//
	// how many lines ?
	//

	var s = ''+value;
	s = s.replace("\r\n", "\n");
	s = s.replace("\r", "");
	var lines = s.split("\n");


	if (lines.length < 2){

		if (lines[0].length < 60){

			var pre = document.createElement('pre');
			pre.appendChild(document.createTextNode(s));
			return pre;
		}
	}


	//
	// multiple lines :(
	//

	var preview = lines[0].substr(0, 60) + ' ...';

	var pre1 = document.createElement('pre');
	pre1.appendChild(document.createTextNode(preview));
	pre1.className = 'clicky';

	var pre2 = document.createElement('pre');
	pre2.appendChild(document.createTextNode(s));
	pre2.style.display = 'none';
	pre2.className = 'clicky';

	pre1.onclick = function(){
		pre1.style.display = 'none';
		pre2.style.display = 'block';
	}

	pre2.onclick = function(){
		pre1.style.display = 'block';
		pre2.style.display = 'none';
	}

	var pre = document.createElement('div');

	pre.appendChild(pre1);
	pre.appendChild(pre2);

	return pre;
}

function getConstructorClass(obj){

	if (!obj.constructor || !obj.constructor.toString) return;

	var m = obj.constructor.toString().match(/function\s*(\w+)/);

	if (m && m.length == 2) return m[1];

	return null;
}

function keySorter(a, b){

	if (a == parseInt(a) && b == parseInt(b)){

		return (parseInt(a) > parseInt(b)) ? 1 : ((parseInt(a) < parseInt(b)) ? -1 : 0);
	}

	// sort by lowercase string

	var a2 = String(a).toLowerCase();
	var b2 = String(b).toLowerCase();

	return (a2 > b2) ? 1 : ((a2 < b2) ? -1 : 0);
}

</script>
<style>

body {
	font-family: arial, helvetica, sans-serif;
}

table {
	border-width: 0px;
	border-spacing: 1px;
	border-collapse: separate;
}

td {
	border-width: 0px;
	padding: 2px;
}

img {
	border: 0;
}

pre {
	margin: 0;
	padding: 0;
	white-space: -moz-pre-wrap;  /* Mozilla, supported since 1999 */
	white-space: -pre-wrap;      /* Opera 4 - 6 */
	white-space: -o-pre-wrap;    /* Opera 7 */
	white-space: pre-wrap;       /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */
	word-wrap: break-word;       /* IE 5.5+ */
}

pre.clicky {
	cursor: hand;
	cursor: pointer;
}

td.propPlus {
	width: 9px;
	background-color: #ddd;
}

td.propName {
	background-color: #ddd;
}

td.propType {
	background-color: #ddd;
}

td.propVal {
	background-color: #ddd;
}

</style>
</head>
<body>

<h2>Javascript Object Browser</h2>

<div id="frame"></div>

</body>
</html>
__CPAN_DIR__ src/selection
__CPAN_FILE__ src/selection/Selection.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.selection.Selection");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.func");
dojo.require("dojo.math");

dojo.selection.Selection = function(items, isCollection) {
	this.items = [];
	this.selection = [];
	this._pivotItems = [];
	this.clearItems();

	if(items) {
		if(isCollection) {
			this.setItemsCollection(items);
		} else {
			this.setItems(items);
		}
	}
}
dojo.lang.extend(dojo.selection.Selection, {
	items: null, // items to select from, order matters for growable selections

	selection: null, // items selected, aren't stored in order (see sorted())
	lastSelected: null, // last item selected

	allowImplicit: true, // if true, grow selection will start from 0th item when nothing is selected
	length: 0, // number of *selected* items

	// if true, the selection is treated as an in-order and can grow by ranges, not just by single item
	isGrowable: true,

	_pivotItems: null, // stack of pivot items
	_pivotItem: null, // item we grow selections from, top of stack

	// event handlers
	onSelect: function(item) {},
	onDeselect: function(item) {},
	onSelectChange: function(item, selected) {},

	_find: function(item, inSelection) {
		if(inSelection) {
			return dojo.lang.find(this.selection, item);
		} else {
			return dojo.lang.find(this.items, item);
		}
	},

	isSelectable: function(item) {
		// user-customizable, will filter items through this
		return true;
	},

	setItems: function(/* ... */) {
		this.clearItems();
		this.addItems.call(this, arguments);
	},

	// this is in case you have an active collection array-like object
	// (i.e. getElementsByTagName collection) that manages its own order
	// and item list
	setItemsCollection: function(collection) {
		this.items = collection;
	},

	addItems: function(/* ... */) {
		var args = dojo.lang.unnest(arguments);
		for(var i = 0; i < args.length; i++) {
			this.items.push(args[i]);
		}
	},

	addItemsAt: function(item, before /* ... */) {
		if(this.items.length == 0) { // work for empy case
			return this.addItems(dojo.lang.toArray(arguments, 2));
		}

		if(!this.isItem(item)) {
			item = this.items[item];
		}
		if(!item) { throw new Error("addItemsAt: item doesn't exist"); }
		var idx = this._find(item);
		if(idx > 0 && before) { idx--; }
		for(var i = 2; i < arguments.length; i++) {
			if(!this.isItem(arguments[i])) {
				this.items.splice(idx++, 0, arguments[i]);
			}
		}
	},

	removeItem: function(item) {
		// remove item
		var idx = this._find(item);
		if(idx > -1) {
			this.items.splice(idx, 1);
		}
		// remove from selection
		// FIXME: do we call deselect? I don't think so because this isn't how
		// you usually want to deselect an item. For example, if you deleted an
		// item, you don't really want to deselect it -- you want it gone. -DS
		idx = this._find(item, true);
		if(idx > -1) {
			this.selection.splice(idx, 1);
		}
	},

	clearItems: function() {
		this.items = [];
		this.deselectAll();
	},

	isItem: function(item) {
		return this._find(item) > -1;
	},

	isSelected: function(item) {
		return this._find(item, true) > -1;
	},

	/**
	 * allows you to filter item in or out of the selection
	 * depending on the current selection and action to be taken
	**/
	selectFilter: function(item, selection, add, grow) {
		return true;
	},

	/**
	 * update -- manages selections, most selecting should be done here
	 *  item => item which may be added/grown to/only selected/deselected
	 *  add => behaves like ctrl in windows selection world
	 *  grow => behaves like shift
	 *  noToggle => if true, don't toggle selection on item
	**/
	update: function(item, add, grow, noToggle) {
		if(!this.isItem(item)) { return false; }

		if(this.isGrowable && grow) {
			if(!this.isSelected(item)
				&& this.selectFilter(item, this.selection, false, true)) {
				this.grow(item);
				this.lastSelected = item;
			}
		} else if(add) {
			if(this.selectFilter(item, this.selection, true, false)) {
				if(noToggle) {
					if(this.select(item)) {
						this.lastSelected = item;
					}
				} else if(this.toggleSelected(item)) {
					this.lastSelected = item;
				}
			}
		} else {
			this.deselectAll();
			this.select(item);
		}

		this.length = this.selection.length;
	},

	/**
	 * Grow a selection.
	 *  toItem => which item to grow selection to
	 *  fromItem => which item to start the growth from (it won't be selected)
	 *
	 * Any items in (fromItem, lastSelected] that aren't part of
	 * (fromItem, toItem] will be deselected
	**/
	grow: function(toItem, fromItem) {
		if(!this.isGrowable) { return; }

		if(arguments.length == 1) {
			fromItem = this._pivotItem;
			if(!fromItem && this.allowImplicit) {
				fromItem = this.items[0];
			}
		}
		if(!toItem || !fromItem) { return false; }

		var fromIdx = this._find(fromItem);

		// get items to deselect (fromItem, lastSelected]
		var toDeselect = {};
		var lastIdx = -1;
		if(this.lastSelected) {
			lastIdx = this._find(this.lastSelected);
			var step = fromIdx < lastIdx ? -1 : 1;
			var range = dojo.math.range(lastIdx, fromIdx, step);
			for(var i = 0; i < range.length; i++) {
				toDeselect[range[i]] = true;
			}
		}

		// add selection (fromItem, toItem]
		var toIdx = this._find(toItem);
		var step = fromIdx < toIdx ? -1 : 1;
		var shrink = lastIdx >= 0 && step == 1 ? lastIdx < toIdx : lastIdx > toIdx;
		var range = dojo.math.range(toIdx, fromIdx, step);
		if(range.length) {
			for(var i = range.length-1; i >= 0; i--) {
				var item = this.items[range[i]];
				if(this.selectFilter(item, this.selection, false, true)) {
					if(this.select(item, true) || shrink) {
						this.lastSelected = item;
					}
					if(range[i] in toDeselect) {
						delete toDeselect[range[i]];
					}
				}
			}
		} else {
			this.lastSelected = fromItem;
		}

		// now deselect...
		for(var i in toDeselect) {
			if(this.items[i] == this.lastSelected) {
				//dojo.debug("oops!");
			}
			this.deselect(this.items[i]);
		}

		// make sure everything is all kosher after selections+deselections
		this._updatePivot();
	},

	/**
	 * Grow selection upwards one item from lastSelected
	**/
	growUp: function() {
		if(!this.isGrowable) { return; }

		var idx = this._find(this.lastSelected) - 1;
		while(idx >= 0) {
			if(this.selectFilter(this.items[idx], this.selection, false, true)) {
				this.grow(this.items[idx]);
				break;
			}
			idx--;
		}
	},

	/**
	 * Grow selection downwards one item from lastSelected
	**/
	growDown: function() {
		if(!this.isGrowable) { return; }

		var idx = this._find(this.lastSelected);
		if(idx < 0 && this.allowImplicit) {
			this.select(this.items[0]);
			idx = 0;
		}
		idx++;
		while(idx > 0 && idx < this.items.length) {
			if(this.selectFilter(this.items[idx], this.selection, false, true)) {
				this.grow(this.items[idx]);
				break;
			}
			idx++;
		}
	},

	toggleSelected: function(item, noPivot) {
		if(this.isItem(item)) {
			if(this.select(item, noPivot)) { return 1; }
			if(this.deselect(item)) { return -1; }
		}
		return 0;
	},

	select: function(item, noPivot) {
		if(this.isItem(item) && !this.isSelected(item)
			&& this.isSelectable(item)) {
			this.selection.push(item);
			this.lastSelected = item;
			this.onSelect(item);
			this.onSelectChange(item, true);
			if(!noPivot) {
				this._addPivot(item);
			}
			this.length = this.selection.length;
			return true;
		}
		return false;
	},

	deselect: function(item) {
		var idx = this._find(item, true);
		if(idx > -1) {
			this.selection.splice(idx, 1);
			this.onDeselect(item);
			this.onSelectChange(item, false);
			if(item == this.lastSelected) {
				this.lastSelected = null;
			}
			this._removePivot(item);
			this.length = this.selection.length;
			return true;
		}
		return false;
	},

	selectAll: function() {
		for(var i = 0; i < this.items.length; i++) {
			this.select(this.items[i]);
		}
	},

	deselectAll: function() {
		while(this.selection && this.selection.length) {
			this.deselect(this.selection[0]);
		}
	},

	selectNext: function() {
		var idx = this._find(this.lastSelected);
		while(idx > -1 && ++idx < this.items.length) {
			if(this.isSelectable(this.items[idx])) {
				this.deselectAll();
				this.select(this.items[idx]);
				return true;
			}
		}
		return false;
	},

	selectPrevious: function() {
		//debugger;
		var idx = this._find(this.lastSelected);
		while(idx-- > 0) {
			if(this.isSelectable(this.items[idx])) {
				this.deselectAll();
				this.select(this.items[idx]);
				return true;
			}
		}
		return false;
	},

	// select first selectable item
	selectFirst: function() {
		this.deselectAll();
		var idx = 0;
		while(this.items[idx] && !this.select(this.items[idx])) {
			idx++;
		}
		return this.items[idx] ? true : false;
	},

	// select last selectable item
	selectLast: function() {
		this.deselectAll();
		var idx = this.items.length-1;
		while(this.items[idx] && !this.select(this.items[idx])) {
			idx--;
		}
		return this.items[idx] ? true : false;
	},

	_addPivot: function(item, andClear) {
		this._pivotItem = item;
		if(andClear) {
			this._pivotItems = [item];
		} else {
			this._pivotItems.push(item);
		}
	},

	_removePivot: function(item) {
		var i = dojo.lang.find(this._pivotItems, item);
		if(i > -1) {
			this._pivotItems.splice(i, 1);
			this._pivotItem = this._pivotItems[this._pivotItems.length-1];
		}

		this._updatePivot();
	},

	_updatePivot: function() {
		if(this._pivotItems.length == 0) {
			if(this.lastSelected) {
				this._addPivot(this.lastSelected);
			}
		}
	},

	sorted: function() {
		return dojo.lang.toArray(this.selection).sort(
			dojo.lang.hitch(this, function(a, b) {
				var A = this._find(a), B = this._find(b);
				if(A > B) {
					return 1;
				} else if(A < B) {
					return -1;
				} else {
					return 0;
				}
			})
		);
	},

	// remove any items from the selection that are no longer in this.items
	updateSelected: function() {
		for(var i = 0; i < this.selection.length; i++) {
			if(this._find(this.selection[i]) < 0) {
				var removed = this.selection.splice(i, 1);

				this._removePivot(removed[0]);
			}
		}

		this.length = this.selection.length;
	}
});

__CPAN_DIR__ src/string
__CPAN_FILE__ src/string/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.string.common");

dojo.string.trim = function(/* string */str, /* integer? */wh){
	//	summary
	//	Trim whitespace from str.  If wh > 0, trim from start, if wh < 0, trim from end, else both
	if(!str.replace){ return str; }
	if(!str.length){ return str; }
	var re = (wh > 0) ? (/^\s+/) : (wh < 0) ? (/\s+$/) : (/^\s+|\s+$/g);
	return str.replace(re, "");	//	string
}

dojo.string.trimStart = function(/* string */str) {
	//	summary
	//	Trim whitespace at the beginning of 'str'
	return dojo.string.trim(str, 1);	//	string
}

dojo.string.trimEnd = function(/* string */str) {
	//	summary
	//	Trim whitespace at the end of 'str'
	return dojo.string.trim(str, -1);
}

dojo.string.repeat = function(/* string */str, /* integer */count, /* string? */separator) {
	//	summary
	//	Return 'str' repeated 'count' times, optionally placing 'separator' between each rep
	var out = "";
	for(var i = 0; i < count; i++) {
		out += str;
		if(separator && i < count - 1) {
			out += separator;
		}
	}
	return out;	//	string
}

dojo.string.pad = function(/* string */str, /* integer */len/*=2*/, /* string */ c/*='0'*/, /* integer */dir/*=1*/) {
	//	summary
	//	Pad 'str' to guarantee that it is at least 'len' length with the character 'c' at either the 
	//	start (dir=1) or end (dir=-1) of the string
	var out = String(str);
	if(!c) {
		c = '0';
	}
	if(!dir) {
		dir = 1;
	}
	while(out.length < len) {
		if(dir > 0) {
			out = c + out;
		} else {
			out += c;
		}
	}
	return out;	//	string
}

dojo.string.padLeft = function(/* string */str, /* integer */len, /* string */c) {
	//	summary
	//	same as dojo.string.pad(str, len, c, 1)
	return dojo.string.pad(str, len, c, 1);	//	string
}

dojo.string.padRight = function(/* string */str, /* integer */len, /* string */c) {
	//	summary
	//	same as dojo.string.pad(str, len, c, -1)
	return dojo.string.pad(str, len, c, -1);	//	string
}

__CPAN_FILE__ src/string/Builder.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.string.Builder");
dojo.require("dojo.string");
dojo.require("dojo.lang.common");

// NOTE: testing shows that direct "+=" concatenation is *much* faster on
// Spidermoneky and Rhino, while arr.push()/arr.join() style concatenation is
// significantly quicker on IE (Jscript/wsh/etc.).

dojo.string.Builder = function(/* string? */str){
	//	summary
	this.arrConcat = (dojo.render.html.capable && dojo.render.html["ie"]);

	var a = [];
	var b = "";
	var length = this.length = b.length;

	if(this.arrConcat){
		if(b.length > 0){
			a.push(b);
		}
		b = "";
	}

	this.toString = this.valueOf = function(){ 
		//	summary
		//	Concatenate internal buffer and return as a string
		return (this.arrConcat) ? a.join("") : b;	//	string
	};

	this.append = function(){
		//	summary
		//	Append all arguments to the end of the internal buffer
		for(var x=0; x<arguments.length; x++){
			var s = arguments[x];
			if(dojo.lang.isArrayLike(s)){
				this.append.apply(this, s);
			} else {
				if(this.arrConcat){
					a.push(s);
				}else{
					b+=s;
				}
				length += s.length;
				this.length = length;
			}
		}
		return this;	//	dojo.string.Builder
	};

	this.clear = function(){
		//	summary
		//	Clear the internal buffer.
		a = [];
		b = "";
		length = this.length = 0;
		return this;	//	dojo.string.Builder
	};

	this.remove = function(/* integer */f, /* integer */l){
		//	summary
		//	Remove a section of string from the internal buffer.
		var s = ""; 
		if(this.arrConcat){
			b = a.join(""); 
		}
		a=[];
		if(f>0){
			s = b.substring(0, (f-1));
		}
		b = s + b.substring(f + l); 
		length = this.length = b.length; 
		if(this.arrConcat){
			a.push(b);
			b="";
		}
		return this;	//	dojo.string.Builder
	};

	this.replace = function(/* string */o, /* string */n){
		//	summary
		//	replace phrase *o* with phrase *n*.
		if(this.arrConcat){
			b = a.join(""); 
		}
		a = []; 
		b = b.replace(o,n); 
		length = this.length = b.length; 
		if(this.arrConcat){
			a.push(b);
			b="";
		}
		return this;	//	dojo.string.Builder
	};

	this.insert = function(/* integer */idx, /* string */s){
		//	summary
		//	Insert string s at index idx.
		if(this.arrConcat){
			b = a.join(""); 
		}
		a=[];
		if(idx == 0){
			b = s + b;
		}else{
			var t = b.split("");
			t.splice(idx,0,s);
			b = t.join("")
		}
		length = this.length = b.length; 
		if(this.arrConcat){
			a.push(b); 
			b="";
		}
		return this;	//	dojo.string.Builder
	};

	this.append.apply(this, arguments);
};

__CPAN_FILE__ src/string/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.string",
		"dojo.string.common",
		"dojo.string.extras",
		"dojo.string.Builder"
	]
});
dojo.provide("dojo.string.*");

__CPAN_FILE__ src/string/extras.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.string.extras");

dojo.require("dojo.string.common");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.array");

//TODO: should we use ${} substitution syntax instead, like widgets do?
dojo.string.substituteParams = function(/*string*/template, /* object - optional or ... */hash){
// summary:
//	Performs parameterized substitutions on a string. Throws an exception if any parameter is unmatched.
//
// description:
//	For example,
//		dojo.string.substituteParams("File '%{0}' is not found in directory '%{1}'.","foo.html","/temp");
//	returns
//		"File 'foo.html' is not found in directory '/temp'."
//
// template: the original string template with %{values} to be replaced
// hash: name/value pairs (type object) to provide substitutions.  Alternatively, substitutions may be
//	included as arguments 1..n to this function, corresponding to template parameters 0..n-1

	var map = (typeof hash == 'object') ? hash : dojo.lang.toArray(arguments, 1);

	return template.replace(/\%\{(\w+)\}/g, function(match, key){
		if(typeof(map[key]) != "undefined" && map[key] != null){
			return map[key];
		}
		dojo.raise("Substitution not found: " + key);
	}); // string
};

dojo.string.capitalize = function(/*string*/str){
// summary:
//	Uppercases the first letter of each word

	if(!dojo.lang.isString(str)){ return ""; }
	if(arguments.length == 0){ str = this; }

	var words = str.split(' ');
	for(var i=0; i<words.length; i++){
		words[i] = words[i].charAt(0).toUpperCase() + words[i].substring(1);
	}
	return words.join(" "); // string
}

dojo.string.isBlank = function(/*string*/str){
// summary:
//	Return true if the entire string is whitespace characters

	if(!dojo.lang.isString(str)){ return true; }
	return (dojo.string.trim(str).length == 0); // boolean
}

//FIXME: not sure exactly what encodeAscii is trying to do, or if it's working right
dojo.string.encodeAscii = function(/*string*/str){
	if(!dojo.lang.isString(str)){ return str; } // unknown
	var ret = "";
	var value = escape(str);
	var match, re = /%u([0-9A-F]{4})/i;
	while((match = value.match(re))){
		var num = Number("0x"+match[1]);
		var newVal = escape("&#" + num + ";");
		ret += value.substring(0, match.index) + newVal;
		value = value.substring(match.index+match[0].length);
	}
	ret += value.replace(/\+/g, "%2B");
	return ret; // string
}

dojo.string.escape = function(/*string*/type, /*string*/str){
// summary:
//	Adds escape sequences for special characters according to the convention of 'type'
//
// type: one of xml|html|xhtml|sql|regexp|regex|javascript|jscript|js|ascii
// str: the string to be escaped

	var args = dojo.lang.toArray(arguments, 1);
	switch(type.toLowerCase()){
		case "xml":
		case "html":
		case "xhtml":
			return dojo.string.escapeXml.apply(this, args); // string
		case "sql":
			return dojo.string.escapeSql.apply(this, args); // string
		case "regexp":
		case "regex":
			return dojo.string.escapeRegExp.apply(this, args); // string
		case "javascript":
		case "jscript":
		case "js":
			return dojo.string.escapeJavaScript.apply(this, args); // string
		case "ascii":
			// so it's encode, but it seems useful
			return dojo.string.encodeAscii.apply(this, args); // string
		default:
			return str; // string
	}
}

dojo.string.escapeXml = function(/*string*/str, /*boolean*/noSingleQuotes){
//summary:
//	Adds escape sequences for special characters in XML: &<>"'
//  Optionally skips escapes for single quotes

	str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;")
		.replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
	if(!noSingleQuotes){ str = str.replace(/'/gm, "&#39;"); }
	return str; // string
}

dojo.string.escapeSql = function(/*string*/str){
//summary:
//	Adds escape sequences for single quotes in SQL expressions

	return str.replace(/'/gm, "''"); //string
}

dojo.string.escapeRegExp = function(/*string*/str){
//summary:
//	Adds escape sequences for special characters in regular expressions

	return str.replace(/\\/gm, "\\\\").replace(/([\f\b\n\t\r[\^$|?*+(){}])/gm, "\\$1"); // string
}

//FIXME: should this one also escape backslash?
dojo.string.escapeJavaScript = function(/*string*/str){
//summary:
//	Adds escape sequences for single and double quotes as well
//	as non-visible characters in JavaScript string literal expressions

	return str.replace(/(["'\f\b\n\t\r])/gm, "\\$1"); // string
}

//FIXME: looks a lot like escapeJavaScript, just adds quotes? deprecate one?
dojo.string.escapeString = function(/*string*/str){
//summary:
//	Adds escape sequences for non-visual characters, double quote and backslash
//	and surrounds with double quotes to form a valid string literal.
	return ('"' + str.replace(/(["\\])/g, '\\$1') + '"'
		).replace(/[\f]/g, "\\f"
		).replace(/[\b]/g, "\\b"
		).replace(/[\n]/g, "\\n"
		).replace(/[\t]/g, "\\t"
		).replace(/[\r]/g, "\\r"); // string
}

// TODO: make an HTML version
dojo.string.summary = function(/*string*/str, /*number*/len){
// summary:
//	Truncates 'str' after 'len' characters and appends periods as necessary so that it ends with "..."

	if(!len || str.length <= len){
		return str; // string
	}

	return str.substring(0, len).replace(/\.+$/, "") + "..."; // string
}

dojo.string.endsWith = function(/*string*/str, /*string*/end, /*boolean*/ignoreCase){
// summary:
//	Returns true if 'str' ends with 'end'

	if(ignoreCase){
		str = str.toLowerCase();
		end = end.toLowerCase();
	}
	if((str.length - end.length) < 0){
		return false; // boolean
	}
	return str.lastIndexOf(end) == str.length - end.length; // boolean
}

dojo.string.endsWithAny = function(/*string*/str /* , ... */){
// summary:
//	Returns true if 'str' ends with any of the arguments[2 -> n]

	for(var i = 1; i < arguments.length; i++) {
		if(dojo.string.endsWith(str, arguments[i])) {
			return true; // boolean
		}
	}
	return false; // boolean
}

dojo.string.startsWith = function(/*string*/str, /*string*/start, /*boolean*/ignoreCase){
// summary:
//	Returns true if 'str' starts with 'start'

	if(ignoreCase) {
		str = str.toLowerCase();
		start = start.toLowerCase();
	}
	return str.indexOf(start) == 0; // boolean
}

dojo.string.startsWithAny = function(/*string*/str /* , ... */){
// summary:
//	Returns true if 'str' starts with any of the arguments[2 -> n]

	for(var i = 1; i < arguments.length; i++) {
		if(dojo.string.startsWith(str, arguments[i])) {
			return true; // boolean
		}
	}
	return false; // boolean
}

dojo.string.has = function(/*string*/str /* , ... */) {
// summary:
//	Returns true if 'str' contains any of the arguments 2 -> n

	for(var i = 1; i < arguments.length; i++) {
		if(str.indexOf(arguments[i]) > -1){
			return true; // boolean
		}
	}
	return false; // boolean
}

dojo.string.normalizeNewlines = function(/*string*/text, /*string? (\n or \r)*/newlineChar){
// summary:
//	Changes occurences of CR and LF in text to CRLF, or if newlineChar is provided as '\n' or '\r',
//	substitutes newlineChar for occurrences of CR/LF and CRLF

	if (newlineChar == "\n"){
		text = text.replace(/\r\n/g, "\n");
		text = text.replace(/\r/g, "\n");
	} else if (newlineChar == "\r"){
		text = text.replace(/\r\n/g, "\r");
		text = text.replace(/\n/g, "\r");
	}else{
		text = text.replace(/([^\r])\n/g, "$1\r\n").replace(/\r([^\n])/g, "\r\n$1");
	}
	return text; // string
}

dojo.string.splitEscaped = function(/*string*/str, /*string of length=1*/charac){
// summary:
//	Splits 'str' into an array separated by 'charac', but skips characters escaped with a backslash

	var components = [];
	for (var i = 0, prevcomma = 0; i < str.length; i++){
		if (str.charAt(i) == '\\'){ i++; continue; }
		if (str.charAt(i) == charac){
			components.push(str.substring(prevcomma, i));
			prevcomma = i + 1;
		}
	}
	components.push(str.substr(prevcomma));
	return components; // array
}

__CPAN_DIR__ src/html
__CPAN_FILE__ src/html/util.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.util");
dojo.require("dojo.html.layout");

dojo.html.getElementWindow = function(/* HTMLElement */element){
	//	summary
	// 	Get the window object where the element is placed in.
	return dojo.html.getDocumentWindow( element.ownerDocument );	//	Window
}

dojo.html.getDocumentWindow = function(doc){
	//	summary
	// 	Get window object associated with document doc

	// With Safari, there is not wa to retrieve the window from the document, so we must fix it.
	if(dojo.render.html.safari && !doc._parentWindow){
		/*
			This is a Safari specific function that fix the reference to the parent
			window from the document object.
		*/

		var fix=function(win){
			win.document._parentWindow=win;
			for(var i=0; i<win.frames.length; i++){
				fix(win.frames[i]);
			}
		}
		fix(window.top);
	}

	//In some IE versions (at least 6.0), document.parentWindow does not return a
	//reference to the real window object (maybe a copy), so we must fix it as well
	//We use IE specific execScript to attach the real window reference to
	//document._parentWindow for later use
	if(dojo.render.html.ie && window !== document.parentWindow && !doc._parentWindow){
		/*
		In IE 6, only the variable "window" can be used to connect events (others
		may be only copies).
		*/
		doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
		//to prevent memory leak, unset it after use
		//another possibility is to add an onUnload handler which seems overkill to me (liucougar)
		var win = doc._parentWindow;
		doc._parentWindow = null;
		return win;	//	Window
	}

	return doc._parentWindow || doc.parentWindow || doc.defaultView;	//	Window
}

dojo.html.gravity = function(/* HTMLElement */node, /* DOMEvent */e){
	//	summary
	//	Calculates the mouse's direction of gravity relative to the centre
	//	of the given node.
	//	<p>
	//	If you wanted to insert a node into a DOM tree based on the mouse
	//	position you might use the following code:
	//	<pre>
	//	if (gravity(node, e) & gravity.NORTH) { [insert before]; }
	//	else { [insert after]; }
	//	</pre>
	//
	//	@param node The node
	//	@param e		The event containing the mouse coordinates
	//	@return		 The directions, NORTH or SOUTH and EAST or WEST. These
	//						 are properties of the function.
	node = dojo.byId(node);
	var mouse = dojo.html.getCursorPosition(e);

	with (dojo.html) {
		var absolute = getAbsolutePosition(node, true);
		var bb = getBorderBox(node);
		var nodecenterx = absolute.x + (bb.width / 2);
		var nodecentery = absolute.y + (bb.height / 2);
	}

	with (dojo.html.gravity) {
		return ((mouse.x < nodecenterx ? WEST : EAST) | (mouse.y < nodecentery ? NORTH : SOUTH));	//	integer
	}
}

dojo.html.gravity.NORTH = 1;
dojo.html.gravity.SOUTH = 1 << 1;
dojo.html.gravity.EAST = 1 << 2;
dojo.html.gravity.WEST = 1 << 3;

dojo.html.overElement = function(/* HTMLElement */element, /* DOMEvent */e){
	//	summary
	//	Returns whether the mouse is over the passed element.
	element = dojo.byId(element);
	var mouse = dojo.html.getCursorPosition(e);
	var bb = dojo.html.getBorderBox(element);
	var absolute = dojo.html.getAbsolutePosition(element, true, dojo.html.boxSizing.BORDER_BOX);
	var top = absolute.y;
	var bottom = top + bb.height;
	var left = absolute.x;
	var right = left + bb.width;

	return (mouse.x >= left
		&& mouse.x <= right
		&& mouse.y >= top
		&& mouse.y <= bottom
	);	//	boolean
}

dojo.html.renderedTextContent = function(/* HTMLElement */node){
	//	summary
	//	Attempts to return the text as it would be rendered, with the line breaks
	//	sorted out nicely. Unfinished.
	node = dojo.byId(node);
	var result = "";
	if (node == null) { return result; }
	for (var i = 0; i < node.childNodes.length; i++) {
		switch (node.childNodes[i].nodeType) {
			case 1: // ELEMENT_NODE
			case 5: // ENTITY_REFERENCE_NODE
				var display = "unknown";
				try {
					display = dojo.html.getStyle(node.childNodes[i], "display");
				} catch(E) {}
				switch (display) {
					case "block": case "list-item": case "run-in":
					case "table": case "table-row-group": case "table-header-group":
					case "table-footer-group": case "table-row": case "table-column-group":
					case "table-column": case "table-cell": case "table-caption":
						// TODO: this shouldn't insert double spaces on aligning blocks
						result += "\n";
						result += dojo.html.renderedTextContent(node.childNodes[i]);
						result += "\n";
						break;

					case "none": break;

					default:
						if(node.childNodes[i].tagName && node.childNodes[i].tagName.toLowerCase() == "br") {
							result += "\n";
						} else {
							result += dojo.html.renderedTextContent(node.childNodes[i]);
						}
						break;
				}
				break;
			case 3: // TEXT_NODE
			case 2: // ATTRIBUTE_NODE
			case 4: // CDATA_SECTION_NODE
				var text = node.childNodes[i].nodeValue;
				var textTransform = "unknown";
				try {
					textTransform = dojo.html.getStyle(node, "text-transform");
				} catch(E) {}
				switch (textTransform){
					case "capitalize":
						var words = text.split(' ');
						for(var i=0; i<words.length; i++){
							words[i] = words[i].charAt(0).toUpperCase() + words[i].substring(1);
						}
						text = words.join(" ");
						break;
					case "uppercase": text = text.toUpperCase(); break;
					case "lowercase": text = text.toLowerCase(); break;
					default: break; // leave as is
				}
				// TODO: implement
				switch (textTransform){
					case "nowrap": break;
					case "pre-wrap": break;
					case "pre-line": break;
					case "pre": break; // leave as is
					default:
						// remove whitespace and collapse first space
						text = text.replace(/\s+/, " ");
						if (/\s$/.test(result)) { text.replace(/^\s/, ""); }
						break;
				}
				result += text;
				break;
			default:
				break;
		}
	}
	return result;	//	string
}

dojo.html.createNodesFromText = function(/* string */txt, /* boolean? */trim){
	//	summary
	//	Attempts to create a set of nodes based on the structure of the passed text.
	if(trim) { txt = txt.replace(/^\s+|\s+$/g, ""); }

	var tn = dojo.doc().createElement("div");
	// tn.style.display = "none";
	tn.style.visibility= "hidden";
	dojo.body().appendChild(tn);
	var tableType = "none";
	if((/^<t[dh][\s\r\n>]/i).test(txt.replace(/^\s+/))) {
		txt = "<table><tbody><tr>" + txt + "</tr></tbody></table>";
		tableType = "cell";
	} else if((/^<tr[\s\r\n>]/i).test(txt.replace(/^\s+/))) {
		txt = "<table><tbody>" + txt + "</tbody></table>";
		tableType = "row";
	} else if((/^<(thead|tbody|tfoot)[\s\r\n>]/i).test(txt.replace(/^\s+/))) {
		txt = "<table>" + txt + "</table>";
		tableType = "section";
	}
	tn.innerHTML = txt;
	if(tn["normalize"]){
		tn.normalize();
	}

	var parent = null;
	switch(tableType) {
		case "cell":
			parent = tn.getElementsByTagName("tr")[0];
			break;
		case "row":
			parent = tn.getElementsByTagName("tbody")[0];
			break;
		case "section":
			parent = tn.getElementsByTagName("table")[0];
			break;
		default:
			parent = tn;
			break;
	}

	/* this doesn't make much sense, I'm assuming it just meant trim() so wrap was replaced with trim
	if(wrap){
		var ret = [];
		// start hack
		var fc = tn.firstChild;
		ret[0] = ((fc.nodeValue == " ")||(fc.nodeValue == "\t")) ? fc.nextSibling : fc;
		// end hack
		// tn.style.display = "none";
		dojo.body().removeChild(tn);
		return ret;
	}
	*/
	var nodes = [];
	for(var x=0; x<parent.childNodes.length; x++){
		nodes.push(parent.childNodes[x].cloneNode(true));
	}
	tn.style.display = "none"; // FIXME: why do we do this?
	dojo.body().removeChild(tn);
	return nodes;	//	array
}

dojo.html.placeOnScreen = function(
	/* HTMLElement */node,
	/* integer */desiredX,
	/* integer */desiredY,
	/* integer */padding,
	/* boolean? */hasScroll,
	/* string? */corners,
	/* boolean? */tryOnly
){
	//	summary
	//	Keeps 'node' in the visible area of the screen while trying to
	//	place closest to desiredX, desiredY. The input coordinates are
	//	expected to be the desired screen position, not accounting for
	//	scrolling. If you already accounted for scrolling, set 'hasScroll'
	//	to true. Set padding to either a number or array for [paddingX, paddingY]
	//	to put some buffer around the element you want to position.
	//	Set which corner(s) you want to bind to, such as
	//
	//	placeOnScreen(node, desiredX, desiredY, padding, hasScroll, "TR")
	//	placeOnScreen(node, [desiredX, desiredY], padding, hasScroll, ["TR", "BL"])
	//
	//	The desiredX/desiredY will be treated as the topleft(TL)/topright(TR) or
	//	BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
	//	and if a perfect match is found, it will be used. Otherwise, it goes through
	//	all of the specified corners, and choose the most appropriate one.
	//	By default, corner = ['TL'].
	//	If tryOnly is set to true, the node will not be moved to the place.
	//
	//	NOTE: node is assumed to be absolutely or relatively positioned.
	//
	//	Alternate call sig:
	//	 placeOnScreen(node, [x, y], padding, hasScroll)
	//
	//	Examples:
	//	 placeOnScreen(node, 100, 200)
	//	 placeOnScreen("myId", [800, 623], 5)
	//	 placeOnScreen(node, 234, 3284, [2, 5], true)

	// TODO: make this function have variable call sigs
	//	kes(node, ptArray, cornerArray, padding, hasScroll)
	//	kes(node, ptX, ptY, cornerA, cornerB, cornerC, paddingArray, hasScroll)
	if(desiredX instanceof Array || typeof desiredX == "array") {
		tryOnly = corners;
		corners = hasScroll;
		hasScroll = padding;
		padding = desiredY;
		desiredY = desiredX[1];
		desiredX = desiredX[0];
	}

	if(corners instanceof String || typeof corners == "string"){
		corners = corners.split(",");
	}

	if(!isNaN(padding)) {
		padding = [Number(padding), Number(padding)];
	} else if(!(padding instanceof Array || typeof padding == "array")) {
		padding = [0, 0];
	}

	var scroll = dojo.html.getScroll().offset;
	var view = dojo.html.getViewport();

	node = dojo.byId(node);
	var oldDisplay = node.style.display;
	node.style.display="";
	var bb = dojo.html.getBorderBox(node);
	var w = bb.width;
	var h = bb.height;
	node.style.display=oldDisplay;

	if(!(corners instanceof Array || typeof corners == "array")){
		corners = ['TL'];
	}

	var bestx, besty, bestDistance = Infinity, bestCorner;

	for(var cidex=0; cidex<corners.length; ++cidex){
		var corner = corners[cidex];
		var match = true;
		var tryX = desiredX - (corner.charAt(1)=='L' ? 0 : w) + padding[0]*(corner.charAt(1)=='L' ? 1 : -1);
		var tryY = desiredY - (corner.charAt(0)=='T' ? 0 : h) + padding[1]*(corner.charAt(0)=='T' ? 1 : -1);
		if(hasScroll) {
			tryX -= scroll.x;
			tryY -= scroll.y;
		}

		if(tryX < 0){
			tryX = 0;
			match = false;
		}

		if(tryY < 0){
			tryY = 0;
			match = false;
		}

		var x = tryX + w;
		if(x > view.width) {
			x = view.width - w;
			match = false;
		} else {
			x = tryX;
		}
		x = Math.max(padding[0], x) + scroll.x;

		var y = tryY + h;
		if(y > view.height) {
			y = view.height - h;
			match = false;
		} else {
			y = tryY;
		}
		y = Math.max(padding[1], y) + scroll.y;

		if(match){ //perfect match, return now
			bestx = x;
			besty = y;
			bestDistance = 0;
			bestCorner = corner;
			break;
		}else{
			//not perfect, find out whether it is better than the saved one
			var dist = Math.pow(x-tryX-scroll.x,2)+Math.pow(y-tryY-scroll.y,2);
			if(bestDistance > dist){
				bestDistance = dist;
				bestx = x;
				besty = y;
				bestCorner = corner;
			}
		}
	}

	if(!tryOnly){
		node.style.left = bestx + "px";
		node.style.top = besty + "px";
	}

	return { left: bestx, top: besty, x: bestx, y: besty, dist: bestDistance, corner:  bestCorner};	//	object
}

dojo.html.placeOnScreenPoint = function(node, desiredX, desiredY, padding, hasScroll) {
	dojo.deprecated("dojo.html.placeOnScreenPoint", "use dojo.html.placeOnScreen() instead", "0.5");
	return dojo.html.placeOnScreen(node, desiredX, desiredY, padding, hasScroll, ['TL', 'TR', 'BL', 'BR']);
}

dojo.html.placeOnScreenAroundElement = function(
	/* HTMLElement */node,
	/* HTMLElement */aroundNode,
	/* integer */padding,
	/* string? */aroundType,
	/* string? */aroundCorners,
	/* boolean? */tryOnly
){
	//	summary
	//	Like placeOnScreen, except it accepts aroundNode instead of x,y
	//	and attempts to place node around it. aroundType (see
	//	dojo.html.boxSizing in html/layout.js) determines which box of the
	//	aroundNode should be used to calculate the outer box.
	//	aroundCorners specify Which corner of aroundNode should be
	//	used to place the node => which corner(s) of node to use (see the
	//	corners parameter in dojo.html.placeOnScreen)
	//	aroundCorners: {'TL': 'BL', 'BL': 'TL'}

	var best, bestDistance=Infinity;
	aroundNode = dojo.byId(aroundNode);
	var oldDisplay = aroundNode.style.display;
	aroundNode.style.display="";
	var mb = dojo.html.getElementBox(aroundNode, aroundType);
	var aroundNodeW = mb.width;
	var aroundNodeH = mb.height;
	var aroundNodePos = dojo.html.getAbsolutePosition(aroundNode, true, aroundType);
	aroundNode.style.display=oldDisplay;

	for(var nodeCorner in aroundCorners){
		var pos, desiredX, desiredY;
		var corners = aroundCorners[nodeCorner];

		desiredX = aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW);
		desiredY = aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH);

		pos = dojo.html.placeOnScreen(node, desiredX, desiredY, padding, true, corners, true);
		if(pos.dist == 0){
			best = pos;
			break;
		}else{
			//not perfect, find out whether it is better than the saved one
			if(bestDistance > pos.dist){
				bestDistance = pos.dist;
				best = pos;
			}
		}
	}

	if(!tryOnly){
		node.style.left = best.left + "px";
		node.style.top = best.top + "px";
	}
	return best;	//	object
}

dojo.html.scrollIntoView = function(/* HTMLElement */node){
	//	summary
	//	Scroll the passed node into view, if it is not.
	if(!node){ return; }

	// don't rely on that node.scrollIntoView works just because the function is there
	// it doesnt work in Konqueror or Opera even though the function is there and probably
	// not safari either
	// dont like browser sniffs implementations but sometimes you have to use it
	if(dojo.render.html.ie){
		//only call scrollIntoView if there is a scrollbar for this menu,
		//otherwise, scrollIntoView will scroll the window scrollbar
		if(dojo.html.getBorderBox(node.parentNode).height < node.parentNode.scrollHeight){
			node.scrollIntoView(false);
		}
	}else if(dojo.render.html.mozilla){
		// IE, mozilla
		node.scrollIntoView(false);
	}else{
		var parent = node.parentNode;
		var parentBottom = parent.scrollTop + dojo.html.getBorderBox(parent).height;
		var nodeBottom = node.offsetTop + dojo.html.getMarginBox(node).height;
		if(parentBottom < nodeBottom){
			parent.scrollTop += (nodeBottom - parentBottom);
		}else if(parent.scrollTop > node.offsetTop){
			parent.scrollTop -= (parent.scrollTop - node.offsetTop);
		}
	}
}

__CPAN_FILE__ src/html/display.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.display");
dojo.require("dojo.html.style");

dojo.html._toggle = function(node, tester, setter){
	node = dojo.byId(node);
	setter(node, !tester(node));
	return tester(node);
}

dojo.html.show = function(/* HTMLElement */node){
	//	summary
	//	Show the passed element by reverting display property set by dojo.html.hide
	node = dojo.byId(node);
	if(dojo.html.getStyleProperty(node, 'display')=='none'){
		dojo.html.setStyle(node, 'display', (node.dojoDisplayCache||''));
		node.dojoDisplayCache = undefined;	// cannot use delete on a node in IE6
	}
}

dojo.html.hide = function(/* HTMLElement */node){
	//	summary
	//	Hide the passed element by setting display:none
	node = dojo.byId(node);
	if(typeof node["dojoDisplayCache"] == "undefined"){ // it could == '', so we cannot say !node.dojoDisplayCount
		var d = dojo.html.getStyleProperty(node, 'display')
		if(d!='none'){
			node.dojoDisplayCache = d;
		}
	}
	dojo.html.setStyle(node, 'display', 'none');
}

dojo.html.setShowing = function(/* HTMLElement */node, /* boolean? */showing){
	//	summary
	// Calls show() if showing is true, hide() otherwise
	dojo.html[(showing ? 'show' : 'hide')](node);
}

dojo.html.isShowing = function(/* HTMLElement */node){
	//	summary
	//	Returns whether the element is displayed or not.
	// FIXME: returns true if node is bad, isHidden would be easier to make correct
	return (dojo.html.getStyleProperty(node, 'display') != 'none');	//	boolean
}

dojo.html.toggleShowing = function(/* HTMLElement */node){
	//	summary
	// Call setShowing() on node with the complement of isShowing(), then return the new value of isShowing()
	return dojo.html._toggle(node, dojo.html.isShowing, dojo.html.setShowing);	//	boolean
}

// Simple mapping of tag names to display values
// FIXME: simplistic 
dojo.html.displayMap = { tr: '', td: '', th: '', img: 'inline', span: 'inline', input: 'inline', button: 'inline' };

dojo.html.suggestDisplayByTagName = function(/* HTMLElement */node){
	//	summary
	// Suggest a value for the display property that will show 'node' based on it's tag
	node = dojo.byId(node);
	if(node && node.tagName){
		var tag = node.tagName.toLowerCase();
		return (tag in dojo.html.displayMap ? dojo.html.displayMap[tag] : 'block');	//	string
	}
}

dojo.html.setDisplay = function(/* HTMLElement */node, /* string */display){
	//	summary
	// 	Sets the value of style.display to value of 'display' parameter if it is a string.
	// 	Otherwise, if 'display' is false, set style.display to 'none'.
	// 	Finally, set 'display' to a suggested display value based on the node's tag
	dojo.html.setStyle(node, 'display', ((display instanceof String || typeof display == "string") ? display : (display ? dojo.html.suggestDisplayByTagName(node) : 'none')));
}

dojo.html.isDisplayed = function(/* HTMLElement */node){
	//	summary
	// 	Is true if the the computed display style for node is not 'none'
	// 	FIXME: returns true if node is bad, isNotDisplayed would be easier to make correct
	return (dojo.html.getComputedStyle(node, 'display') != 'none');	//	boolean
}

dojo.html.toggleDisplay = function(/* HTMLElement */node){
	//	summary
	// 	Call setDisplay() on node with the complement of isDisplayed(), then
	// 	return the new value of isDisplayed()
	return dojo.html._toggle(node, dojo.html.isDisplayed, dojo.html.setDisplay);	//	boolean
}

dojo.html.setVisibility = function(/* HTMLElement */node, /* string */visibility){
	//	summary
	// 	Sets the value of style.visibility to value of 'visibility' parameter if it is a string.
	// 	Otherwise, if 'visibility' is false, set style.visibility to 'hidden'. Finally, set style.visibility to 'visible'.
	dojo.html.setStyle(node, 'visibility', ((visibility instanceof String || typeof visibility == "string") ? visibility : (visibility ? 'visible' : 'hidden')));
}

dojo.html.isVisible = function(/* HTMLElement */node){
	//	summary
	// 	Returns true if the the computed visibility style for node is not 'hidden'
	// 	FIXME: returns true if node is bad, isInvisible would be easier to make correct
	return (dojo.html.getComputedStyle(node, 'visibility') != 'hidden');	//	boolean
}

dojo.html.toggleVisibility = function(node){
	//	summary
	// Call setVisibility() on node with the complement of isVisible(), then return the new value of isVisible()
	return dojo.html._toggle(node, dojo.html.isVisible, dojo.html.setVisibility);	//	boolean
}

dojo.html.setOpacity = function(/* HTMLElement */node, /* float */opacity, /* boolean? */dontFixOpacity){
	//	summary
	//	Sets the opacity of node in a cross-browser way.
	//	float between 0.0 (transparent) and 1.0 (opaque)
	node = dojo.byId(node);
	var h = dojo.render.html;
	if(!dontFixOpacity){
		if( opacity >= 1.0){
			if(h.ie){
				dojo.html.clearOpacity(node);
				return;
			}else{
				opacity = 0.999999;
			}
		}else if( opacity < 0.0){ opacity = 0; }
	}
	if(h.ie){
		if(node.nodeName.toLowerCase() == "tr"){
			// FIXME: is this too naive? will we get more than we want?
			var tds = node.getElementsByTagName("td");
			for(var x=0; x<tds.length; x++){
				tds[x].style.filter = "Alpha(Opacity="+opacity*100+")";
			}
		}
		node.style.filter = "Alpha(Opacity="+opacity*100+")";
	}else if(h.moz){
		node.style.opacity = opacity; // ffox 1.0 directly supports "opacity"
		node.style.MozOpacity = opacity;
	}else if(h.safari){
		node.style.opacity = opacity; // 1.3 directly supports "opacity"
		node.style.KhtmlOpacity = opacity;
	}else{
		node.style.opacity = opacity;
	}
}

dojo.html.clearOpacity = function(/* HTMLElement */node){
	//	summary
	//	Clears any opacity setting on the passed element.
	node = dojo.byId(node);
	var ns = node.style;
	var h = dojo.render.html;
	if(h.ie){
		try {
			if( node.filters && node.filters.alpha ){
				ns.filter = ""; // FIXME: may get rid of other filter effects
			}
		} catch(e) {
			/*
			 * IE7 gives error if node.filters not set;
			 * don't know why or how to workaround (other than this)
			 */
		}
	}else if(h.moz){
		ns.opacity = 1;
		ns.MozOpacity = 1;
	}else if(h.safari){
		ns.opacity = 1;
		ns.KhtmlOpacity = 1;
	}else{
		ns.opacity = 1;
	}
}

dojo.html.getOpacity = function(/* HTMLElement */node){
	//	summary
	//	Returns the opacity of the passed element
	node = dojo.byId(node);
	var h = dojo.render.html;
	if(h.ie){
		var opac = (node.filters && node.filters.alpha &&
			typeof node.filters.alpha.opacity == "number"
			? node.filters.alpha.opacity : 100) / 100;
	}else{
		var opac = node.style.opacity || node.style.MozOpacity ||
			node.style.KhtmlOpacity || 1;
	}
	return opac >= 0.999999 ? 1.0 : Number(opac);	//	float
}

__CPAN_FILE__ src/html/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.common");
dojo.require("dojo.lang.common");
dojo.require("dojo.dom");

dojo.lang.mixin(dojo.html, dojo.dom);

dojo.html.body = function(){
	dojo.deprecated("dojo.html.body() moved to dojo.body()", "0.5");
	return dojo.body();
}

// FIXME: we are going to assume that we can throw any and every rendering
// engine into the IE 5.x box model. In Mozilla, we do this w/ CSS.
// Need to investigate for KHTML and Opera

dojo.html.getEventTarget = function(/* DOMEvent */evt){
	//	summary
	//	Returns the target of an event
	if(!evt) { evt = dojo.global().event || {} };
	var t = (evt.srcElement ? evt.srcElement : (evt.target ? evt.target : null));
	while((t)&&(t.nodeType!=1)){ t = t.parentNode; }
	return t;	//	HTMLElement
}

dojo.html.getViewport = function(){
	//	summary
	//	Returns the dimensions of the viewable area of a browser window
	var _window = dojo.global();
	var _document = dojo.doc();
	var w = 0;
	var h = 0;

	if(dojo.render.html.mozilla){
		// mozilla
		w = _document.documentElement.clientWidth;
		h = _window.innerHeight;
	}else if(!dojo.render.html.opera && _window.innerWidth){
		//in opera9, dojo.body().clientWidth should be used, instead
		//of window.innerWidth/document.documentElement.clientWidth
		//so we have to check whether it is opera
		w = _window.innerWidth;
		h = _window.innerHeight;
	} else if (!dojo.render.html.opera && dojo.exists(_document, "documentElement.clientWidth")){
		// IE6 Strict
		var w2 = _document.documentElement.clientWidth;
		// this lets us account for scrollbars
		if(!w || w2 && w2 < w) {
			w = w2;
		}
		h = _document.documentElement.clientHeight;
	} else if (dojo.body().clientWidth){
		// IE, Opera
		w = dojo.body().clientWidth;
		h = dojo.body().clientHeight;
	}
	return { width: w, height: h };	//	object
}

dojo.html.getScroll = function(){
	//	summary
	//	Returns the scroll position of the document
	var _window = dojo.global();
	var _document = dojo.doc();
	var top = _window.pageYOffset || _document.documentElement.scrollTop || dojo.body().scrollTop || 0;
	var left = _window.pageXOffset || _document.documentElement.scrollLeft || dojo.body().scrollLeft || 0;
	return { 
		top: top, 
		left: left, 
		offset:{ x: left, y: top }	//	note the change, NOT an Array with added properties. 
	};	//	object
}

dojo.html.getParentByType = function(/* HTMLElement */node, /* string */type) {
	//	summary
	//	Returns the first ancestor of node with tagName type.
	var _document = dojo.doc();
	var parent = dojo.byId(node);
	type = type.toLowerCase();
	while((parent)&&(parent.nodeName.toLowerCase()!=type)){
		if(parent==(_document["body"]||_document["documentElement"])){
			return null;
		}
		parent = parent.parentNode;
	}
	return parent;	//	HTMLElement
}

dojo.html.getAttribute = function(/* HTMLElement */node, /* string */attr){
	//	summary
	//	Returns the value of attribute attr from node.
	node = dojo.byId(node);
	// FIXME: need to add support for attr-specific accessors
	if((!node)||(!node.getAttribute)){
		// if(attr !== 'nwType'){
		//	alert("getAttr of '" + attr + "' with bad node"); 
		// }
		return null;
	}
	var ta = typeof attr == 'string' ? attr : new String(attr);

	// first try the approach most likely to succeed
	var v = node.getAttribute(ta.toUpperCase());
	if((v)&&(typeof v == 'string')&&(v!="")){ 
		return v;	//	string 
	}

	// try returning the attributes value, if we couldn't get it as a string
	if(v && v.value){ 
		return v.value;	//	string 
	}

	// this should work on Opera 7, but it's a little on the crashy side
	if((node.getAttributeNode)&&(node.getAttributeNode(ta))){
		return (node.getAttributeNode(ta)).value;	//	string
	}else if(node.getAttribute(ta)){
		return node.getAttribute(ta);	//	string
	}else if(node.getAttribute(ta.toLowerCase())){
		return node.getAttribute(ta.toLowerCase());	//	string
	}
	return null;	//	string
}
	
dojo.html.hasAttribute = function(/* HTMLElement */node, /* string */attr){
	//	summary
	//	Determines whether or not the specified node carries a value for the attribute in question.
	return dojo.html.getAttribute(dojo.byId(node), attr) ? true : false;	//	boolean
}
	
dojo.html.getCursorPosition = function(/* DOMEvent */e){
	//	summary
	//	Returns the mouse position relative to the document (not the viewport).
	//	For example, if you have a document that is 10000px tall,
	//	but your browser window is only 100px tall,
	//	if you scroll to the bottom of the document and call this function it
	//	will return {x: 0, y: 10000}
	//	NOTE: for events delivered via dojo.event.connect() and/or dojoAttachEvent (for widgets),
	//	you can just access evt.pageX and evt.pageY, rather than calling this function.
	e = e || dojo.global().event;
	var cursor = {x:0, y:0};
	if(e.pageX || e.pageY){
		cursor.x = e.pageX;
		cursor.y = e.pageY;
	}else{
		var de = dojo.doc().documentElement;
		var db = dojo.body();
		cursor.x = e.clientX + ((de||db)["scrollLeft"]) - ((de||db)["clientLeft"]);
		cursor.y = e.clientY + ((de||db)["scrollTop"]) - ((de||db)["clientTop"]);
	}
	return cursor;	//	object
}

dojo.html.isTag = function(/* HTMLElement */node) {
	//	summary
	//	Like dojo.dom.isTag, except case-insensitive
	node = dojo.byId(node);
	if(node && node.tagName) {
		for (var i=1; i<arguments.length; i++){
			if (node.tagName.toLowerCase()==String(arguments[i]).toLowerCase()){
				return String(arguments[i]).toLowerCase();	//	string
			}
		}
	}
	return "";	//	string
}

//define dojo.html.createExternalElement for IE to workaround the annoying activation "feature" in new IE
//details: http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/overview/activating_activex.asp
if(dojo.render.html.ie && !dojo.render.html.ie70){
	//only define createExternalElement for IE in none https to avoid "mixed content" warning dialog
	if(window.location.href.substr(0,6).toLowerCase() != "https:"){
		(function(){
			// FIXME: this seems not to work correctly on IE 7!!

			//The trick is to define a function in a script.src property:
			// <script src="javascript:'function createExternalElement(){...}'"></script>,
			//which will be treated as an external javascript file in IE
			var xscript = dojo.doc().createElement('script');
			xscript.src = "javascript:'dojo.html.createExternalElement=function(doc, tag){ return doc.createElement(tag); }'";
			dojo.doc().getElementsByTagName("head")[0].appendChild(xscript);
		})();
	}
}else{
	//for other browsers, simply use document.createElement
	//is enough
	dojo.html.createExternalElement = function(/* HTMLDocument */doc, /* string */tag){
		//	summary
		//	Creates an element in the HTML document, here for ActiveX activation workaround.
		return doc.createElement(tag);	//	HTMLElement
	}
}

dojo.html._callDeprecated = function(inFunc, replFunc, args, argName, retValue){
	dojo.deprecated("dojo.html." + inFunc,
					"replaced by dojo.html." + replFunc + "(" + (argName ? "node, {"+ argName + ": " + argName + "}" : "" ) + ")" + (retValue ? "." + retValue : ""), "0.5");
	var newArgs = [];
	if(argName){ var argsIn = {}; argsIn[argName] = args[1]; newArgs.push(args[0]); newArgs.push(argsIn); }
	else { newArgs = args }
	var ret = dojo.html[replFunc].apply(dojo.html, args);
	if(retValue){ return ret[retValue]; }
	else { return ret; }
}

dojo.html.getViewportWidth = function(){
	return dojo.html._callDeprecated("getViewportWidth", "getViewport", arguments, null, "width");
}
dojo.html.getViewportHeight = function(){
	return dojo.html._callDeprecated("getViewportHeight", "getViewport", arguments, null, "height");
}
dojo.html.getViewportSize = function(){
	return dojo.html._callDeprecated("getViewportSize", "getViewport", arguments);
}
dojo.html.getScrollTop = function(){
	return dojo.html._callDeprecated("getScrollTop", "getScroll", arguments, null, "top");
}
dojo.html.getScrollLeft = function(){
	return dojo.html._callDeprecated("getScrollLeft", "getScroll", arguments, null, "left");
}
dojo.html.getScrollOffset = function(){
	return dojo.html._callDeprecated("getScrollOffset", "getScroll", arguments, null, "offset");
}

__CPAN_FILE__ src/html/style.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.style");
dojo.require("dojo.uri.Uri");

dojo.html.getClass = function(/* HTMLElement */node){
	//	summary
	//	Returns the string value of the list of CSS classes currently assigned directly 
	//	to the node in question. Returns an empty string if no class attribute is found;
	node = dojo.byId(node);
	if(!node){ return ""; }
	var cs = "";
	if(node.className){
		cs = node.className;
	}else if(dojo.html.hasAttribute(node, "class")){
		cs = dojo.html.getAttribute(node, "class");
	}
	return cs.replace(/^\s+|\s+$/g, "");	//	string
}

dojo.html.getClasses = function(/* HTMLElement */node) {
	//	summary
	//	Returns an array of CSS classes currently assigned directly to the node in question. 
	//	Returns an empty array if no classes are found;
	var c = dojo.html.getClass(node);
	return (c == "") ? [] : c.split(/\s+/g);	//	array
}

dojo.html.hasClass = function(/* HTMLElement */node, /* string */classname){
	//	summary
	//	Returns whether or not the specified classname is a portion of the
	//	class list currently applied to the node. Does not cover cascaded
	//	styles, only classes directly applied to the node.
	return (new RegExp('(^|\\s+)'+classname+'(\\s+|$)')).test(dojo.html.getClass(node))	//	boolean
}

dojo.html.prependClass = function(/* HTMLElement */node, /* string */classStr){
	//	summary
	//	Adds the specified class to the beginning of the class list on the
	//	passed node. This gives the specified class the highest precidence
	//	when style cascading is calculated for the node. Returns true or
	//	false; indicating success or failure of the operation, respectively.
	classStr += " " + dojo.html.getClass(node);
	return dojo.html.setClass(node, classStr);	//	boolean
}

dojo.html.addClass = function(/* HTMLElement */node, /* string */classStr){
	//	summary
	//	Adds the specified class to the end of the class list on the
	//	passed &node;. Returns &true; or &false; indicating success or failure.
	if (dojo.html.hasClass(node, classStr)) {
	  return false;
	}
	classStr = (dojo.html.getClass(node) + " " + classStr).replace(/^\s+|\s+$/g,"");
	return dojo.html.setClass(node, classStr);	//	boolean
}

dojo.html.setClass = function(/* HTMLElement */node, /* string */classStr){
	//	summary
	//	Clobbers the existing list of classes for the node, replacing it with
	//	the list given in the 2nd argument. Returns true or false
	//	indicating success or failure.
	node = dojo.byId(node);
	var cs = new String(classStr);
	try{
		if(typeof node.className == "string"){
			node.className = cs;
		}else if(node.setAttribute){
			node.setAttribute("class", classStr);
			node.className = cs;
		}else{
			return false;
		}
	}catch(e){
		dojo.debug("dojo.html.setClass() failed", e);
	}
	return true;
}

dojo.html.removeClass = function(/* HTMLElement */node, /* string */classStr, /* boolean? */allowPartialMatches){
	//	summary
	//	Removes the className from the node;. Returns true or false indicating success or failure.
	try{
		if (!allowPartialMatches) {
			var newcs = dojo.html.getClass(node).replace(new RegExp('(^|\\s+)'+classStr+'(\\s+|$)'), "$1$2");
		} else {
			var newcs = dojo.html.getClass(node).replace(classStr,'');
		}
		dojo.html.setClass(node, newcs);
	}catch(e){
		dojo.debug("dojo.html.removeClass() failed", e);
	}
	return true;	//	boolean
}

dojo.html.replaceClass = function(/* HTMLElement */node, /* string */newClass, /* string */oldClass) {
	//	summary
	//	Replaces 'oldClass' and adds 'newClass' to node
	dojo.html.removeClass(node, oldClass);
	dojo.html.addClass(node, newClass);
}

// Enum type for getElementsByClass classMatchType arg:
dojo.html.classMatchType = {
	ContainsAll : 0, // all of the classes are part of the node's class (default)
	ContainsAny : 1, // any of the classes are part of the node's class
	IsOnly : 2 // only all of the classes are part of the node's class
}


dojo.html.getElementsByClass = function(
	/* string */classStr, 
	/* HTMLElement? */parent, 
	/* string? */nodeType, 
	/* integer? */classMatchType, 
	/* boolean? */useNonXpath
){
	//	summary
	//	Returns an array of nodes for the given classStr, children of a
	//	parent, and optionally of a certain nodeType
	// FIXME: temporarily set to false because of several dojo tickets related
	// to the xpath version not working consistently in firefox.
	useNonXpath = false;
	var _document = dojo.doc();
	parent = dojo.byId(parent) || _document;
	var classes = classStr.split(/\s+/g);
	var nodes = [];
	if( classMatchType != 1 && classMatchType != 2 ) classMatchType = 0; // make it enum
	var reClass = new RegExp("(\\s|^)((" + classes.join(")|(") + "))(\\s|$)");
	var srtLength = classes.join(" ").length;
	var candidateNodes = [];
	
	if(!useNonXpath && _document.evaluate) { // supports dom 3 xpath
		var xpath = ".//" + (nodeType || "*") + "[contains(";
		if(classMatchType != dojo.html.classMatchType.ContainsAny){
			xpath += "concat(' ',@class,' '), ' " +
			classes.join(" ') and contains(concat(' ',@class,' '), ' ") +
			" ')";
			if (classMatchType == 2) {
				xpath += " and string-length(@class)="+srtLength+"]";
			}else{
				xpath += "]";
			}
		}else{
			xpath += "concat(' ',@class,' '), ' " +
			classes.join(" ') or contains(concat(' ',@class,' '), ' ") +
			" ')]";
		}
		var xpathResult = _document.evaluate(xpath, parent, null, XPathResult.ANY_TYPE, null);
		var result = xpathResult.iterateNext();
		while(result){
			try{
				candidateNodes.push(result);
				result = xpathResult.iterateNext();
			}catch(e){ break; }
		}
		return candidateNodes;	//	NodeList
	}else{
		if(!nodeType){
			nodeType = "*";
		}
		candidateNodes = parent.getElementsByTagName(nodeType);

		var node, i = 0;
		outer:
		while(node = candidateNodes[i++]){
			var nodeClasses = dojo.html.getClasses(node);
			if(nodeClasses.length == 0){ continue outer; }
			var matches = 0;
	
			for(var j = 0; j < nodeClasses.length; j++){
				if(reClass.test(nodeClasses[j])){
					if(classMatchType == dojo.html.classMatchType.ContainsAny){
						nodes.push(node);
						continue outer;
					}else{
						matches++;
					}
				}else{
					if(classMatchType == dojo.html.classMatchType.IsOnly){
						continue outer;
					}
				}
			}
	
			if(matches == classes.length){
				if(	(classMatchType == dojo.html.classMatchType.IsOnly)&&
					(matches == nodeClasses.length)){
					nodes.push(node);
				}else if(classMatchType == dojo.html.classMatchType.ContainsAll){
					nodes.push(node);
				}
			}
		}
		return nodes;	//	NodeList
	}
}
dojo.html.getElementsByClassName = dojo.html.getElementsByClass;

dojo.html.toCamelCase = function(/* string */selector){
	//	summary
	//	Translates a CSS selector string to a camel-cased one.
	var arr = selector.split('-'), cc = arr[0];
	for(var i = 1; i < arr.length; i++) {
		cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
	}
	return cc;	//	string
}

dojo.html.toSelectorCase = function(/* string */selector){
	//	summary
	//	Translates a camel cased string to a selector cased one.
	return selector.replace(/([A-Z])/g, "-$1" ).toLowerCase();	//	string
}

dojo.html.getComputedStyle = function(/* HTMLElement */node, /* string */cssSelector, /* integer? */inValue){
	//	summary
	//	Returns the computed style of cssSelector on node.
	node = dojo.byId(node);
	// cssSelector may actually be in camel case, so force selector version
	var cssSelector = dojo.html.toSelectorCase(cssSelector);
	var property = dojo.html.toCamelCase(cssSelector);
	if(!node || !node.style){
		return inValue;			
	} else if (document.defaultView && dojo.html.isDescendantOf(node, node.ownerDocument)){ // W3, gecko, KHTML
		try{
			// mozilla segfaults when margin-* and node is removed from doc
			// FIXME: need to figure out a if there is quicker workaround
			var cs = document.defaultView.getComputedStyle(node, "");
			if(cs){
				return cs.getPropertyValue(cssSelector);	//	integer
			} 
		}catch(e){ // reports are that Safari can throw an exception above
			if(node.style.getPropertyValue){ // W3
				return node.style.getPropertyValue(cssSelector);	//	integer
			} else {
				return inValue;	//	integer
			}
		}
	} else if(node.currentStyle){ // IE
		return node.currentStyle[property];	//	integer
	}
	
	if(node.style.getPropertyValue){ // W3
		return node.style.getPropertyValue(cssSelector);	//	integer
	}else{
		return inValue;	//	integer
	}
}

dojo.html.getStyleProperty = function(/* HTMLElement */node, /* string */cssSelector){
	//	summary
	//	Returns the value of the passed style
	node = dojo.byId(node);
	return (node && node.style ? node.style[dojo.html.toCamelCase(cssSelector)] : undefined);	//	string
}

dojo.html.getStyle = function(/* HTMLElement */node, /* string */cssSelector){
	//	summary
	//	Returns the computed value of the passed style
	var value = dojo.html.getStyleProperty(node, cssSelector);
	return (value ? value : dojo.html.getComputedStyle(node, cssSelector));	//	string || integer
}

dojo.html.setStyle = function(/* HTMLElement */node, /* string */cssSelector, /* string */value){
	//	summary
	//	Set the value of passed style on node
	node = dojo.byId(node);
	if(node && node.style){
		var camelCased = dojo.html.toCamelCase(cssSelector);
		node.style[camelCased] = value;
	}
}

dojo.html.setStyleText = function (/* HTMLElement */target, /* string */text) {
	//	summary
	//	Try to set the entire cssText property of the passed target; equiv of setting style attribute.
	try {
	 	target.style.cssText = text;
	} catch (e) {
		target.setAttribute("style", text);
	}
}

dojo.html.copyStyle = function(/* HTMLElement */target, /* HTMLElement */source){
	//	summary
	// work around for opera which doesn't have cssText, and for IE which fails on setAttribute 
	if(!source.style.cssText){ 
		target.setAttribute("style", source.getAttribute("style")); 
	}else{
		target.style.cssText = source.style.cssText; 
	}
	dojo.html.addClass(target, dojo.html.getClass(source));
}

dojo.html.getUnitValue = function(/* HTMLElement */node, /* string */cssSelector, /* boolean? */autoIsZero){
	//	summary
	//	Get the value of passed selector, with the specific units used
	var s = dojo.html.getComputedStyle(node, cssSelector);
	if((!s)||((s == 'auto')&&(autoIsZero))){ 
		return { value: 0, units: 'px' };	//	object 
	}
	// FIXME: is regex inefficient vs. parseInt or some manual test? 
	var match = s.match(/(\-?[\d.]+)([a-z%]*)/i);
	if (!match){return dojo.html.getUnitValue.bad;}
	return { value: Number(match[1]), units: match[2].toLowerCase() };	//	object
}
dojo.html.getUnitValue.bad = { value: NaN, units: '' };

dojo.html.getPixelValue = function(/* HTMLElement */node, /* string */cssSelector, /* boolean? */autoIsZero){
	//	summary
	//	Get the value of passed selector in pixels.
	var result = dojo.html.getUnitValue(node, cssSelector, autoIsZero);
	// FIXME: there is serious debate as to whether or not this is the right solution
	if(isNaN(result.value)){ 
		return 0; //	integer 
	}	
	// FIXME: code exists for converting other units to px (see Dean Edward's IE7) 
	// but there are cross-browser complexities
	if((result.value)&&(result.units != 'px')){ 
		return NaN;	//	integer 
	}
	return result.value;	//	integer
}

dojo.html.setPositivePixelValue = function(/* HTMLElement */node, /* string */selector, /* integer */value){
	//	summary
	//	Attempt to set the value of selector on node as a positive pixel value.
	if(isNaN(value)){return false;}
	node.style[selector] = Math.max(0, value) + 'px'; 
	return true;	//	boolean
}

dojo.html.styleSheet = null;

// FIXME: this is a really basic stub for adding and removing cssRules, but
// it assumes that you know the index of the cssRule that you want to add 
// or remove, making it less than useful.  So we need something that can 
// search for the selector that you you want to remove.
dojo.html.insertCssRule = function(/* string */selector, /* string */declaration, /* integer? */index) {
	//	summary
	//	Attempt to insert declaration as selector on the internal stylesheet; if index try to set it there.
	if (!dojo.html.styleSheet) {
		if (document.createStyleSheet) { // IE
			dojo.html.styleSheet = document.createStyleSheet();
		} else if (document.styleSheets[0]) { // rest
			// FIXME: should create a new style sheet here
			// fall back on an exsiting style sheet
			dojo.html.styleSheet = document.styleSheets[0];
		} else { 
			return null;	//	integer 
		} // fail
	}

	if (arguments.length < 3) { // index may == 0
		if (dojo.html.styleSheet.cssRules) { // W3
			index = dojo.html.styleSheet.cssRules.length;
		} else if (dojo.html.styleSheet.rules) { // IE
			index = dojo.html.styleSheet.rules.length;
		} else { 
			return null;	//	integer 
		} // fail
	}

	if (dojo.html.styleSheet.insertRule) { // W3
		var rule = selector + " { " + declaration + " }";
		return dojo.html.styleSheet.insertRule(rule, index);	//	integer
	} else if (dojo.html.styleSheet.addRule) { // IE
		return dojo.html.styleSheet.addRule(selector, declaration, index);	//	integer
	} else { 
		return null; // integer
	} // fail
}

dojo.html.removeCssRule = function(/* integer? */index){
	//	summary
	//	Attempt to remove the rule at index.
	if(!dojo.html.styleSheet){
		dojo.debug("no stylesheet defined for removing rules");
		return false;
	}
	if(dojo.render.html.ie){
		if(!index){
			index = dojo.html.styleSheet.rules.length;
			dojo.html.styleSheet.removeRule(index);
		}
	}else if(document.styleSheets[0]){
		if(!index){
			index = dojo.html.styleSheet.cssRules.length;
		}
		dojo.html.styleSheet.deleteRule(index);
	}
	return true;	//	boolean
}

dojo.html._insertedCssFiles = []; // cache container needed because IE reformats cssText when added to DOM
dojo.html.insertCssFile = function(/* string */URI, /* HTMLDocument? */doc, /* boolean? */checkDuplicates, /* boolean */fail_ok){
	//	summary
	// calls css by XmlHTTP and inserts it into DOM as <style [widgetType="widgetType"]> *downloaded cssText*</style>
	if(!URI){ return; }
	if(!doc){ doc = document; }
	var cssStr = dojo.hostenv.getText(URI, false, fail_ok);
  if(cssStr===null){ return; } 
	cssStr = dojo.html.fixPathsInCssText(cssStr, URI);

	if(checkDuplicates){
		var idx = -1, node, ent = dojo.html._insertedCssFiles;
		for(var i = 0; i < ent.length; i++){
			if((ent[i].doc == doc) && (ent[i].cssText == cssStr)){
				idx = i; node = ent[i].nodeRef;
				break;
			}
		}
		// make sure we havent deleted our node
		if(node){
			var styles = doc.getElementsByTagName("style");
			for(var i = 0; i < styles.length; i++){
				if(styles[i] == node){
					return;
				}
			}
			// delete this entry
			dojo.html._insertedCssFiles.shift(idx, 1);
		}
	}

	var style = dojo.html.insertCssText(cssStr);
	dojo.html._insertedCssFiles.push({'doc': doc, 'cssText': cssStr, 'nodeRef': style});

	// insert custom attribute ex dbgHref="../foo.css" usefull when debugging in DOM inspectors, no?
	if(style && djConfig.isDebug){
		style.setAttribute("dbgHref", URI);
	}
	return style;	//	HTMLStyleElement
}

dojo.html.insertCssText = function(/* string */cssStr, /* HTMLDocument? */doc, /* string? */URI){
	//	summary
	//	Attempt to insert CSS rules into the document through inserting a style element
	// DomNode Style  = insertCssText(String ".dojoMenu {color: green;}"[, DomDoc document, dojo.uri.Uri Url ])
	if(!cssStr){ 
		return; //	HTMLStyleElement
	}
	if(!doc){ doc = document; }
	if(URI){// fix paths in cssStr
		cssStr = dojo.html.fixPathsInCssText(cssStr, URI);
	}
	var style = doc.createElement("style");
	style.setAttribute("type", "text/css");
	// IE is b0rken enough to require that we add the element to the doc
	// before changing it's properties
	var head = doc.getElementsByTagName("head")[0];
	if(!head){ // must have a head tag 
		dojo.debug("No head tag in document, aborting styles");
		return;	//	HTMLStyleElement
	}else{
		head.appendChild(style);
	}
	if(style.styleSheet){// IE
		style.styleSheet.cssText = cssStr;
	}else{ // w3c
		var cssText = doc.createTextNode(cssStr);
		style.appendChild(cssText);
	}
	return style;	//	HTMLStyleElement
}

dojo.html.fixPathsInCssText = function(/* string */cssStr, /* string */URI){
	//	summary
	// usage: cssText comes from dojoroot/src/widget/templates/Foobar.css
	// 	it has .dojoFoo { background-image: url(images/bar.png);} then uri should point to dojoroot/src/widget/templates/
	function iefixPathsInCssText() {
		var regexIe = /AlphaImageLoader\(src\=['"]([\t\s\w()\/.\\'"-:#=&?~]*)['"]/;
		while(match = regexIe.exec(cssStr)){
			url = match[1].replace(regexTrim, "$2");
			if(!regexProtocol.exec(url)){
				url = (new dojo.uri.Uri(URI, url).toString());
			}
			str += cssStr.substring(0, match.index) + "AlphaImageLoader(src='" + url + "'";
			cssStr = cssStr.substr(match.index + match[0].length);
		}
		return str + cssStr;
	}

	if(!cssStr || !URI){ return; }
	var match, str = "", url = "";
	var regex = /url\(\s*([\t\s\w()\/.\\'"-:#=&?]+)\s*\)/;
	var regexProtocol = /(file|https?|ftps?):\/\//;
	var regexTrim = /^[\s]*(['"]?)([\w()\/.\\'"-:#=&?]*)\1[\s]*?$/;
	if (dojo.render.html.ie55 || dojo.render.html.ie60) {
		cssStr = iefixPathsInCssText();
	}
	while(match = regex.exec(cssStr)){
		url = match[1].replace(regexTrim, "$2");
		if(!regexProtocol.exec(url)){
			url = (new dojo.uri.Uri(URI, url).toString());
		}
		str += cssStr.substring(0, match.index) + "url(" + url + ")";
		cssStr = cssStr.substr(match.index + match[0].length);
	}
	return str + cssStr;	//	string
}

dojo.html.setActiveStyleSheet = function(/* string */title){
	//	summary
	//	Activate style sheet with specified title.
	var i = 0, a, els = dojo.doc().getElementsByTagName("link");
	while (a = els[i++]) {
		if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")){
			a.disabled = true;
			if (a.getAttribute("title") == title) { a.disabled = false; }
		}
	}
}

dojo.html.getActiveStyleSheet = function(){
	//	summary
	//	return the title of the currently active stylesheet
	var i = 0, a, els = dojo.doc().getElementsByTagName("link");
	while (a = els[i++]) {
		if (a.getAttribute("rel").indexOf("style") != -1 
			&& a.getAttribute("title") 
			&& !a.disabled
		){
			return a.getAttribute("title");	//	string 
		}
	}
	return null;	//	string
}

dojo.html.getPreferredStyleSheet = function(){
	//	summary
	//	Return the preferred stylesheet title (i.e. link without alt attribute)
	var i = 0, a, els = dojo.doc().getElementsByTagName("link");
	while (a = els[i++]) {
		if(a.getAttribute("rel").indexOf("style") != -1
			&& a.getAttribute("rel").indexOf("alt") == -1
			&& a.getAttribute("title")
		){ 
			return a.getAttribute("title"); 	//	string
		}
	}
	return null;	//	string
}

dojo.html.applyBrowserClass = function(/* HTMLElement */node){
	//	summary
	//	Applies pre-set class names based on browser & version to the passed node.
	//	Modified version of Morris' CSS hack.
	var drh=dojo.render.html;
	var classes = {
		dj_ie: drh.ie,
		dj_ie55: drh.ie55,
		dj_ie6: drh.ie60,
		dj_ie7: drh.ie70,
		dj_iequirks: drh.ie && drh.quirks,
		dj_opera: drh.opera,
		dj_opera8: drh.opera && (Math.floor(dojo.render.version)==8),
		dj_opera9: drh.opera && (Math.floor(dojo.render.version)==9),
		dj_khtml: drh.khtml,
		dj_safari: drh.safari,
		dj_gecko: drh.mozilla
	}; // no dojo unsupported browsers
	for(var p in classes){
		if(classes[p]){
			dojo.html.addClass(node, p);
		}
	}
};

__CPAN_FILE__ src/html/color.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.html.style");
dojo.provide("dojo.html.color");

dojo.require("dojo.gfx.color");
dojo.require("dojo.lang.common");

dojo.html.getBackgroundColor = function(/* HTMLElement */node){
	//	summary
	//	returns the background color of the passed node as a 32-bit color (RGBA)
	node = dojo.byId(node);
	var color;
	do{
		color = dojo.html.getStyle(node, "background-color");
		// Safari doesn't say "transparent"
		if(color.toLowerCase() == "rgba(0, 0, 0, 0)") { color = "transparent"; }
		if(node == document.getElementsByTagName("body")[0]) { node = null; break; }
		node = node.parentNode;
	}while(node && dojo.lang.inArray(["transparent", ""], color));
	if(color == "transparent"){
		color = [255, 255, 255, 0];
	}else{
		color = dojo.gfx.color.extractRGB(color);
	}
	return color;	//	array
}

__CPAN_FILE__ src/html/layout.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.layout");

dojo.require("dojo.html.common");
dojo.require("dojo.html.style");
dojo.require("dojo.html.display");

dojo.html.sumAncestorProperties = function(/* HTMLElement */node, /* string */prop){
	//	summary
	//	Returns the sum of the passed property on all ancestors of node.
	node = dojo.byId(node);
	if(!node){ return 0; } // FIXME: throw an error?
	
	var retVal = 0;
	while(node){
		if(dojo.html.getComputedStyle(node, 'position') == 'fixed'){
			return 0;
		}
		var val = node[prop];
		if(val){
			retVal += val - 0;
			if(node==dojo.body()){ break; }// opera and khtml #body & #html has the same values, we only need one value
		}
		node = node.parentNode;
	}
	return retVal;	//	integer
}

dojo.html.setStyleAttributes = function(/* HTMLElement */node, /* string */attributes) { 
	//	summary
	//	allows a dev to pass a string similar to what you'd pass in style="", and apply it to a node.
	node = dojo.byId(node);
	var splittedAttribs=attributes.replace(/(;)?\s*$/, "").split(";"); 
	for(var i=0; i<splittedAttribs.length; i++){ 
		var nameValue=splittedAttribs[i].split(":"); 
		var name=nameValue[0].replace(/\s*$/, "").replace(/^\s*/, "").toLowerCase();
		var value=nameValue[1].replace(/\s*$/, "").replace(/^\s*/, "");
		switch(name){
			case "opacity":
				dojo.html.setOpacity(node, value); 
				break; 
			case "content-height":
				dojo.html.setContentBox(node, {height: value}); 
				break; 
			case "content-width":
				dojo.html.setContentBox(node, {width: value}); 
				break; 
			case "outer-height":
				dojo.html.setMarginBox(node, {height: value}); 
				break; 
			case "outer-width":
				dojo.html.setMarginBox(node, {width: value}); 
				break; 
			default:
				node.style[dojo.html.toCamelCase(name)]=value; 
		}
	} 
}

dojo.html.boxSizing = {
	MARGIN_BOX: "margin-box",
	BORDER_BOX: "border-box",
	PADDING_BOX: "padding-box",
	CONTENT_BOX: "content-box"
};

dojo.html.getAbsolutePosition = dojo.html.abs = function(/* HTMLElement */node, /* boolean? */includeScroll, /* string? */boxType){
	//	summary
	//	Gets the absolute position of the passed element based on the document itself.
	node = dojo.byId(node, node.ownerDocument);
	var ret = {
		x: 0,
		y: 0
	};

	var bs = dojo.html.boxSizing;
	if(!boxType) { boxType = bs.CONTENT_BOX; }
	var nativeBoxType = 2; //BORDER box
	var targetBoxType;
	switch(boxType){
		case bs.MARGIN_BOX:
			targetBoxType = 3;
			break;
		case bs.BORDER_BOX:
			targetBoxType = 2;
			break;
		case bs.PADDING_BOX:
		default:
			targetBoxType = 1;
			break;
		case bs.CONTENT_BOX:
			targetBoxType = 0;
			break;
	}

	var h = dojo.render.html;
	var db = document["body"]||document["documentElement"];

	if(h.ie){
		with(node.getBoundingClientRect()){
			ret.x = left-2;
			ret.y = top-2;
		}
	}else if(document.getBoxObjectFor){
		// mozilla
		nativeBoxType = 1; //getBoxObjectFor return padding box coordinate
		try{
			var bo = document.getBoxObjectFor(node);
			ret.x = bo.x - dojo.html.sumAncestorProperties(node, "scrollLeft");
			ret.y = bo.y - dojo.html.sumAncestorProperties(node, "scrollTop");
		}catch(e){
			// squelch
		}
	}else{
		if(node["offsetParent"]){
			var endNode;
			// in Safari, if the node is an absolutely positioned child of
			// the body and the body has a margin the offset of the child
			// and the body contain the body's margins, so we need to end
			// at the body
			if(	(h.safari)&&
				(node.style.getPropertyValue("position") == "absolute")&&
				(node.parentNode == db)){
				endNode = db;
			}else{
				endNode = db.parentNode;
			}

			//TODO: set correct nativeBoxType for safari/konqueror

			if(node.parentNode != db){
				var nd = node;
				if(dojo.render.html.opera){ nd = db; }
				ret.x -= dojo.html.sumAncestorProperties(nd, "scrollLeft");
				ret.y -= dojo.html.sumAncestorProperties(nd, "scrollTop");
			}
			var curnode = node;
			do{
				var n = curnode["offsetLeft"];
				//FIXME: ugly hack to workaround the submenu in 
				//popupmenu2 does not shown up correctly in opera. 
				//Someone have a better workaround?
				if(!h.opera || n>0){
					ret.x += isNaN(n) ? 0 : n;
				}
				var m = curnode["offsetTop"];
				ret.y += isNaN(m) ? 0 : m;
				curnode = curnode.offsetParent;
			}while((curnode != endNode)&&(curnode != null));
		}else if(node["x"]&&node["y"]){
			ret.x += isNaN(node.x) ? 0 : node.x;
			ret.y += isNaN(node.y) ? 0 : node.y;
		}
	}

	// account for document scrolling!
	if(includeScroll){
		var scroll = dojo.html.getScroll();
		ret.y += scroll.top;
		ret.x += scroll.left;
	}

	var extentFuncArray=[dojo.html.getPaddingExtent, dojo.html.getBorderExtent, dojo.html.getMarginExtent];
	if(nativeBoxType > targetBoxType){
		for(var i=targetBoxType;i<nativeBoxType;++i){
			ret.y += extentFuncArray[i](node, 'top');
			ret.x += extentFuncArray[i](node, 'left');
		}
	}else if(nativeBoxType < targetBoxType){
		for(var i=targetBoxType;i>nativeBoxType;--i){
			ret.y -= extentFuncArray[i-1](node, 'top');
			ret.x -= extentFuncArray[i-1](node, 'left');
		}
	}
	ret.top = ret.y;
	ret.left = ret.x;
	return ret;	//	object
}

dojo.html.isPositionAbsolute = function(/* HTMLElement */node){
	//	summary
	//	Returns true if the element is absolutely positioned.
	return (dojo.html.getComputedStyle(node, 'position') == 'absolute');	//	boolean
}

dojo.html._sumPixelValues = function(/* HTMLElement */node, selectors, autoIsZero){
	var total = 0;
	for(var x=0; x<selectors.length; x++){
		total += dojo.html.getPixelValue(node, selectors[x], autoIsZero);
	}
	return total;
}

dojo.html.getMargin = function(/* HTMLElement */node){
	//	summary
	//	Returns the width and height of the passed node's margin
	return {
		width: dojo.html._sumPixelValues(node, ["margin-left", "margin-right"], (dojo.html.getComputedStyle(node, 'position') == 'absolute')),
		height: dojo.html._sumPixelValues(node, ["margin-top", "margin-bottom"], (dojo.html.getComputedStyle(node, 'position') == 'absolute'))
	};	//	object
}

dojo.html.getBorder = function(/* HTMLElement */node){
	//	summary
	//	Returns the width and height of the passed node's border
	return {
		width: dojo.html.getBorderExtent(node, 'left') + dojo.html.getBorderExtent(node, 'right'),
		height: dojo.html.getBorderExtent(node, 'top') + dojo.html.getBorderExtent(node, 'bottom')
	};	//	object
}

dojo.html.getBorderExtent = function(/* HTMLElement */node, /* string */side){
	//	summary
	//	returns the width of the requested border
	return (dojo.html.getStyle(node, 'border-' + side + '-style') == 'none' ? 0 : dojo.html.getPixelValue(node, 'border-' + side + '-width'));	// integer
}

dojo.html.getMarginExtent = function(/* HTMLElement */node, /* string */side){
	//	summary
	//	returns the width of the requested margin
	return dojo.html._sumPixelValues(node, ["margin-" + side], dojo.html.isPositionAbsolute(node));	//	integer
}

dojo.html.getPaddingExtent = function(/* HTMLElement */node, /* string */side){
	//	summary
	//	Returns the width of the requested padding 
	return dojo.html._sumPixelValues(node, ["padding-" + side], true);	//	integer
}

dojo.html.getPadding = function(/* HTMLElement */node){
	//	summary
	//	Returns the width and height of the passed node's padding
	return {
		width: dojo.html._sumPixelValues(node, ["padding-left", "padding-right"], true),
		height: dojo.html._sumPixelValues(node, ["padding-top", "padding-bottom"], true)
	};	//	object
}

dojo.html.getPadBorder = function(/* HTMLElement */node){
	//	summary
	//	Returns the width and height of the passed node's padding and border
	var pad = dojo.html.getPadding(node);
	var border = dojo.html.getBorder(node);
	return { width: pad.width + border.width, height: pad.height + border.height };	//	object
}

dojo.html.getBoxSizing = function(/* HTMLElement */node){
	//	summary
	//	Returns which box model the passed element is working with
	var h = dojo.render.html;
	var bs = dojo.html.boxSizing;
	if((h.ie)||(h.opera)){ 
		var cm = document["compatMode"];
		if((cm == "BackCompat")||(cm == "QuirksMode")){ 
			return bs.BORDER_BOX; 	//	string
		}else{
			return bs.CONTENT_BOX; 	//	string
		}
	}else{
		if(arguments.length == 0){ node = document.documentElement; }
		var sizing = dojo.html.getStyle(node, "-moz-box-sizing");
		if(!sizing){ sizing = dojo.html.getStyle(node, "box-sizing"); }
		return (sizing ? sizing : bs.CONTENT_BOX);	//	string
	}
}

dojo.html.isBorderBox = function(/* HTMLElement */node){
	//	summary
	//	returns whether the passed element is using border box sizing or not.
	return (dojo.html.getBoxSizing(node) == dojo.html.boxSizing.BORDER_BOX);	//	boolean
}

dojo.html.getBorderBox = function(/* HTMLElement */node){
	//	summary
	//	Returns the dimensions of the passed element based on border-box sizing.
	node = dojo.byId(node);
	return { width: node.offsetWidth, height: node.offsetHeight };	//	object
}

dojo.html.getPaddingBox = function(/* HTMLElement */node){
	//	summary
	//	Returns the dimensions of the padding box (see http://www.w3.org/TR/CSS21/box.html)
	var box = dojo.html.getBorderBox(node);
	var border = dojo.html.getBorder(node);
	return {
		width: box.width - border.width,
		height:box.height - border.height
	};	//	object
}

dojo.html.getContentBox = function(/* HTMLElement */node){
	//	summary
	//	Returns the dimensions of the content box (see http://www.w3.org/TR/CSS21/box.html)
	node = dojo.byId(node);
	var padborder = dojo.html.getPadBorder(node);
	return {
		width: node.offsetWidth - padborder.width,
		height: node.offsetHeight - padborder.height
	};	//	object
}

dojo.html.setContentBox = function(/* HTMLElement */node, /* object */args){
	//	summary
	//	Sets the dimensions of the passed node according to content sizing.
	node = dojo.byId(node);
	var width = 0; var height = 0;
	var isbb = dojo.html.isBorderBox(node);
	var padborder = (isbb ? dojo.html.getPadBorder(node) : { width: 0, height: 0});
	var ret = {};
	if(typeof args.width != "undefined"){
		width = args.width + padborder.width;
		ret.width = dojo.html.setPositivePixelValue(node, "width", width);
	}
	if(typeof args.height != "undefined"){
		height = args.height + padborder.height;
		ret.height = dojo.html.setPositivePixelValue(node, "height", height);
	}
	return ret;	//	object
}

dojo.html.getMarginBox = function(/* HTMLElement */node){
	//	summary
	//	returns the dimensions of the passed node including any margins.
	var borderbox = dojo.html.getBorderBox(node);
	var margin = dojo.html.getMargin(node);
	return { width: borderbox.width + margin.width, height: borderbox.height + margin.height };	//	object
}

dojo.html.setMarginBox = function(/* HTMLElement */node, /* object */args){
	//	summary
	//	Sets the dimensions of the passed node using margin box calcs.
	node = dojo.byId(node);
	var width = 0; var height = 0;
	var isbb = dojo.html.isBorderBox(node);
	var padborder = (!isbb ? dojo.html.getPadBorder(node) : { width: 0, height: 0 });
	var margin = dojo.html.getMargin(node);
	var ret = {};
	if(typeof args.width != "undefined"){
		width = args.width - padborder.width;
		width -= margin.width;
		ret.width = dojo.html.setPositivePixelValue(node, "width", width);
	}
	if(typeof args.height != "undefined"){
		height = args.height - padborder.height;
		height -= margin.height;
		ret.height = dojo.html.setPositivePixelValue(node, "height", height);
	}
	return ret;	//	object
}

dojo.html.getElementBox = function(/* HTMLElement */node, /* string */type){
	//	summary
	//	return dimesions of a node based on the passed box model type.
	var bs = dojo.html.boxSizing;
	switch(type){
		case bs.MARGIN_BOX:
			return dojo.html.getMarginBox(node);	//	object
		case bs.BORDER_BOX:
			return dojo.html.getBorderBox(node);	//	object
		case bs.PADDING_BOX:
			return dojo.html.getPaddingBox(node);	//	object
		case bs.CONTENT_BOX:
		default:
			return dojo.html.getContentBox(node);	//	object
	}
}
// in: coordinate array [x,y,w,h] or dom node
// return: coordinate object
dojo.html.toCoordinateObject = dojo.html.toCoordinateArray = function(/* array */coords, /* boolean? */includeScroll, /* string? */boxtype) {
	//	summary
	//	Converts an array of coordinates into an object of named arguments.
	if(coords instanceof Array || typeof coords == "array"){
		dojo.deprecated("dojo.html.toCoordinateArray", "use dojo.html.toCoordinateObject({left: , top: , width: , height: }) instead", "0.5");
		// coords is already an array (of format [x,y,w,h]), just return it
		while ( coords.length < 4 ) { coords.push(0); }
		while ( coords.length > 4 ) { coords.pop(); }
		var ret = {
			left: coords[0],
			top: coords[1],
			width: coords[2],
			height: coords[3]
		};
	}else if(!coords.nodeType && !(coords instanceof String || typeof coords == "string") &&
			 ('width' in coords || 'height' in coords || 'left' in coords ||
			  'x' in coords || 'top' in coords || 'y' in coords)){
		// coords is a coordinate object or at least part of one
		var ret = {
			left: coords.left||coords.x||0,
			top: coords.top||coords.y||0,
			width: coords.width||0,
			height: coords.height||0
		};
	}else{
		// coords is an dom object (or dom object id); return it's coordinates
		var node = dojo.byId(coords);
		var pos = dojo.html.abs(node, includeScroll, boxtype);
		var marginbox = dojo.html.getMarginBox(node);
		var ret = {
			left: pos.left,
			top: pos.top,
			width: marginbox.width,
			height: marginbox.height
		};
	}
	ret.x = ret.left;
	ret.y = ret.top;
	return ret;	//	object
}

dojo.html.setMarginBoxWidth = dojo.html.setOuterWidth = function(node, width){
	return dojo.html._callDeprecated("setMarginBoxWidth", "setMarginBox", arguments, "width");
}
dojo.html.setMarginBoxHeight = dojo.html.setOuterHeight = function(){
	return dojo.html._callDeprecated("setMarginBoxHeight", "setMarginBox", arguments, "height");
}
dojo.html.getMarginBoxWidth = dojo.html.getOuterWidth = function(){
	return dojo.html._callDeprecated("getMarginBoxWidth", "getMarginBox", arguments, null, "width");
}
dojo.html.getMarginBoxHeight = dojo.html.getOuterHeight = function(){
	return dojo.html._callDeprecated("getMarginBoxHeight", "getMarginBox", arguments, null, "height");
}
dojo.html.getTotalOffset = function(node, type, includeScroll){
	return dojo.html._callDeprecated("getTotalOffset", "getAbsolutePosition", arguments, null, type);
}
dojo.html.getAbsoluteX = function(node, includeScroll){
	return dojo.html._callDeprecated("getAbsoluteX", "getAbsolutePosition", arguments, null, "x");
}
dojo.html.getAbsoluteY = function(node, includeScroll){
	return dojo.html._callDeprecated("getAbsoluteY", "getAbsolutePosition", arguments, null, "y");
}
dojo.html.totalOffsetLeft = function(node, includeScroll){
	return dojo.html._callDeprecated("totalOffsetLeft", "getAbsolutePosition", arguments, null, "left");
}
dojo.html.totalOffsetTop = function(node, includeScroll){
	return dojo.html._callDeprecated("totalOffsetTop", "getAbsolutePosition", arguments, null, "top");
}
dojo.html.getMarginWidth = function(node){
	return dojo.html._callDeprecated("getMarginWidth", "getMargin", arguments, null, "width");
}
dojo.html.getMarginHeight = function(node){
	return dojo.html._callDeprecated("getMarginHeight", "getMargin", arguments, null, "height");
}
dojo.html.getBorderWidth = function(node){
	return dojo.html._callDeprecated("getBorderWidth", "getBorder", arguments, null, "width");
}
dojo.html.getBorderHeight = function(node){
	return dojo.html._callDeprecated("getBorderHeight", "getBorder", arguments, null, "height");
}
dojo.html.getPaddingWidth = function(node){
	return dojo.html._callDeprecated("getPaddingWidth", "getPadding", arguments, null, "width");
}
dojo.html.getPaddingHeight = function(node){
	return dojo.html._callDeprecated("getPaddingHeight", "getPadding", arguments, null, "height");
}
dojo.html.getPadBorderWidth = function(node){
	return dojo.html._callDeprecated("getPadBorderWidth", "getPadBorder", arguments, null, "width");
}
dojo.html.getPadBorderHeight = function(node){
	return dojo.html._callDeprecated("getPadBorderHeight", "getPadBorder", arguments, null, "height");
}
dojo.html.getBorderBoxWidth = dojo.html.getInnerWidth = function(){
	return dojo.html._callDeprecated("getBorderBoxWidth", "getBorderBox", arguments, null, "width");
}
dojo.html.getBorderBoxHeight = dojo.html.getInnerHeight = function(){
	return dojo.html._callDeprecated("getBorderBoxHeight", "getBorderBox", arguments, null, "height");
}
dojo.html.getContentBoxWidth = dojo.html.getContentWidth = function(){
	return dojo.html._callDeprecated("getContentBoxWidth", "getContentBox", arguments, null, "width");
}
dojo.html.getContentBoxHeight = dojo.html.getContentHeight = function(){
	return dojo.html._callDeprecated("getContentBoxHeight", "getContentBox", arguments, null, "height");
}
dojo.html.setContentBoxWidth = dojo.html.setContentWidth = function(node, width){
	return dojo.html._callDeprecated("setContentBoxWidth", "setContentBox", arguments, "width");
}
dojo.html.setContentBoxHeight = dojo.html.setContentHeight = function(node, height){
	return dojo.html._callDeprecated("setContentBoxHeight", "setContentBox", arguments, "height");
}

__CPAN_FILE__ src/html/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [ "dojo.html.common",
			  "dojo.html.style" ]
});
dojo.provide("dojo.html.*");

__CPAN_FILE__ src/html/metrics.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.metrics");
dojo.require("dojo.html.layout");

/*	dojo.html.metrics
 *	Methods to help determine font metrics, including things like
 *	how much of a string will fit inside a certain width, what size
 *	something might be if you were to place it in a certain node, etc.
 *
 *	Based partially on a submitted patch by Morris Johns, and work
 *	done with 13th Parallel and f( m ) (the 13th columns and the
 *	unreleased f( m ) layout manager.
 */

//	derived from Morris John's scrollbar measurer.
dojo.html.getScrollbar=function(){
	//	summary
	//	returns the width of a scrollbar.
	
	//	set up the test nodes.
	var scroll = document.createElement("div");
	scroll.style.width="100px";
	scroll.style.height="100px";
	scroll.style.overflow="scroll";
	scroll.style.position="absolute";
	scroll.style.top="-300px";
	scroll.style.left="0px"
	
	var test = document.createElement("div");
	test.style.width="400px";
	test.style.height="400px";
	scroll.appendChild(test);
	dojo.body().appendChild(scroll);

	var width=scroll.offsetWidth - scroll.clientWidth;

	dojo.body().removeChild(scroll);
	scroll.removeChild(test);
	scroll=test=null;

	//	we return an object because we may add additional info in the future.
	return { width: width };	//	object
};

//	derived from Morris John's emResized measurer
dojo.html.getFontMeasurements = function(){
	//	summary
	//	Returns an object that has pixel equivilents of standard font size values.
	var heights = {
		'1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0,
		'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0
	};

	if(dojo.render.html.ie){
		//	we do a font-size fix if and only if one isn't applied already.
		//	NOTE: If someone set the fontSize on the HTML Element, this will kill it.
		document.documentElement.style.fontSize="100%";
	}

	//	set up the measuring node.
	var div=document.createElement("div");
	div.style.position="absolute";
	div.style.left="-100px";
	div.style.top="0";
	div.style.width="30px";
	div.style.height="1000em";
	div.style.border="0";
	div.style.margin="0";
	div.style.padding="0";
	div.style.outline="0";
	div.style.lineHeight="1";
	div.style.overflow="hidden";
	dojo.body().appendChild(div);

	//	do the measurements.
	for(var p in heights){
		div.style.fontSize = p;
		heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
	}
	
	dojo.body().removeChild(div);
	div = null;
	return heights; 	//	object
};

dojo.html._fontMeasurements = null;

dojo.html.getCachedFontMeasurements = function(recalculate){
	if(recalculate || !dojo.html._fontMeasurements){
		dojo.html._fontMeasurements = dojo.html.getFontMeasurements();
	}
	return dojo.html._fontMeasurements;
};

dojo.html.measureFragment = function(/* HTMLElement */node, /* string */html, /* string? */boxType){
	//	summary
	//	get the dimensions of passed node if it were populated with passed html.
	var clone = node.cloneNode(true);
	clone.innerHTML = html;
	node.parentNode.appendChild(clone);
	var ret = dojo.html.getElementBox(clone, boxType);
	node.parentNode.removeChild(clone);
	clone=null;
	return ret; // object
};

//	the following are derived from the 13th Parallel Column script, as
//		reinterpreted by trt.  http://www.13thparallel.org/archive/column-script
//	Original by Dan Pupius and Michael van Ouwerkerk.
dojo.html.getFittedFragment = function(/* HTMLElement */node, /* string */html){
	//	summary
	//	Given html, return the fragment that will fit on one line of passed node.
	function cl(node){
		var element = document.createElement(node.tagName);
		element.id = node.id + "-clone";
		element.className = node.className;
		for (var j = 0; j < node.attributes.length; j++) {
			if (node.attributes[j].specified) {
				if (node.attributes[j].nodeName.toLowerCase() != "style" 
					&& node.attributes[j].nodeName.toLowerCase() != "edited" 
					&& node.attributes[j].nodeName.toLowerCase() != "contenteditable"
					&& node.attributes[j].nodeName.toLowerCase() != "id"
					&& node.attributes[j].nodeName.toLowerCase() != "class"
				){
					element.setAttribute(node.attributes[j].nodeName.toLowerCase(), node.attributes[j].nodeValue);
				}
			}
		}
		return element;
	}
	var height = dojo.html.getFontMeasurements()["16px"];
	var n=cl(node);
	n.style.width=dojo.html.getBorderBox(node).width+"px";
	n.style.height=(height+4)+"px";
	node.parentNode.appendChild(n);
	var rem = dojo.html.fitToElement(n, html);
	var ret = n.innerHTML;
	n.parentNode.removeChild(n);
	return ret;
};

dojo.html.fitToElement = function(/* HTMLElement */node, /* string */html){
	//	summary
	//	will fit as much html as possible into node, and return the unused
	//	portion, with tag corrections.
	function cl(node){
		var element = document.createElement(node.tagName);
		element.id = node.id + "-clone";
		element.className = node.className;
		for (var j = 0; j < node.attributes.length; j++) {
			if (node.attributes[j].specified) {
				if (node.attributes[j].nodeName.toLowerCase() != "style" 
					&& node.attributes[j].nodeName.toLowerCase() != "edited" 
					&& node.attributes[j].nodeName.toLowerCase() != "contenteditable"
					&& node.attributes[j].nodeName.toLowerCase() != "id"
					&& node.attributes[j].nodeName.toLowerCase() != "class"
				){
					element.setAttribute(node.attributes[j].nodeName.toLowerCase(), node.attributes[j].nodeValue);
				}
			}
		}
		return element;
	}

	var clone = cl(node);
	node.parentNode.appendChild(clone);
	var t=dojo.html.getBorderBox(node);
	clone.style.width = t.width+"px";

	var singletons = ["br","img", "hr", "input", "!--"];
	var chop = ["<BR>","<br>","<br/>","<br />","<p></p>","<P></P>"];
	var openTags = [];

	var str = html;
	var i = 0;
	var limit = str.length;
	var add = 0;
	var doLoop = true;
	clone.innerHTML = str;
	while (doLoop) {
		add = Math.round((limit - i) / 2);
		if (add <= 1) doLoop = false;
		i += add;
		clone.innerHTML = str.substr(0, i);
		if (clone.offsetHeight > t.height) {
			limit = i;
			i -= add;
		}
	}
	if (str.substr(0, i) != str) {
		var lastSpace = str.substr(0, i).lastIndexOf(" ");
		var lastNewLine = str.substr(0, i).lastIndexOf("\n");
		var lastGreater = str.substr(0, i).lastIndexOf(">");
		var lastLess = str.substr(0, i).lastIndexOf("<");
		if (lastLess <= lastGreater && lastNewLine == i - 1) i = i;
		else if (lastSpace != -1 && lastSpace > lastGreater && lastGreater > lastLess) i = lastSpace + 1;
		else if (lastLess > lastGreater) i = lastLess;
		else if (lastGreater != -1) i = lastGreater + 1;
	}

	str = str.substr(0, i);
	var ret = html.substr(str.length);	//	get the rest of the passed text.

	var doPush = true;
	var tags = str.split("<");
	tags.shift();
	for (var j = 0; j < tags.length; j++) {
		tags[j] = tags[j].split(">")[0];
		if (tags[j].charAt(tags[j].length - 1) == "/"){ continue; }
		if (tags[j].charAt(0) != "/") {
			for (var k = 0; k < singletons.length; k++) {
				if (tags[j].split(" ")[0].toLowerCase() == singletons[k]){
					doPush = false;
				}
			}
			if (doPush){
				openTags.push(tags[j]);
			}
			doPush = true;
		} else {
			openTags.pop();
		}
	}

	//	close any open tags and prepend them to ret as well.
	for(var j=0; j<chop.length; j++){
		if(ret.charAt(0) == "\n"){ ret = ret.substr(1); }
		while(ret.indexOf(chop[j]) == 0){
			ret = ret.substr(chop[j].length);
		}
	}

	for(var j=openTags.length-1; j>=0; j--){
		if(str.lastIndexOf(openTags[j]) == (str.length-openTags[j].length-1)){
			str = str.substring(0, str.lastIndexOf(openTags[j]));
		} else {
			str += "</"+openTags[j]+">";
		}
		if(ret.length > 0){
			ret = "<"+openTags[j]+">"+ret;
		}
	}
	
	for(var j=0; j<chop.length; j++){
		if(ret.charAt(0) == "\n"){ ret = ret.substr(1); }
		while(ret.indexOf(chop[j]) == 0){
			ret = ret.substr(chop[j].length);
		}
	}
	//	push it into the node and pull the temp one.
	node.innerHTML = str;
	clone.parentNode.removeChild(clone);
	clone = null;
	
	//	return the remainder.
	return ret;	//	string
};

__CPAN_FILE__ src/html/selection.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.html.common");
dojo.provide("dojo.html.selection");

dojo.require("dojo.dom");
dojo.require("dojo.lang.common");

/**
 * type of selection
**/
dojo.html.selectionType = {
	NONE : 0, //selection is empty
	TEXT : 1, //selection contains text (may also contains CONTROL objects)
	CONTROL : 2 //only one element is selected (such as img, table etc)
};

dojo.html.clearSelection = function(){
	// summary: deselect the current selection to make it empty
	var _window = dojo.global();
	var _document = dojo.doc();
	try{
		if(_window["getSelection"]){ 
			if(dojo.render.html.safari){
				// pulled from WebCore/ecma/kjs_window.cpp, line 2536
				_window.getSelection().collapse();
			}else{
				_window.getSelection().removeAllRanges();
			}
		}else if(_document.selection){
			if(_document.selection.empty){
				_document.selection.empty();
			}else if(_document.selection.clear){
				_document.selection.clear();
			}
		}
		return true;
	}catch(e){
		dojo.debug(e);
		return false;
	}
}

dojo.html.disableSelection = function(/*DomNode*/element){
	// summary: disable selection on a node
	element = dojo.byId(element)||dojo.body();
	var h = dojo.render.html;
	
	if(h.mozilla){
		element.style.MozUserSelect = "none";
	}else if(h.safari){
		element.style.KhtmlUserSelect = "none"; 
	}else if(h.ie){
		element.unselectable = "on";
	}else{
		return false;
	}
	return true;
}

dojo.html.enableSelection = function(/*DomNode*/element){
	// summary: enable selection on a node
	element = dojo.byId(element)||dojo.body();
	
	var h = dojo.render.html;
	if(h.mozilla){ 
		element.style.MozUserSelect = ""; 
	}else if(h.safari){
		element.style.KhtmlUserSelect = "";
	}else if(h.ie){
		element.unselectable = "off";
	}else{
		return false;
	}
	return true;
}

dojo.html.selectElement = function(/*DomNode*/element){
	dojo.deprecated("dojo.html.selectElement", "replaced by dojo.html.selection.selectElementChildren", 0.5);
}

dojo.html.selectInputText = function(/*DomNode*/element){
	// summary: select all the text in an input element
	var _window = dojo.global();
	var _document = dojo.doc();
	element = dojo.byId(element);
	if(_document["selection"] && dojo.body()["createTextRange"]){ // IE
		var range = element.createTextRange();
		range.moveStart("character", 0);
		range.moveEnd("character", element.value.length);
		range.select();
	}else if(_window["getSelection"]){
		var selection = _window.getSelection();
		// FIXME: does this work on Safari?
		element.setSelectionRange(0, element.value.length);
	}
	element.focus();
}


dojo.html.isSelectionCollapsed = function(){
	dojo.deprecated("dojo.html.isSelectionCollapsed", "replaced by dojo.html.selection.isCollapsed", 0.5);
	return dojo.html.selection.isCollapsed();
}

dojo.lang.mixin(dojo.html.selection, {
	getType: function() {
		// summary: Get the selection type (like document.select.type in IE).
		if(dojo.doc()["selection"]){ //IE
			return dojo.html.selectionType[dojo.doc().selection.type.toUpperCase()];
		}else{
			var stype = dojo.html.selectionType.TEXT;
	
			// Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
			var oSel;
			try {oSel = dojo.global().getSelection();}
			catch (e) {}
			
			if(oSel && oSel.rangeCount==1){
				var oRange = oSel.getRangeAt(0);
				if (oRange.startContainer == oRange.endContainer && (oRange.endOffset - oRange.startOffset) == 1
					&& oRange.startContainer.nodeType != dojo.dom.TEXT_NODE) {
					stype = dojo.html.selectionType.CONTROL;
				}
			}
			return stype;
		}
	},
	isCollapsed: function() {
		// summary: return whether the current selection is empty
		var _window = dojo.global();
		var _document = dojo.doc();
		if(_document["selection"]){ // IE
			return _document.selection.createRange().text == "";
		}else if(_window["getSelection"]){
			var selection = _window.getSelection();
			if(dojo.lang.isString(selection)){ // Safari
				return selection == "";
			}else{ // Mozilla/W3
				return selection.isCollapsed || selection.toString() == "";
			}
		}
	},
	getSelectedElement: function() {
		// summary: 
		//		Retrieves the selected element (if any), just in the case that a single
		//		element (object like and image or a table) is selected.
		if ( dojo.html.selection.getType() == dojo.html.selectionType.CONTROL ){
			if(dojo.doc()["selection"]){ //IE
				var range = dojo.doc().selection.createRange();
		
				if ( range && range.item ){
					return dojo.doc().selection.createRange().item(0);
				}
			}else{
				var selection = dojo.global().getSelection();
				return selection.anchorNode.childNodes[ selection.anchorOffset ];
			}
		}
	},
	getParentElement: function() {
		// summary: 
		//		Get the parent element of the current selection
		if(dojo.html.selection.getType() == dojo.html.selectionType.CONTROL){
			var p = dojo.html.selection.getSelectedElement();
			if(p){ return p.parentNode; }
		}else{
			if(dojo.doc()["selection"]){ //IE
				return dojo.doc().selection.createRange().parentElement();
			}else{
				var selection = dojo.global().getSelection();
				if(selection){
					var node = selection.anchorNode;
		
					while ( node && node.nodeType != dojo.dom.ELEMENT_NODE ){
						node = node.parentNode;
					}
		
					return node;
				}
			}
		}
	},
	getSelectedText: function(){
		// summary:
		//		Return the text (no html tags) included in the current selection or null if no text is selected
		if(dojo.doc()["selection"]){ //IE
			if(dojo.html.selection.getType() == dojo.html.selectionType.CONTROL){
				return null;
			}
			return dojo.doc().selection.createRange().text;
		}else{
			var selection = dojo.global().getSelection();
			if(selection){
				return selection.toString();
			}
		}
	},
	getSelectedHtml: function(){
		// summary:
		//		Return the html of the current selection or null if unavailable
		if(dojo.doc()["selection"]){ //IE
			if(dojo.html.selection.getType() == dojo.html.selectionType.CONTROL){
				return null;
			}
			return dojo.doc().selection.createRange().htmlText;
		}else{
			var selection = dojo.global().getSelection();
			if(selection && selection.rangeCount){
				var frag = selection.getRangeAt(0).cloneContents();
				var div = document.createElement("div");
				div.appendChild(frag);
				return div.innerHTML;
			}
			return null;
		}
	},
	hasAncestorElement: function(/*String*/tagName /* ... */){
		// summary: 
		// 		Check whether current selection has a  parent element which is of type tagName (or one of the other specified tagName)
		return (dojo.html.selection.getAncestorElement.apply(this, arguments) != null);
	},
	getAncestorElement: function(/*String*/tagName /* ... */){
		// summary:
		//		Return the parent element of the current selection which is of type tagName (or one of the other specified tagName)
		var node = dojo.html.selection.getSelectedElement() || dojo.html.selection.getParentElement();
		while(node /*&& node.tagName.toLowerCase() != 'body'*/){
			if(dojo.html.selection.isTag(node, arguments).length>0){
				return node;
			}
			node = node.parentNode;
		}
		return null;
	},
	//modified from dojo.html.isTag to take an array as second parameter
	isTag: function(/*DomNode*/node, /*Array*/tags) {
		if(node && node.tagName) {
			for (var i=0; i<tags.length; i++){
				if (node.tagName.toLowerCase()==String(tags[i]).toLowerCase()){
					return String(tags[i]).toLowerCase();
				}
			}
		}
		return "";
	},
	selectElement: function(/*DomNode*/element) {
		// summary: clear previous selection and select element (including all its children)
		var _window = dojo.global();
		var _document = dojo.doc();
		element = dojo.byId(element);
		if(_document.selection && dojo.body().createTextRange){ // IE
			try{
				var range = dojo.body().createControlRange();
				range.addElement(element);
				range.select();
			}catch(e){
				dojo.html.selection.selectElementChildren(element);
			}
		}else if(_window["getSelection"]){
			var selection = _window.getSelection();
			// FIXME: does this work on Safari?
			if(selection["removeAllRanges"]){ // Mozilla
				var range = _document.createRange() ;
				range.selectNode(element) ;
				selection.removeAllRanges() ;
				selection.addRange(range) ;
			}
		}
	},
	selectElementChildren: function(/*DomNode*/element){
		// summary: clear previous selection and select the content of the node (excluding the node itself)
		var _window = dojo.global();
		var _document = dojo.doc();
		element = dojo.byId(element);
		if(_document.selection && dojo.body().createTextRange){ // IE
			var range = dojo.body().createTextRange();
			range.moveToElementText(element);
			range.select();
		}else if(_window["getSelection"]){
			var selection = _window.getSelection();
			if(selection["setBaseAndExtent"]){ // Safari
				selection.setBaseAndExtent(element, 0, element, element.innerText.length - 1);
			} else if(selection["selectAllChildren"]){ // Mozilla
				selection.selectAllChildren(element);
			}
		}
	},
	getBookmark: function(){
		// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
		var bookmark;
		var _document = dojo.doc();
		if(_document["selection"]){ // IE
			var range = _document.selection.createRange();
			bookmark = range.getBookmark();
		}else{
			var selection;
			try {selection = dojo.global().getSelection();}
			catch (e) {}
			if(selection){
				var range = selection.getRangeAt(0);
				bookmark = range.cloneRange();
			}else{
				dojo.debug("No idea how to store the current selection for this browser!");
			}
		}
		return bookmark;
	},
	moveToBookmark: function(/*Object*/bookmark){
		// summary: Moves current selection to a bookmark
		// bookmark: this should be a returned object from dojo.html.selection.getBookmark()
		var _document = dojo.doc();
		if(_document["selection"]){ // IE
			var range = _document.selection.createRange();
			 range.moveToBookmark(bookmark);
			 range.select();
		}else{ //Moz/W3C
			var selection;
			try {selection = dojo.global().getSelection();}
			catch (e) {}
			if(selection && selection['removeAllRanges']){
				selection.removeAllRanges() ;
				selection.addRange(bookmark) ;
			}else{
				dojo.debug("No idea how to restore selection for this browser!");
			}
		}
	},
	collapse: function(/*Boolean*/beginning) {
		// summary: clear current selection
		if(dojo.global()['getSelection']){
			var selection = dojo.global().getSelection();
			if(selection.removeAllRanges){ // Mozilla
				if(beginning){
					selection.collapseToStart();
				}else{
					selection.collapseToEnd();
				}
			}else{ // Safari
				// pulled from WebCore/ecma/kjs_window.cpp, line 2536
				 dojo.global().getSelection().collapse(beginning);
			}
		}else if(dojo.doc().selection){ // IE
			var range = dojo.doc().selection.createRange();
			range.collapse(beginning);
			range.select();
		}
	},
	remove: function() {
		// summary: delete current selection
		if(dojo.doc().selection) { //IE
			var selection = dojo.doc().selection;

			if ( selection.type.toUpperCase() != "NONE" ){
				selection.clear();
			}
		
			return selection;
		}else{
			var selection = dojo.global().getSelection();

			for ( var i = 0; i < selection.rangeCount; i++ ){
				selection.getRangeAt(i).deleteContents();
			}
		
			return selection;
		}
	}
});

__CPAN_FILE__ src/html/shadow.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.shadow");

dojo.require("dojo.lfx.shadow");
dojo.deprecated("dojo.html.shadow has been moved to dojo.lfx.", "0.5");

dojo.html.shadow = dojo.lfx.shadow;

__CPAN_FILE__ src/html/iframe.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.html.iframe");
dojo.require("dojo.html.util");

// thanks burstlib!
dojo.html.iframeContentWindow = function(/* HTMLIFrameElement */iframe_el) {
	//	summary
	//	returns the window reference of the passed iframe
	var win = dojo.html.getDocumentWindow(dojo.html.iframeContentDocument(iframe_el)) ||
		// Moz. TODO: is this available when defaultView isn't?
		dojo.html.iframeContentDocument(iframe_el).__parent__ ||
		(iframe_el.name && document.frames[iframe_el.name]) || null;
	return win;	//	Window
}

dojo.html.iframeContentDocument = function(/* HTMLIFrameElement */iframe_el){
	//	summary
	//	returns a reference to the document object inside iframe_el
	var doc = iframe_el.contentDocument // W3
		|| ((iframe_el.contentWindow)&&(iframe_el.contentWindow.document))	// IE
		|| ((iframe_el.name)&&(document.frames[iframe_el.name])&&(document.frames[iframe_el.name].document)) 
		|| null;
	return doc;	//	HTMLDocument
}

dojo.html.BackgroundIframe = function(/* HTMLElement */node) {
	//	summary
	//	For IE z-index schenanigans
	//	Two possible uses:
	//	1. new dojo.html.BackgroundIframe(node)
	//		Makes a background iframe as a child of node, that fills area (and position) of node
	//	2. new dojo.html.BackgroundIframe()
	//		Attaches frame to dojo.body().  User must call size() to set size.
	if(dojo.render.html.ie55 || dojo.render.html.ie60) {
		var html="<iframe src='javascript:false'"
			+ "' style='position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;"
			+ "z-index: -1; filter:Alpha(Opacity=\"0\");' "
			+ ">";
		this.iframe = dojo.doc().createElement(html);
		this.iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
		if(node){
			node.appendChild(this.iframe);
			this.domNode=node;
		}else{
			dojo.body().appendChild(this.iframe);
			this.iframe.style.display="none";
		}
	}
}
dojo.lang.extend(dojo.html.BackgroundIframe, {
	iframe: null,
	onResized: function(){
		//	summary
		//	Resize event handler.
		// TODO: this function shouldn't be necessary but setting width=height=100% doesn't work!
		if(this.iframe && this.domNode && this.domNode.parentNode){ // No parentElement if onResized() timeout event occurs on a removed domnode
			var outer = dojo.html.getMarginBox(this.domNode);
			if (outer.width  == 0 || outer.height == 0 ){
				dojo.lang.setTimeout(this, this.onResized, 100);
				return;
			}
			this.iframe.style.width = outer.width + "px";
			this.iframe.style.height = outer.height + "px";
		}
	},

	size: function(/* HTMLElement */node) {
		// 	Call this function if the iframe is connected to dojo.body() rather than the node being shadowed 
		//	(TODO: erase)
		if(!this.iframe) { return; }
		var coords = dojo.html.toCoordinateObject(node, true, dojo.html.boxSizing.BORDER_BOX);
		this.iframe.style.width = coords.width + "px";
		this.iframe.style.height = coords.height + "px";
		this.iframe.style.left = coords.left + "px";
		this.iframe.style.top = coords.top + "px";
	},

	setZIndex: function(/* HTMLElement */node) {
		//	summary
		//	Sets the z-index of the background iframe.
		if(!this.iframe) { return; }
		if(dojo.dom.isNode(node)) {
			this.iframe.style.zIndex = dojo.html.getStyle(node, "z-index") - 1;
		} else if(!isNaN(node)) {
			this.iframe.style.zIndex = node;
		}
	},

	show: function() {
		//	summary
		//	show the iframe
		if(!this.iframe) { return; }
		this.iframe.style.display = "block";
	},

	hide: function() {
		//	summary
		//	hide the iframe
		if(!this.iframe) { return; }
		this.iframe.style.display = "none";
	},

	remove: function() {
		//	summary
		//	remove the iframe
		dojo.html.removeNode(this.iframe);
	}
});

__CPAN_DIR__ src/html/images
__CPAN_FILE__ src/html/images/shadowBL.png
‰PNG


IHDRÄ¾‹gAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<¢IDATxÚ4ŽÉÃ DÙ²ô!‘ôóÿ—D•HÂÖçŠ"
c<ã1zß÷ ”òZë~ƒµ¿_ðèj­ÍÓ8Î4	8Õ¯Šˆ˜|ñ¨ÈŽ!U¦nêHs ^ýS\ŸNÖÚãGD8ÁÃÏpGY–å)¥˜qœ%	“Ãdœ÷¾ÄÓ4M"Êº§ÿÍ²NÛ‚Þ¶­�çÙæy.LeY�xSß_=5bËd5Ê¦IEND®B`‚
__CPAN_FILE__ src/html/images/shadowTR.png
‰PNG


IHDRÄ¾‹gAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<±IDATxÚ�„ D¡(bÔ%‘xïä]=�ÉXùt§’4˜×IÑÇq¸û¾yš&VJ±è”R;ÏSîŠZk£h‡²¥”.„`ö}':"òè`�ÎË²<1Æ¼m[™ç™;˜+Œ‚þ3Æ¤Z+
Ã ®ëbçKB`æŒ‘òµÖ*@Í{_%YÌ¨×Z‹Y>x{ài>¨×„ñ&ÉnÐ„]^`Ä´,œõ0äÍÈ4¾®ÿË`å÷Ò±IEND®B`‚
__CPAN_FILE__ src/html/images/shadowBR.png
‰PNG


IHDRÄ¾‹gAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<¡IDATxÚ4OIÃ Â�ŸÌúÑ<�sE¥„Ò„Õ�‰Z¤‘1³Øèu]"r*¥v Oô¬{ïýcqiZë†Ú‰‰ƒ*(b­UÍ	qÁÙŒ1ŠrÎÂ„ ™)„³Âéœ»sBô^–åâØŠK'ÉZ+ÇÕ”ÒÀwÂä`ìoáZJiÞûcœLà÷„3K'ÉÂÜ¶M¾œ„Ùïæ?IEND®B`‚
__CPAN_FILE__ src/html/images/shadowR.png
‰PNG


IHDRãïCgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<'IDATxÚbLII)g``øÄßüû÷ï
�ý†……å#H À´®@ßÙ@IEND®B`‚
__CPAN_FILE__ src/html/images/shadowB.png
‰PNG


IHDRÐ¡òdµgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<hIDATxÚìÝ1nÃ0Ð
ðQ}ŒÜ¸èÐ¥C<°Éœ%†àˆß:¶>éÔAË¨mû¾ß¾€jZÇñvñÚpFtum ¡-"îÚËi�ÇG][6ê¼Y7�~N‹Aç¾s~Õlè°˜íñûŸ6Àr®7Ù.9æì²åÌ–yí•k“è²§[;îkÈ6e6ôÏ¯m@Å<w ÿj,§ê ¸ò½j¶•³[;ßÚ3gS{Æ¦Ù�>J¨[¶DÙBmË];s_£èÚ£³“yî@ÿÑ(ÇŽÞ|×o^ú&[ùç§÷�jM1@¿ŠAG½¾Énmµå¸¶MKØ_ßÚËñ§Ÿ­-›ljÓ7’‹ðûv^_Z oÕ&Û|Ù|°À3xƒèÀYvŽªMmú‚{ädˆãžè‹ÚÔæ{è´Çá 31 ÒWÜsøC7÷}Šù`|¤fZì³oNIEND®B`‚
__CPAN_FILE__ src/html/images/shadowL.png
‰PNG


IHDRãïCgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<&IDATxÚbLHHfeeåÿÿÿ¿0ƒ(ˆfddñ¹€4@€³¢
ªÙZuIEND®B`‚
__CPAN_FILE__ src/html/images/shadowTL.png
‰PNG


IHDRÄ¾‹gAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<¡IDATxÚ,ŽA„0ëÔe[•.¸óÀÿÄqA°Îª‡(QÆv‚eY°ï;rÎVkEçyÂçû¾·m³yží8Ž(ø¯RŠ=Ï’àº®v][kIpHfÆ.Ýéð}ßc,Zf	>€qš&WµG‰‹º›ø�òØîÕ¿êÕ5“‚æ7=¶;«@Sù¹ä	è)ì±¹Ã¢ÒO€¨´9êuÈcIEND®B`‚
__CPAN_FILE__ src/html/images/shadowT.png
‰PNG


IHDR8•AgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<*IDATxÚbHOOçdb``àbúóç?ˆ%Â"LÿÿÿqÁb\±7²™“)IEND®B`‚
__CPAN_DIR__ src/event
__CPAN_FILE__ src/event/browser.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.event.browser");
dojo.require("dojo.event.common");

// FIXME: any particular reason this is in the global scope?
dojo._ie_clobber = new function(){
	this.clobberNodes = [];

	function nukeProp(node, prop){
		// try{ node.removeAttribute(prop); 	}catch(e){ /* squelch */ }
		try{ node[prop] = null; 			}catch(e){ /* squelch */ }
		try{ delete node[prop]; 			}catch(e){ /* squelch */ }
		// FIXME: JotLive needs this, but I'm not sure if it's too slow or not
		try{ node.removeAttribute(prop);	}catch(e){ /* squelch */ }
	}

	this.clobber = function(nodeRef){
		var na;
		var tna;
		if(nodeRef){
			tna = nodeRef.all || nodeRef.getElementsByTagName("*");
			na = [nodeRef];
			for(var x=0; x<tna.length; x++){
				// if we're gonna be clobbering the thing, at least make sure
				// we aren't trying to do it twice
				if(tna[x]["__doClobber__"]){
					na.push(tna[x]);
				}
			}
		}else{
			try{ window.onload = null; }catch(e){}
			na = (this.clobberNodes.length) ? this.clobberNodes : document.all;
		}
		tna = null;
		var basis = {};
		for(var i = na.length-1; i>=0; i=i-1){
			var el = na[i];
			try{
				if(el && el["__clobberAttrs__"]){
					for(var j=0; j<el.__clobberAttrs__.length; j++){
						nukeProp(el, el.__clobberAttrs__[j]);
					}
					nukeProp(el, "__clobberAttrs__");
					nukeProp(el, "__doClobber__");
				}
			}catch(e){ /* squelch! */};
		}
		na = null;
	}
}

if(dojo.render.html.ie){
	dojo.addOnUnload(function(){
		dojo._ie_clobber.clobber();
		try{
			if((dojo["widget"])&&(dojo.widget["manager"])){
				dojo.widget.manager.destroyAll();
			}
		}catch(e){}
		try{ window.onload = null; }catch(e){}
		try{ window.onunload = null; }catch(e){}
		dojo._ie_clobber.clobberNodes = [];
		// CollectGarbage();
	});
}

dojo.event.browser = new function(){

	var clobberIdx = 0;

	this.normalizedEventName = function(/*String*/eventName){
		switch(eventName){
			case "CheckboxStateChange":
			case "DOMAttrModified":
			case "DOMMenuItemActive":
			case "DOMMenuItemInactive":
			case "DOMMouseScroll":
			case "DOMNodeInserted":
			case "DOMNodeRemoved":
			case "RadioStateChange":
				return eventName;
				break;
			default:
				return eventName.toLowerCase();
				break;
		}
	}
	
	this.clean = function(/*DOMNode*/node){
		// summary:
		//		removes native event handlers so that destruction of the node
		//		will not leak memory. On most browsers this is a no-op, but
		//		it's critical for manual node removal on IE.
		// node:
		//		A DOM node. All of it's children will also be cleaned.
		if(dojo.render.html.ie){ 
			dojo._ie_clobber.clobber(node);
		}
	}

	this.addClobberNode = function(/*DOMNode*/node){
		// summary:
		//		register the passed node to support event stripping
		// node:
		//		A DOM node
		if(!dojo.render.html.ie){ return; }
		if(!node["__doClobber__"]){
			node.__doClobber__ = true;
			dojo._ie_clobber.clobberNodes.push(node);
			// this might not be the most efficient thing to do, but it's
			// much less error prone than other approaches which were
			// previously tried and failed
			node.__clobberAttrs__ = [];
		}
	}

	this.addClobberNodeAttrs = function(/*DOMNode*/node, /*Array*/props){
		// summary:
		//		register the passed node to support event stripping
		// node:
		//		A DOM node to stip properties from later
		// props:
		//		A list of propeties to strip from the node
		if(!dojo.render.html.ie){ return; }
		this.addClobberNode(node);
		for(var x=0; x<props.length; x++){
			node.__clobberAttrs__.push(props[x]);
		}
	}

	this.removeListener = function(	/*DOMNode*/ node, 
									/*String*/	evtName, 
									/*Function*/fp, 
									/*Boolean*/	capture){
		// summary:
		//		clobbers the listener from the node
		// evtName:
		//		the name of the handler to remove the function from
		// node:
		//		DOM node to attach the event to
		// fp:
		//		the function to register
		// capture:
		//		Optional. should this listener prevent propigation?
		if(!capture){ var capture = false; }
		evtName = dojo.event.browser.normalizedEventName(evtName);
		if( (evtName == "onkey") || (evtName == "key") ){
			if(dojo.render.html.ie){
				this.removeListener(node, "onkeydown", fp, capture);
			}
			evtName = "onkeypress";
		}
		if(evtName.substr(0,2)=="on"){ evtName = evtName.substr(2); }
		// FIXME: this is mostly a punt, we aren't actually doing anything on IE
		if(node.removeEventListener){
			node.removeEventListener(evtName, fp, capture);
		}
	}

	this.addListener = function(/*DOMNode*/node, /*String*/evtName, /*Function*/fp, /*Boolean*/capture, /*Boolean*/dontFix){
		// summary:
		//		adds a listener to the node
		// evtName:
		//		the name of the handler to add the listener to can be either of
		//		the form "onclick" or "click"
		// node:
		//		DOM node to attach the event to
		// fp:
		//		the function to register
		// capture:
		//		Optional. Should this listener prevent propigation?
		// dontFix:
		//		Optional. Should we avoid registering a new closure around the
		//		listener to enable fixEvent for dispatch of the registered
		//		function?
		if(!node){ return; } // FIXME: log and/or bail?
		if(!capture){ var capture = false; }
		evtName = dojo.event.browser.normalizedEventName(evtName);
		if( (evtName == "onkey") || (evtName == "key") ){
			if(dojo.render.html.ie){
				this.addListener(node, "onkeydown", fp, capture, dontFix);
			}
			evtName = "onkeypress";
		}
		if(evtName.substr(0,2)!="on"){ evtName = "on"+evtName; }

		if(!dontFix){
			// build yet another closure around fp in order to inject fixEvent
			// around the resulting event
			var newfp = function(evt){
				if(!evt){ evt = window.event; }
				var ret = fp(dojo.event.browser.fixEvent(evt, this));
				if(capture){
					dojo.event.browser.stopEvent(evt);
				}
				return ret;
			}
		}else{
			newfp = fp;
		}

		if(node.addEventListener){ 
			node.addEventListener(evtName.substr(2), newfp, capture);
			return newfp;
		}else{
			if(typeof node[evtName] == "function" ){
				var oldEvt = node[evtName];
				node[evtName] = function(e){
					oldEvt(e);
					return newfp(e);
				}
			}else{
				node[evtName]=newfp;
			}
			if(dojo.render.html.ie){
				this.addClobberNodeAttrs(node, [evtName]);
			}
			return newfp;
		}
	}

	this.isEvent = function(/*Object*/obj){
		// summary: 
		//		Tries to determine whether or not the object is a DOM event.

		// FIXME: event detection hack ... could test for additional attributes
		// if necessary
		return (typeof obj != "undefined")&&(typeof Event != "undefined")&&(obj.eventPhase); // Boolean
		// Event does not support instanceof in Opera, otherwise:
		//return (typeof Event != "undefined")&&(obj instanceof Event);
	}

	this.currentEvent = null;
	
	this.callListener = function(/*Function*/listener, /*DOMNode*/curTarget){
		// summary:
		//		calls the specified listener in the context of the passed node
		//		with the current DOM event object as the only parameter
		// listener:
		//		the function to call
		// curTarget:
		//		the Node to call the function in the scope of
		if(typeof listener != 'function'){
			dojo.raise("listener not a function: " + listener);
		}
		dojo.event.browser.currentEvent.currentTarget = curTarget;
		return listener.call(curTarget, dojo.event.browser.currentEvent);
	}

	this._stopPropagation = function(){
		dojo.event.browser.currentEvent.cancelBubble = true; 
	}

	this._preventDefault = function(){
		dojo.event.browser.currentEvent.returnValue = false;
	}

	this.keys = {
		KEY_BACKSPACE: 8,
		KEY_TAB: 9,
		KEY_CLEAR: 12,
		KEY_ENTER: 13,
		KEY_SHIFT: 16,
		KEY_CTRL: 17,
		KEY_ALT: 18,
		KEY_PAUSE: 19,
		KEY_CAPS_LOCK: 20,
		KEY_ESCAPE: 27,
		KEY_SPACE: 32,
		KEY_PAGE_UP: 33,
		KEY_PAGE_DOWN: 34,
		KEY_END: 35,
		KEY_HOME: 36,
		KEY_LEFT_ARROW: 37,
		KEY_UP_ARROW: 38,
		KEY_RIGHT_ARROW: 39,
		KEY_DOWN_ARROW: 40,
		KEY_INSERT: 45,
		KEY_DELETE: 46,
		KEY_HELP: 47,
		KEY_LEFT_WINDOW: 91,
		KEY_RIGHT_WINDOW: 92,
		KEY_SELECT: 93,
		KEY_NUMPAD_0: 96,
		KEY_NUMPAD_1: 97,
		KEY_NUMPAD_2: 98,
		KEY_NUMPAD_3: 99,
		KEY_NUMPAD_4: 100,
		KEY_NUMPAD_5: 101,
		KEY_NUMPAD_6: 102,
		KEY_NUMPAD_7: 103,
		KEY_NUMPAD_8: 104,
		KEY_NUMPAD_9: 105,
		KEY_NUMPAD_MULTIPLY: 106,
		KEY_NUMPAD_PLUS: 107,
		KEY_NUMPAD_ENTER: 108,
		KEY_NUMPAD_MINUS: 109,
		KEY_NUMPAD_PERIOD: 110,
		KEY_NUMPAD_DIVIDE: 111,
		KEY_F1: 112,
		KEY_F2: 113,
		KEY_F3: 114,
		KEY_F4: 115,
		KEY_F5: 116,
		KEY_F6: 117,
		KEY_F7: 118,
		KEY_F8: 119,
		KEY_F9: 120,
		KEY_F10: 121,
		KEY_F11: 122,
		KEY_F12: 123,
		KEY_F13: 124,
		KEY_F14: 125,
		KEY_F15: 126,
		KEY_NUM_LOCK: 144,
		KEY_SCROLL_LOCK: 145
	};

	// reverse lookup
	this.revKeys = [];
	for(var key in this.keys){
		this.revKeys[this.keys[key]] = key;
	}

	this.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
		// summary:
		//		normalizes properties on the event object including event
		//		bubbling methods, keystroke normalization, and x/y positions
		// evt: the native event object
		// sender: the node to treat as "currentTarget"
		if(!evt){
			if(window["event"]){
				evt = window.event;
			}
		}
		
		if((evt["type"])&&(evt["type"].indexOf("key") == 0)){ // key events
			evt.keys = this.revKeys;
			// FIXME: how can we eliminate this iteration?
			for(var key in this.keys){
				evt[key] = this.keys[key];
			}
			if(evt["type"] == "keydown" && dojo.render.html.ie){
				switch(evt.keyCode){
					case evt.KEY_SHIFT:
					case evt.KEY_CTRL:
					case evt.KEY_ALT:
					case evt.KEY_CAPS_LOCK:
					case evt.KEY_LEFT_WINDOW:
					case evt.KEY_RIGHT_WINDOW:
					case evt.KEY_SELECT:
					case evt.KEY_NUM_LOCK:
					case evt.KEY_SCROLL_LOCK:
					// I'll get these in keypress after the OS munges them based on numlock
					case evt.KEY_NUMPAD_0:
					case evt.KEY_NUMPAD_1:
					case evt.KEY_NUMPAD_2:
					case evt.KEY_NUMPAD_3:
					case evt.KEY_NUMPAD_4:
					case evt.KEY_NUMPAD_5:
					case evt.KEY_NUMPAD_6:
					case evt.KEY_NUMPAD_7:
					case evt.KEY_NUMPAD_8:
					case evt.KEY_NUMPAD_9:
					case evt.KEY_NUMPAD_PERIOD:
						break; // just ignore the keys that can morph
					case evt.KEY_NUMPAD_MULTIPLY:
					case evt.KEY_NUMPAD_PLUS:
					case evt.KEY_NUMPAD_ENTER:
					case evt.KEY_NUMPAD_MINUS:
					case evt.KEY_NUMPAD_DIVIDE:
						break; // I could handle these but just pick them up in keypress
					case evt.KEY_PAUSE:
					case evt.KEY_TAB:
					case evt.KEY_BACKSPACE:
					case evt.KEY_ENTER:
					case evt.KEY_ESCAPE:
					case evt.KEY_PAGE_UP:
					case evt.KEY_PAGE_DOWN:
					case evt.KEY_END:
					case evt.KEY_HOME:
					case evt.KEY_LEFT_ARROW:
					case evt.KEY_UP_ARROW:
					case evt.KEY_RIGHT_ARROW:
					case evt.KEY_DOWN_ARROW:
					case evt.KEY_INSERT:
					case evt.KEY_DELETE:
					case evt.KEY_F1:
					case evt.KEY_F2:
					case evt.KEY_F3:
					case evt.KEY_F4:
					case evt.KEY_F5:
					case evt.KEY_F6:
					case evt.KEY_F7:
					case evt.KEY_F8:
					case evt.KEY_F9:
					case evt.KEY_F10:
					case evt.KEY_F11:
					case evt.KEY_F12:
					case evt.KEY_F12:
					case evt.KEY_F13:
					case evt.KEY_F14:
					case evt.KEY_F15:
					case evt.KEY_CLEAR:
					case evt.KEY_HELP:
						evt.key = evt.keyCode;
						break;
					default:
						if(evt.ctrlKey || evt.altKey){
							var unifiedCharCode = evt.keyCode;
							// if lower case but keycode is uppercase, convert it
							if(unifiedCharCode >= 65 && unifiedCharCode <= 90 && evt.shiftKey == false){
								unifiedCharCode += 32;
							}
							if(unifiedCharCode >= 1 && unifiedCharCode <= 26 && evt.ctrlKey){
								unifiedCharCode += 96; // 001-032 = ctrl+[a-z]
							}
							evt.key = String.fromCharCode(unifiedCharCode);
						}
				}
			} else if(evt["type"] == "keypress"){
				if(dojo.render.html.opera){
					if(evt.which == 0){
						evt.key = evt.keyCode;
					}else if(evt.which > 0){
						switch(evt.which){
							case evt.KEY_SHIFT:
							case evt.KEY_CTRL:
							case evt.KEY_ALT:
							case evt.KEY_CAPS_LOCK:
							case evt.KEY_NUM_LOCK:
							case evt.KEY_SCROLL_LOCK:
								break;
							case evt.KEY_PAUSE:
							case evt.KEY_TAB:
							case evt.KEY_BACKSPACE:
							case evt.KEY_ENTER:
							case evt.KEY_ESCAPE:
								evt.key = evt.which;
								break;
							default:
								var unifiedCharCode = evt.which;
								if((evt.ctrlKey || evt.altKey || evt.metaKey) && (evt.which >= 65 && evt.which <= 90 && evt.shiftKey == false)){
									unifiedCharCode += 32;
								}
								evt.key = String.fromCharCode(unifiedCharCode);
						}
					}
				}else if(dojo.render.html.ie){ // catch some IE keys that are hard to get in keyDown
					// key combinations were handled in onKeyDown
					if(!evt.ctrlKey && !evt.altKey && evt.keyCode >= evt.KEY_SPACE){
						evt.key = String.fromCharCode(evt.keyCode);
					}
				}else if(dojo.render.html.safari){
					switch(evt.keyCode){
						case 63232: evt.key = evt.KEY_UP_ARROW; break;
						case 63233: evt.key = evt.KEY_DOWN_ARROW; break;
						case 63234: evt.key = evt.KEY_LEFT_ARROW; break;
						case 63235: evt.key = evt.KEY_RIGHT_ARROW; break;
						default: 
							evt.key = evt.charCode > 0 ? String.fromCharCode(evt.charCode) : evt.keyCode;
					}
				}else{
					evt.key = evt.charCode > 0 ? String.fromCharCode(evt.charCode) : evt.keyCode;
				}
			}
		}
		if(dojo.render.html.ie){
			if(!evt.target){ evt.target = evt.srcElement; }
			if(!evt.currentTarget){ evt.currentTarget = (sender ? sender : evt.srcElement); }
			if(!evt.layerX){ evt.layerX = evt.offsetX; }
			if(!evt.layerY){ evt.layerY = evt.offsetY; }
			// FIXME: scroll position query is duped from dojo.html to avoid dependency on that entire module
			// DONOT replace the following to use dojo.body(), in IE, document.documentElement should be used
			// here rather than document.body
			var doc = (evt.srcElement && evt.srcElement.ownerDocument) ? evt.srcElement.ownerDocument : document;
			var docBody = ((dojo.render.html.ie55)||(doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
			if(!evt.pageX){ evt.pageX = evt.clientX + (docBody.scrollLeft || 0) }
			if(!evt.pageY){ evt.pageY = evt.clientY + (docBody.scrollTop || 0) }
			// mouseover
			if(evt.type == "mouseover"){ evt.relatedTarget = evt.fromElement; }
			// mouseout
			if(evt.type == "mouseout"){ evt.relatedTarget = evt.toElement; }
			this.currentEvent = evt;
			evt.callListener = this.callListener;
			evt.stopPropagation = this._stopPropagation;
			evt.preventDefault = this._preventDefault;
		}
		return evt; // Event
	}

	this.stopEvent = function(/*Event*/evt){
		// summary:
		//		prevents propigation and clobbers the default action of the
		//		passed event
		// evt: Optional for IE. The native event object.
		if(window.event){
			evt.returnValue = false;
			evt.cancelBubble = true;
		}else{
			evt.preventDefault();
			evt.stopPropagation();
		}
	}
}

__CPAN_FILE__ src/event/topic.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.event.common");
dojo.provide("dojo.event.topic");

dojo.event.topic = new function(){
	this.topics = {};

	this.getTopic = function(/*String*/topic){
		// summary:
		//		returns a topic implementation object of type
		//		dojo.event.topic.TopicImpl
		// topic:
		//		a unique, opaque string that names the topic
		if(!this.topics[topic]){
			this.topics[topic] = new this.TopicImpl(topic);
		}
		return this.topics[topic]; // a dojo.event.topic.TopicImpl object
	}

	this.registerPublisher = function(/*String*/topic, /*Object*/obj, /*String*/funcName){
		// summary:
		//		registers a function as a publisher on a topic. Subsequent
		//		calls to the function will cause a publish event on the topic
		//		with the arguments passed to the function passed to registered
		//		listeners.
		// topic: 
		//		a unique, opaque string that names the topic
		// obj:
		//		the scope to locate the function in
		// funcName:
		//		the name of the function to register
		var topic = this.getTopic(topic);
		topic.registerPublisher(obj, funcName);
	}

	this.subscribe = function(/*String*/topic, /*Object*/obj, /*String*/funcName){
		// summary:
		//		susbscribes the function to the topic. Subsequent events
		//		dispached to the topic will create a function call for the
		//		obj.funcName() function.
		// topic: 
		//		a unique, opaque string that names the topic
		// obj:
		//		the scope to locate the function in
		// funcName:
		//		the name of the function to being registered as a listener
		var topic = this.getTopic(topic);
		topic.subscribe(obj, funcName);
	}

	this.unsubscribe = function(/*String*/topic, /*Object*/obj, /*String*/funcName){
		// summary:
		//		unsubscribes the obj.funcName() from the topic
		// topic: 
		//		a unique, opaque string that names the topic
		// obj:
		//		the scope to locate the function in
		// funcName:
		//		the name of the function to being unregistered as a listener
		var topic = this.getTopic(topic);
		topic.unsubscribe(obj, funcName);
	}

	this.destroy = function(/*String*/topic){
		// summary: 
		//		destroys the topic and unregisters all listeners
		// topic:
		//		a unique, opaque string that names the topic
		this.getTopic(topic).destroy();
		delete this.topics[topic];
	}

	this.publishApply = function(/*String*/topic, /*Array*/args){
		// summary: 
		//		dispatches an event to the topic using the args array as the
		//		source for the call arguments to each listener. This is similar
		//		to JavaScript's built-in Function.apply()
		// topic:
		//		a unique, opaque string that names the topic
		// args:
		//		the arguments to be passed into listeners of the topic
		var topic = this.getTopic(topic);
		topic.sendMessage.apply(topic, args);
	}

	this.publish = function(/*String*/topic, /*Object*/message){
		// summary: 
		//		manually "publish" to the passed topic
		// topic:
		//		a unique, opaque string that names the topic
		// message:
		//		can be an array of parameters (similar to publishApply), or
		//		will be treated as one of many arguments to be passed along in
		//		a "flat" unrolling
		var topic = this.getTopic(topic);
		// if message is an array, we treat it as a set of arguments,
		// otherwise, we just pass on the arguments passed in as-is
		var args = [];
		// could we use concat instead here?
		for(var x=1; x<arguments.length; x++){
			args.push(arguments[x]);
		}
		topic.sendMessage.apply(topic, args);
	}
}

dojo.event.topic.TopicImpl = function(topicName){
	// summary: a class to represent topics

	this.topicName = topicName;

	this.subscribe = function(/*Object*/listenerObject, /*Function or String*/listenerMethod){
		// summary:
		//		use dojo.event.connect() to attach the passed listener to the
		//		topic represented by this object
		// listenerObject:
		//		if a string and listenerMethod is ommitted, this is treated as
		//		the name of a function in the global namespace. If
		//		listenerMethod is provided, this is the scope to find/execute
		//		the function in.
		// listenerMethod:
		//		Optional. The function to register.
		var tf = listenerMethod||listenerObject;
		var to = (!listenerMethod) ? dj_global : listenerObject;
		return dojo.event.kwConnect({ // dojo.event.MethodJoinPoint
			srcObj:		this, 
			srcFunc:	"sendMessage", 
			adviceObj:	to,
			adviceFunc: tf
		});
	}

	this.unsubscribe = function(/*Object*/listenerObject, /*Function or String*/listenerMethod){
		// summary:
		//		use dojo.event.disconnect() to attach the passed listener to the
		//		topic represented by this object
		// listenerObject:
		//		if a string and listenerMethod is ommitted, this is treated as
		//		the name of a function in the global namespace. If
		//		listenerMethod is provided, this is the scope to find the
		//		function in.
		// listenerMethod:
		//		Optional. The function to unregister.
		var tf = (!listenerMethod) ? listenerObject : listenerMethod;
		var to = (!listenerMethod) ? null : listenerObject;
		return dojo.event.kwDisconnect({ // dojo.event.MethodJoinPoint
			srcObj:		this, 
			srcFunc:	"sendMessage", 
			adviceObj:	to,
			adviceFunc: tf
		});
	}

	this._getJoinPoint = function(){
		return dojo.event.MethodJoinPoint.getForMethod(this, "sendMessage");
	}

	this.setSquelch = function(/*Boolean*/shouldSquelch){
		// summary: 
		//		determine whether or not exceptions in the calling of a
		//		listener in the chain should stop execution of the chain.
		this._getJoinPoint().squelch = shouldSquelch;
	}

	this.destroy = function(){
		// summary: disconnects all listeners from this topic
		this._getJoinPoint().disconnect();
	}

	this.registerPublisher = function(	/*Object*/publisherObject, 
										/*Function or String*/publisherMethod){
		// summary:
		//		registers the passed function as a publisher on this topic.
		//		Each time the function is called, an event will be published on
		//		this topic.
		// publisherObject:
		//		if a string and listenerMethod is ommitted, this is treated as
		//		the name of a function in the global namespace. If
		//		listenerMethod is provided, this is the scope to find the
		//		function in.
		// publisherMethod:
		//		Optional. The function to register.
		dojo.event.connect(publisherObject, publisherMethod, this, "sendMessage");
	}

	this.sendMessage = function(message){
		// summary: a stub to be called when a message is sent to the topic.

		// The message has been propagated
	}
}


__CPAN_FILE__ src/event/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.event.common");

dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.lang.func");

// TODO: connection filter functions
//			these are functions that accept a method invocation (like around
//			advice) and return a boolean based on it. That value determines
//			whether or not the connection proceeds. It could "feel" like around
//			advice for those who know what it is (calling proceed() or not),
//			but I think presenting it as a "filter" and/or calling it with the
//			function args and not the MethodInvocation might make it more
//			palletable to "normal" users than around-advice currently is
// TODO: execution scope mangling
//			YUI's event facility by default executes listeners in the context
//			of the source object. This is very odd, but should probably be
//			supported as an option (both for the source and for the dest). It
//			can be thought of as a connection-specific hitch().
// TODO: more resiliency for 4+ arguments to connect()

dojo.event = new function(){
	this._canTimeout = dojo.lang.isFunction(dj_global["setTimeout"])||dojo.lang.isAlien(dj_global["setTimeout"]);

	// FIXME: where should we put this method (not here!)?
	function interpolateArgs(args, searchForNames){
		var dl = dojo.lang;
		var ao = {
			srcObj: dj_global,
			srcFunc: null,
			adviceObj: dj_global,
			adviceFunc: null,
			aroundObj: null,
			aroundFunc: null,
			adviceType: (args.length>2) ? args[0] : "after",
			precedence: "last",
			once: false,
			delay: null,
			rate: 0,
			adviceMsg: false
		};

		switch(args.length){
			case 0: return;
			case 1: return;
			case 2:
				ao.srcFunc = args[0];
				ao.adviceFunc = args[1];
				break;
			case 3:
				if((dl.isObject(args[0]))&&(dl.isString(args[1]))&&(dl.isString(args[2]))){
					ao.adviceType = "after";
					ao.srcObj = args[0];
					ao.srcFunc = args[1];
					ao.adviceFunc = args[2];
				}else if((dl.isString(args[1]))&&(dl.isString(args[2]))){
					ao.srcFunc = args[1];
					ao.adviceFunc = args[2];
				}else if((dl.isObject(args[0]))&&(dl.isString(args[1]))&&(dl.isFunction(args[2]))){
					ao.adviceType = "after";
					ao.srcObj = args[0];
					ao.srcFunc = args[1];
					var tmpName  = dl.nameAnonFunc(args[2], ao.adviceObj, searchForNames);
					ao.adviceFunc = tmpName;
				}else if((dl.isFunction(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))){
					ao.adviceType = "after";
					ao.srcObj = dj_global;
					var tmpName  = dl.nameAnonFunc(args[0], ao.srcObj, searchForNames);
					ao.srcFunc = tmpName;
					ao.adviceObj = args[1];
					ao.adviceFunc = args[2];
				}
				break;
			case 4:
				if((dl.isObject(args[0]))&&(dl.isObject(args[2]))){
					// we can assume that we've got an old-style "connect" from
					// the sigslot school of event attachment. We therefore
					// assume after-advice.
					ao.adviceType = "after";
					ao.srcObj = args[0];
					ao.srcFunc = args[1];
					ao.adviceObj = args[2];
					ao.adviceFunc = args[3];
				}else if((dl.isString(args[0]))&&(dl.isString(args[1]))&&(dl.isObject(args[2]))){
					ao.adviceType = args[0];
					ao.srcObj = dj_global;
					ao.srcFunc = args[1];
					ao.adviceObj = args[2];
					ao.adviceFunc = args[3];
				}else if((dl.isString(args[0]))&&(dl.isFunction(args[1]))&&(dl.isObject(args[2]))){
					ao.adviceType = args[0];
					ao.srcObj = dj_global;
					var tmpName  = dl.nameAnonFunc(args[1], dj_global, searchForNames);
					ao.srcFunc = tmpName;
					ao.adviceObj = args[2];
					ao.adviceFunc = args[3];
				}else if((dl.isString(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))&&(dl.isFunction(args[3]))){
					ao.srcObj = args[1];
					ao.srcFunc = args[2];
					var tmpName  = dl.nameAnonFunc(args[3], dj_global, searchForNames);
					ao.adviceObj = dj_global;
					ao.adviceFunc = tmpName;
				}else if(dl.isObject(args[1])){
					ao.srcObj = args[1];
					ao.srcFunc = args[2];
					ao.adviceObj = dj_global;
					ao.adviceFunc = args[3];
				}else if(dl.isObject(args[2])){
					ao.srcObj = dj_global;
					ao.srcFunc = args[1];
					ao.adviceObj = args[2];
					ao.adviceFunc = args[3];
				}else{
					ao.srcObj = ao.adviceObj = ao.aroundObj = dj_global;
					ao.srcFunc = args[1];
					ao.adviceFunc = args[2];
					ao.aroundFunc = args[3];
				}
				break;
			case 6:
				ao.srcObj = args[1];
				ao.srcFunc = args[2];
				ao.adviceObj = args[3]
				ao.adviceFunc = args[4];
				ao.aroundFunc = args[5];
				ao.aroundObj = dj_global;
				break;
			default:
				ao.srcObj = args[1];
				ao.srcFunc = args[2];
				ao.adviceObj = args[3]
				ao.adviceFunc = args[4];
				ao.aroundObj = args[5];
				ao.aroundFunc = args[6];
				ao.once = args[7];
				ao.delay = args[8];
				ao.rate = args[9];
				ao.adviceMsg = args[10];
				break;
		}

		if(dl.isFunction(ao.aroundFunc)){
			var tmpName  = dl.nameAnonFunc(ao.aroundFunc, ao.aroundObj, searchForNames);
			ao.aroundFunc = tmpName;
		}

		if(dl.isFunction(ao.srcFunc)){
			ao.srcFunc = dl.getNameInObj(ao.srcObj, ao.srcFunc);
		}

		if(dl.isFunction(ao.adviceFunc)){
			ao.adviceFunc = dl.getNameInObj(ao.adviceObj, ao.adviceFunc);
		}

		if((ao.aroundObj)&&(dl.isFunction(ao.aroundFunc))){
			ao.aroundFunc = dl.getNameInObj(ao.aroundObj, ao.aroundFunc);
		}

		if(!ao.srcObj){
			dojo.raise("bad srcObj for srcFunc: "+ao.srcFunc);
		}
		if(!ao.adviceObj){
			dojo.raise("bad adviceObj for adviceFunc: "+ao.adviceFunc);
		}
		
		if(!ao.adviceFunc){
			dojo.debug("bad adviceFunc for srcFunc: "+ao.srcFunc);
			dojo.debugShallow(ao);
		} 
		
		return ao;
	}

	this.connect = function(/*...*/){
		// summary:
		//		dojo.event.connect is the glue that holds most Dojo-based
		//		applications together. Most combinations of arguments are
		//		supported, with the connect() method attempting to disambiguate
		//		the implied types of positional parameters. The following will
		//		all work:
		//			dojo.event.connect("globalFunctionName1", "globalFunctionName2");
		//			dojo.event.connect(functionReference1, functionReference2);
		//			dojo.event.connect("globalFunctionName1", functionReference2);
		//			dojo.event.connect(functionReference1, "globalFunctionName2");
		//			dojo.event.connect(scope1, "functionName1", "globalFunctionName2");
		//			dojo.event.connect("globalFunctionName1", scope2, "functionName2");
		//			dojo.event.connect(scope1, "functionName1", scope2, "functionName2");
		//			dojo.event.connect("after", scope1, "functionName1", scope2, "functionName2");
		//			dojo.event.connect("before", scope1, "functionName1", scope2, "functionName2");
		//			dojo.event.connect("around", 	scope1, "functionName1", 
		//											scope2, "functionName2",
		//											aroundFunctionReference);
		//			dojo.event.connect("around", 	scope1, "functionName1", 
		//											scope2, "functionName2",
		//											scope3, "aroundFunctionName");
		//			dojo.event.connect("before-around", 	scope1, "functionName1", 
		//													scope2, "functionName2",
		//													aroundFunctionReference);
		//			dojo.event.connect("after-around", 		scope1, "functionName1", 
		//													scope2, "functionName2",
		//													aroundFunctionReference);
		//			dojo.event.connect("after-around", 		scope1, "functionName1", 
		//													scope2, "functionName2",
		//													scope3, "aroundFunctionName");
		//			dojo.event.connect("around", 	scope1, "functionName1", 
		//											scope2, "functionName2",
		//											scope3, "aroundFunctionName", true, 30);
		//			dojo.event.connect("around", 	scope1, "functionName1", 
		//											scope2, "functionName2",
		//											scope3, "aroundFunctionName", null, null, 10);
		// adviceType: 
		//		Optional. String. One of "before", "after", "around",
		//		"before-around", or "after-around". FIXME
		// srcObj:
		//		the scope in which to locate/execute the named srcFunc. Along
		//		with srcFunc, this creates a way to dereference the function to
		//		call. So if the function in question is "foo.bar", the
		//		srcObj/srcFunc pair would be foo and "bar", where "bar" is a
		//		string and foo is an object reference.
		// srcFunc:
		//		the name of the function to connect to. When it is executed,
		//		the listener being registered with this call will be called.
		//		The adviceType defines the call order between the source and
		//		the target functions.
		// adviceObj:
		//		the scope in which to locate/execute the named adviceFunc.
		// adviceFunc:
		//		the name of the function being conected to srcObj.srcFunc
		// aroundObj:
		//		the scope in which to locate/execute the named aroundFunc.
		// aroundFunc:
		//		the name of, or a reference to, the function that will be used
		//		to mediate the advice call. Around advice requires a special
		//		unary function that will be passed a "MethodInvocation" object.
		//		These objects have several important properties, namely:
		//			- args
		//				a mutable array of arguments to be passed into the
		//				wrapped function
		//			- proceed
		//				a function that "continues" the invocation. The result
		//				of this function is the return of the wrapped function.
		//				You can then manipulate this return before passing it
		//				back out (or take further action based on it).
		// once:
		//		boolean that determines whether or not this connect() will
		//		create a new connection if an identical connect() has already
		//		been made. Defaults to "false".
		// delay:
		//		an optional delay (in ms), as an integer, for dispatch of a
		//		listener after the source has been fired.
		// rate:
		//		an optional rate throttling parameter (integer, in ms). When
		//		specified, this particular connection will not fire more than
		//		once in the interval specified by the rate
		// adviceMsg:
		//		boolean. Should the listener have all the parameters passed in
		//		as a single argument?

		/*
				ao.adviceType = args[0];
				ao.srcObj = args[1];
				ao.srcFunc = args[2];
				ao.adviceObj = args[3]
				ao.adviceFunc = args[4];
				ao.aroundObj = args[5];
				ao.aroundFunc = args[6];
				ao.once = args[7];
				ao.delay = args[8];
				ao.rate = args[9];
				ao.adviceMsg = args[10];
		*/
		if(arguments.length == 1){
			var ao = arguments[0];
		}else{
			var ao = interpolateArgs(arguments, true);
		}
		if(dojo.lang.isString(ao.srcFunc) && (ao.srcFunc.toLowerCase() == "onkey") ){
			if(dojo.render.html.ie){
				ao.srcFunc = "onkeydown";
				this.connect(ao);
			}
			ao.srcFunc = "onkeypress";
		}


		if(dojo.lang.isArray(ao.srcObj) && ao.srcObj!=""){
			var tmpAO = {};
			for(var x in ao){
				tmpAO[x] = ao[x];
			}
			var mjps = [];
			dojo.lang.forEach(ao.srcObj, function(src){
				if((dojo.render.html.capable)&&(dojo.lang.isString(src))){
					src = dojo.byId(src);
					// dojo.debug(src);
				}
				tmpAO.srcObj = src;
				// dojo.debug(tmpAO.srcObj, tmpAO.srcFunc);
				// dojo.debug(tmpAO.adviceObj, tmpAO.adviceFunc);
				mjps.push(dojo.event.connect.call(dojo.event, tmpAO));
			});
			return mjps;
		}

		// FIXME: just doing a "getForMethod()" seems to be enough to put this into infinite recursion!!
		var mjp = dojo.event.MethodJoinPoint.getForMethod(ao.srcObj, ao.srcFunc);
		if(ao.adviceFunc){
			var mjp2 = dojo.event.MethodJoinPoint.getForMethod(ao.adviceObj, ao.adviceFunc);
		}

		mjp.kwAddAdvice(ao);

		// advanced users might want to fsck w/ the join point manually
		return mjp; // a MethodJoinPoint object
	}

	this.log = function(/*object or funcName*/ a1, /*funcName*/ a2){
		// summary:
		//		a function that will wrap and log all calls to the specified
		//		a1.a2() function. If only a1 is passed, it'll be used as a
		//		function or function name on the global context. Logging will
		//		be sent to dojo.debug
		// a1:
		//		if a2 is passed, this should be an object. If not, it can be a
		//		function or function name.
		// a2:
		//		a function name
		var kwArgs;
		if((arguments.length == 1)&&(typeof a1 == "object")){
			kwArgs = a1;
		}else{
			kwArgs = {
				srcObj: a1,
				srcFunc: a2
			};
		}
		kwArgs.adviceFunc = function(){
			var argsStr = [];
			for(var x=0; x<arguments.length; x++){
				argsStr.push(arguments[x]);
			}
			dojo.debug("("+kwArgs.srcObj+")."+kwArgs.srcFunc, ":", argsStr.join(", "));
		}
		this.kwConnect(kwArgs);
	}

	this.connectBefore = function(){
		// summary:
		//	 	takes the same parameters as dojo.event.connect(), except that
		//	 	the advice type will always be "before"
		var args = ["before"];
		for(var i = 0; i < arguments.length; i++){ args.push(arguments[i]); }
		return this.connect.apply(this, args); // a MethodJoinPoint object
	}

	this.connectAround = function(){
		// summary:
		//	 	takes the same parameters as dojo.event.connect(), except that
		//	 	the advice type will always be "around"
		var args = ["around"];
		for(var i = 0; i < arguments.length; i++){ args.push(arguments[i]); }
		return this.connect.apply(this, args); // a MethodJoinPoint object
	}

	this.connectOnce = function(){
		// summary:
		//	 	takes the same parameters as dojo.event.connect(), except that
		//	 	the "once" flag will always be set to "true"
		var ao = interpolateArgs(arguments, true);
		ao.once = true;
		return this.connect(ao); // a MethodJoinPoint object
	}

	this._kwConnectImpl = function(kwArgs, disconnect){
		var fn = (disconnect) ? "disconnect" : "connect";
		if(typeof kwArgs["srcFunc"] == "function"){
			kwArgs.srcObj = kwArgs["srcObj"]||dj_global;
			var tmpName  = dojo.lang.nameAnonFunc(kwArgs.srcFunc, kwArgs.srcObj, true);
			kwArgs.srcFunc = tmpName;
		}
		if(typeof kwArgs["adviceFunc"] == "function"){
			kwArgs.adviceObj = kwArgs["adviceObj"]||dj_global;
			var tmpName  = dojo.lang.nameAnonFunc(kwArgs.adviceFunc, kwArgs.adviceObj, true);
			kwArgs.adviceFunc = tmpName;
		}
		kwArgs.srcObj = kwArgs["srcObj"]||dj_global;
		kwArgs.adviceObj = kwArgs["adviceObj"]||kwArgs["targetObj"]||dj_global;
		kwArgs.adviceFunc = kwArgs["adviceFunc"]||kwArgs["targetFunc"];
		// pass kwargs to avoid unrolling/repacking
		return dojo.event[fn](kwArgs);
	}

	this.kwConnect = function(/*Object*/ kwArgs){
		// summary:
		//		A version of dojo.event.connect() that takes a map of named
		//		parameters instead of the positional parameters that
		//		dojo.event.connect() uses. For many advanced connection types,
		//		this can be a much more readable (and potentially faster)
		//		alternative.
		// kwArgs:
		// 		An object that can have the following properties:
		//			- adviceType
		//			- srcObj
		//			- srcFunc
		//			- adviceObj
		//			- adviceFunc 
		//			- aroundObj
		//			- aroundFunc
		//			- once
		//			- delay
		//			- rate
		//			- adviceMsg
		//		As with connect, only srcFunc and adviceFunc are generally
		//		required

		return this._kwConnectImpl(kwArgs, false); // a MethodJoinPoint object

	}

	this.disconnect = function(){
		// summary:
		//		Takes the same parameters as dojo.event.connect() but destroys
		//		an existing connection instead of building a new one. For
		//		multiple identical connections, multiple disconnect() calls
		//		will unroll one each time it's called.
		if(arguments.length == 1){
			var ao = arguments[0];
		}else{
			var ao = interpolateArgs(arguments, true);
		}
		if(!ao.adviceFunc){ return; } // nothing to disconnect
		if(dojo.lang.isString(ao.srcFunc) && (ao.srcFunc.toLowerCase() == "onkey") ){
			if(dojo.render.html.ie){
				ao.srcFunc = "onkeydown";
				this.disconnect(ao);
			}
			ao.srcFunc = "onkeypress";
		}
		var mjp = dojo.event.MethodJoinPoint.getForMethod(ao.srcObj, ao.srcFunc);
		return mjp.removeAdvice(ao.adviceObj, ao.adviceFunc, ao.adviceType, ao.once); // a MethodJoinPoint object
	}

	this.kwDisconnect = function(kwArgs){
		// summary:
		//		Takes the same parameters as dojo.event.kwConnect() but
		//		destroys an existing connection instead of building a new one.
		return this._kwConnectImpl(kwArgs, true);
	}
}

// exactly one of these is created whenever a method with a joint point is run,
// if there is at least one 'around' advice.
dojo.event.MethodInvocation = function(/*dojo.event.MethodJoinPoint*/join_point, /*Object*/obj, /*Array*/args){
	// summary:
	//		a class the models the call into a function. This is used under the
	//		covers for all method invocations on both ends of a
	//		connect()-wrapped function dispatch. This allows us to "pickle"
	//		calls, such as in the case of around advice.
	// join_point:
	//		a dojo.event.MethodJoinPoint object that represents a connection
	// obj:
	//		the scope the call will execute in
	// args:
	//		an array of parameters that will get passed to the callee
	this.jp_ = join_point;
	this.object = obj;
	this.args = [];
	// make sure we don't lock into a mutable object which can change under us.
	// It's ok if the individual items change, though.
	for(var x=0; x<args.length; x++){
		this.args[x] = args[x];
	}
	// the index of the 'around' that is currently being executed.
	this.around_index = -1;
}

dojo.event.MethodInvocation.prototype.proceed = function(){
	// summary:
	//		proceed with the method call that's represented by this invocation
	//		object
	this.around_index++;
	if(this.around_index >= this.jp_.around.length){
		return this.jp_.object[this.jp_.methodname].apply(this.jp_.object, this.args);
		// return this.jp_.run_before_after(this.object, this.args);
	}else{
		var ti = this.jp_.around[this.around_index];
		var mobj = ti[0]||dj_global;
		var meth = ti[1];
		return mobj[meth].call(mobj, this);
	}
} 


dojo.event.MethodJoinPoint = function(/*Object*/obj, /*String*/funcName){
	this.object = obj||dj_global;
	this.methodname = funcName;
	this.methodfunc = this.object[funcName];
	this.squelch = false;
	// this.before = [];
	// this.after = [];
	// this.around = [];
}

dojo.event.MethodJoinPoint.getForMethod = function(/*Object*/obj, /*String*/funcName){
	// summary:
	//		"static" class function for returning a MethodJoinPoint from a
	//		scoped function. If one doesn't exist, one is created.
	// obj:
	//		the scope to search for the function in
	// funcName:
	//		the name of the function to return a MethodJoinPoint for
	if(!obj){ obj = dj_global; }
	if(!obj[funcName]){
		// supply a do-nothing method implementation
		obj[funcName] = function(){};
		if(!obj[funcName]){
			// e.g. cannot add to inbuilt objects in IE6
			dojo.raise("Cannot set do-nothing method on that object "+funcName);
		}
	}else if((!dojo.lang.isFunction(obj[funcName]))&&(!dojo.lang.isAlien(obj[funcName]))){
		// FIXME: should we throw an exception here instead?
		return null; 
	}
	// we hide our joinpoint instance in obj[funcName + '$joinpoint']
	var jpname = funcName + "$joinpoint";
	var jpfuncname = funcName + "$joinpoint$method";
	var joinpoint = obj[jpname];
	if(!joinpoint){
		var isNode = false;
		if(dojo.event["browser"]){
			if( (obj["attachEvent"])||
				(obj["nodeType"])||
				(obj["addEventListener"]) ){
				isNode = true;
				dojo.event.browser.addClobberNodeAttrs(obj, [jpname, jpfuncname, funcName]);
			}
		}
		var origArity = obj[funcName].length;
		obj[jpfuncname] = obj[funcName];
		// joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, funcName);
		joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, jpfuncname);
		obj[funcName] = function(){ 
			var args = [];

			if((isNode)&&(!arguments.length)){
				var evt = null;
				try{
					if(obj.ownerDocument){
						evt = obj.ownerDocument.parentWindow.event;
					}else if(obj.documentElement){
						evt = obj.documentElement.ownerDocument.parentWindow.event;
					}else if(obj.event){ //obj is a window
						evt = obj.event;
					}else{
						evt = window.event;
					}
				}catch(e){
					evt = window.event;
				}

				if(evt){
					args.push(dojo.event.browser.fixEvent(evt, this));
				}
			}else{
				for(var x=0; x<arguments.length; x++){
					if((x==0)&&(isNode)&&(dojo.event.browser.isEvent(arguments[x]))){
						args.push(dojo.event.browser.fixEvent(arguments[x], this));
					}else{
						args.push(arguments[x]);
					}
				}
			}
			// return joinpoint.run.apply(joinpoint, arguments); 
			return joinpoint.run.apply(joinpoint, args); 
		}
		obj[funcName].__preJoinArity = origArity;
	}
	return joinpoint; // dojo.event.MethodJoinPoint
}

dojo.lang.extend(dojo.event.MethodJoinPoint, {
	unintercept: function(){
		// summary: 
		//		destroy the connection to all listeners that may have been
		//		registered on this joinpoint
		this.object[this.methodname] = this.methodfunc;
		this.before = [];
		this.after = [];
		this.around = [];
	},

	disconnect: dojo.lang.forward("unintercept"),

	run: function(){
		// summary:
		//		execute the connection represented by this join point. The
		//		arguments passed to run() will be passed to the function and
		//		its listeners.
		var obj = this.object||dj_global;
		var args = arguments;

		// optimization. We only compute once the array version of the arguments
		// pseudo-arr in order to prevent building it each time advice is unrolled.
		var aargs = [];
		for(var x=0; x<args.length; x++){
			aargs[x] = args[x];
		}

		var unrollAdvice  = function(marr){ 
			if(!marr){
				dojo.debug("Null argument to unrollAdvice()");
				return;
			}
		  
			var callObj = marr[0]||dj_global;
			var callFunc = marr[1];
			
			if(!callObj[callFunc]){
				dojo.raise("function \"" + callFunc + "\" does not exist on \"" + callObj + "\"");
			}
			
			var aroundObj = marr[2]||dj_global;
			var aroundFunc = marr[3];
			var msg = marr[6];
			var undef;

			var to = {
				args: [],
				jp_: this,
				object: obj,
				proceed: function(){
					return callObj[callFunc].apply(callObj, to.args);
				}
			};
			to.args = aargs;

			var delay = parseInt(marr[4]);
			var hasDelay = ((!isNaN(delay))&&(marr[4]!==null)&&(typeof marr[4] != "undefined"));
			if(marr[5]){
				var rate = parseInt(marr[5]);
				var cur = new Date();
				var timerSet = false;
				if((marr["last"])&&((cur-marr.last)<=rate)){
					if(dojo.event._canTimeout){
						if(marr["delayTimer"]){
							clearTimeout(marr.delayTimer);
						}
						var tod = parseInt(rate*2); // is rate*2 naive?
						var mcpy = dojo.lang.shallowCopy(marr);
						marr.delayTimer = setTimeout(function(){
							// FIXME: on IE at least, event objects from the
							// browser can go out of scope. How (or should?) we
							// deal with it?
							mcpy[5] = 0;
							unrollAdvice(mcpy);
						}, tod);
					}
					return;
				}else{
					marr.last = cur;
				}
			}

			// FIXME: need to enforce rates for a connection here!

			if(aroundFunc){
				// NOTE: around advice can't delay since we might otherwise depend
				// on execution order!
				aroundObj[aroundFunc].call(aroundObj, to);
			}else{
				// var tmjp = dojo.event.MethodJoinPoint.getForMethod(obj, methname);
				if((hasDelay)&&((dojo.render.html)||(dojo.render.svg))){  // FIXME: the render checks are grotty!
					dj_global["setTimeout"](function(){
						if(msg){
							callObj[callFunc].call(callObj, to); 
						}else{
							callObj[callFunc].apply(callObj, args); 
						}
					}, delay);
				}else{ // many environments can't support delay!
					if(msg){
						callObj[callFunc].call(callObj, to); 
					}else{
						callObj[callFunc].apply(callObj, args); 
					}
				}
			}
		}

		var unRollSquelch = function(){
			if(this.squelch){
				try{
					return unrollAdvice.apply(this, arguments);
				}catch(e){ 
					dojo.debug(e);
				}
			}else{
				return unrollAdvice.apply(this, arguments);
			}
		}

		if((this["before"])&&(this.before.length>0)){
			// pass a cloned array, if this event disconnects this event forEach on this.before wont work
			dojo.lang.forEach(this.before.concat(new Array()), unRollSquelch);
		}

		var result;
		try{
			if((this["around"])&&(this.around.length>0)){
				var mi = new dojo.event.MethodInvocation(this, obj, args);
				result = mi.proceed();
			}else if(this.methodfunc){
				result = this.object[this.methodname].apply(this.object, args);
			}
		}catch(e){ if(!this.squelch){ dojo.raise(e); } }

		if((this["after"])&&(this.after.length>0)){
			// see comment on this.before above
			dojo.lang.forEach(this.after.concat(new Array()), unRollSquelch);
		}

		return (this.methodfunc) ? result : null;
	},

	getArr: function(/*String*/kind){
		// summary: return a list of listeners of the past "kind"
		// kind:
		//		can be one of: "before", "after", "around", "before-around", or
		//		"after-around"
		var type = "after";
		// FIXME: we should be able to do this through props or Array.in()
		if((typeof kind == "string")&&(kind.indexOf("before")!=-1)){
			type = "before";
		}else if(kind=="around"){
			type = "around";
		}
		if(!this[type]){ this[type] = []; }
		return this[type]; // Array
	},

	kwAddAdvice: function(/*Object*/args){
		// summary:
		//		adds advice to the joinpoint with arguments in a map
		// args:
		// 		An object that can have the following properties:
		//			- adviceType
		//			- adviceObj
		//			- adviceFunc 
		//			- aroundObj
		//			- aroundFunc
		//			- once
		//			- delay
		//			- rate
		//			- adviceMsg
		this.addAdvice(	args["adviceObj"], args["adviceFunc"], 
						args["aroundObj"], args["aroundFunc"], 
						args["adviceType"], args["precedence"], 
						args["once"], args["delay"], args["rate"], 
						args["adviceMsg"]);
	},

	addAdvice: function(	thisAdviceObj, thisAdvice, 
							thisAroundObj, thisAround, 
							adviceType, precedence, 
							once, delay, rate, asMessage){
		// summary:
		//		add advice to this joinpoint using positional parameters
		// thisAdviceObj:
		//		the scope in which to locate/execute the named adviceFunc.
		// thisAdviceFunc:
		//		the name of the function being conected
		// thisAroundObj:
		//		the scope in which to locate/execute the named aroundFunc.
		// thisAroundFunc:
		//		the name of the function that will be used to mediate the
		//		advice call.
		// adviceType: 
		//		Optional. String. One of "before", "after", "around",
		//		"before-around", or "after-around". FIXME
		// once:
		//		boolean that determines whether or not this advice will create
		//		a new connection if an identical advice set has already been
		//		provided. Defaults to "false".
		// delay:
		//		an optional delay (in ms), as an integer, for dispatch of a
		//		listener after the source has been fired.
		// rate:
		//		an optional rate throttling parameter (integer, in ms). When
		//		specified, this particular connection will not fire more than
		//		once in the interval specified by the rate
		// adviceMsg:
		//		boolean. Should the listener have all the parameters passed in
		//		as a single argument?
		var arr = this.getArr(adviceType);
		if(!arr){
			dojo.raise("bad this: " + this);
		}

		var ao = [thisAdviceObj, thisAdvice, thisAroundObj, thisAround, delay, rate, asMessage];
		
		if(once){
			if(this.hasAdvice(thisAdviceObj, thisAdvice, adviceType, arr) >= 0){
				return;
			}
		}

		if(precedence == "first"){
			arr.unshift(ao);
		}else{
			arr.push(ao);
		}
	},

	hasAdvice: function(thisAdviceObj, thisAdvice, adviceType, arr){
		// summary:
		//		returns the array index of the first existing connection
		//		betweened the passed advice and this joinpoint. Will be -1 if
		//		none exists.
		// thisAdviceObj:
		//		the scope in which to locate/execute the named adviceFunc.
		// thisAdviceFunc:
		//		the name of the function being conected
		// adviceType: 
		//		Optional. String. One of "before", "after", "around",
		//		"before-around", or "after-around". FIXME
		// arr:
		//		Optional. The list of advices to search. Will be found via
		//		adviceType if not passed
		if(!arr){ arr = this.getArr(adviceType); }
		var ind = -1;
		for(var x=0; x<arr.length; x++){
			var aao = (typeof thisAdvice == "object") ? (new String(thisAdvice)).toString() : thisAdvice;
			var a1o = (typeof arr[x][1] == "object") ? (new String(arr[x][1])).toString() : arr[x][1];
			if((arr[x][0] == thisAdviceObj)&&(a1o == aao)){
				ind = x;
			}
		}
		return ind; // Integer
	},

	removeAdvice: function(thisAdviceObj, thisAdvice, adviceType, once){
		// summary:
		//		returns the array index of the first existing connection
		//		betweened the passed advice and this joinpoint. Will be -1 if
		//		none exists.
		// thisAdviceObj:
		//		the scope in which to locate/execute the named adviceFunc.
		// thisAdviceFunc:
		//		the name of the function being conected
		// adviceType: 
		//		Optional. String. One of "before", "after", "around",
		//		"before-around", or "after-around". FIXME
		// once:
		//		Optional. Should this only remove the first occurance of the
		//		connection?
		var arr = this.getArr(adviceType);
		var ind = this.hasAdvice(thisAdviceObj, thisAdvice, adviceType, arr);
		if(ind == -1){
			return false;
		}
		while(ind != -1){
			arr.splice(ind, 1);
			if(once){ break; }
			ind = this.hasAdvice(thisAdviceObj, thisAdvice, adviceType, arr);
		}
		return true;
	}
});

__CPAN_FILE__ src/event/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: ["dojo.event.common", "dojo.event.topic"],
	browser: ["dojo.event.browser"],
	dashboard: ["dojo.event.browser"]
});
dojo.provide("dojo.event.*");

__CPAN_DIR__ src/dnd
__CPAN_FILE__ src/dnd/DragAndDrop.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.lang.common");
dojo.require("dojo.lang.declare");
dojo.provide("dojo.dnd.DragAndDrop");

dojo.declare("dojo.dnd.DragSource", null, {
	type: "",

	onDragEnd: function(){
	},

	onDragStart: function(){
	},

	/*
	 * This function gets called when the DOM element was 
	 * selected for dragging by the HtmlDragAndDropManager.
	 */
	onSelected: function(){
	},

	unregister: function(){
		dojo.dnd.dragManager.unregisterDragSource(this);
	},

	reregister: function(){
		dojo.dnd.dragManager.registerDragSource(this);
	}
}, function(){

	//dojo.profile.start("DragSource");

	var dm = dojo.dnd.dragManager;
	if(dm["registerDragSource"]){ // side-effect prevention
		dm.registerDragSource(this);
	}

	//dojo.profile.end("DragSource");

});

dojo.declare("dojo.dnd.DragObject", null, {
	type: "",

	onDragStart: function(){
		// gets called directly after being created by the DragSource
		// default action is to clone self as icon
	},

	onDragMove: function(){
		// this changes the UI for the drag icon
		//	"it moves itself"
	},

	onDragOver: function(){
	},

	onDragOut: function(){
	},

	onDragEnd: function(){
	},

	// normal aliases
	onDragLeave: this.onDragOut,
	onDragEnter: this.onDragOver,

	// non-camel aliases
	ondragout: this.onDragOut,
	ondragover: this.onDragOver
}, function(){
	var dm = dojo.dnd.dragManager;
	if(dm["registerDragObject"]){ // side-effect prevention
		dm.registerDragObject(this);
	}
});

dojo.declare("dojo.dnd.DropTarget", null, {

	acceptsType: function(type){
		if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard
			if(!dojo.lang.inArray(this.acceptedTypes, type)) { return false; }
		}
		return true;
	},

	accepts: function(dragObjects){
		if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard
			for (var i = 0; i < dragObjects.length; i++) {
				if (!dojo.lang.inArray(this.acceptedTypes,
					dragObjects[i].type)) { return false; }
			}
		}
		return true;
	},

	unregister: function(){
		dojo.dnd.dragManager.unregisterDropTarget(this);
	},

	onDragOver: function(){
	},

	onDragOut: function(){
	},

	onDragMove: function(){
	},

	onDropStart: function(){
	},

	onDrop: function(){
	},

	onDropEnd: function(){
	}
}, function(){
	if (this.constructor == dojo.dnd.DropTarget) { return; } // need to be subclassed
	this.acceptedTypes = [];
	dojo.dnd.dragManager.registerDropTarget(this);
});

// NOTE: this interface is defined here for the convenience of the DragManager
// implementor. It is expected that in most cases it will be satisfied by
// extending a native event (DOM event in HTML and SVG).
dojo.dnd.DragEvent = function(){
	this.dragSource = null;
	this.dragObject = null;
	this.target = null;
	this.eventStatus = "success";
	//
	// can be one of:
	//	[	"dropSuccess", "dropFailure", "dragMove",
	//		"dragStart", "dragEnter", "dragLeave"]
	//
}
/*
 *	The DragManager handles listening for low-level events and dispatching
 *	them to higher-level primitives like drag sources and drop targets. In
 *	order to do this, it must keep a list of the items.
 */
dojo.declare("dojo.dnd.DragManager", null, {
	selectedSources: [],
	dragObjects: [],
	dragSources: [],
	registerDragSource: function(){},
	dropTargets: [],
	registerDropTarget: function(){},
	lastDragTarget: null,
	currentDragTarget: null,
	onKeyDown: function(){},
	onMouseOut: function(){},
	onMouseMove: function(){},
	onMouseUp: function(){}
});

// NOTE: despite the existance of the DragManager class, there will be a
// singleton drag manager provided by the renderer-specific D&D support code.
// It is therefore sane for us to assign instance variables to the DragManager
// prototype

// The renderer-specific file will define the following object:
// dojo.dnd.dragManager = null;

__CPAN_FILE__ src/dnd/TreeDragAndDropV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
 * TreeDrag* specialized on managing subtree drags
 * It selects nodes and visualises what's going on,
 * but delegates real actions upon tree to the controller
 *
 * This code is considered a part of controller
*/

dojo.provide("dojo.dnd.TreeDragAndDropV3");

dojo.require("dojo.dnd.HtmlDragAndDrop");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.Deferred");
dojo.require("dojo.html.layout");

// FIXME: if controller can't move then skip node on move start
dojo.dnd.TreeDragSourceV3 = function(node, syncController, type, treeNode){
	//dojo.profile.start("TreeDragSourceV3 "+treeNode);
	this.controller = syncController;
	this.treeNode = treeNode;

	dojo.dnd.HtmlDragSource.call(this, node, type);
	//dojo.profile.end("TreeDragSourceV3 "+treeNode);

}

dojo.inherits(dojo.dnd.TreeDragSourceV3, dojo.dnd.HtmlDragSource);


// .......................................

dojo.dnd.TreeDropTargetV3 = function(domNode, controller, type, treeNode){

	this.treeNode = treeNode;
	this.controller = controller; // I will sync-ly process drops
	
	dojo.dnd.HtmlDropTarget.call(this, domNode, type);
}

dojo.inherits(dojo.dnd.TreeDropTargetV3, dojo.dnd.HtmlDropTarget);

dojo.lang.extend(dojo.dnd.TreeDropTargetV3, {

	autoExpandDelay: 1500,
	autoExpandTimer: null,


	position: null,

	indicatorStyle: "2px black groove",

	showIndicator: function(position) {

		// do not change style too often, cause of blinking possible
		if (this.position == position) {
			return;
		}

		//dojo.debug("set position for "+this.treeNode)

		this.hideIndicator();

		this.position = position;
		
		var node = this.treeNode;
			
		
		node.contentNode.style.width = dojo.html.getBorderBox(node.labelNode).width + "px";

		if (position == "onto") {					
			node.contentNode.style.border = this.indicatorStyle;
		} else {
			// FIXME: bottom-top or highlight should cover ONLY top/bottom or div itself,
			// not span whole line (try Dnd)
			// FAILURE: Can't put span inside div: multiline bottom-top will span multiple lines
			if (position == "before") {
				node.contentNode.style.borderTop = this.indicatorStyle;
			} else if (position == "after") {
				node.contentNode.style.borderBottom = this.indicatorStyle;
			}									
		}  
	},

	hideIndicator: function() {
		this.treeNode.contentNode.style.borderBottom = "";
		this.treeNode.contentNode.style.borderTop = "";
		this.treeNode.contentNode.style.border = "";
		this.treeNode.contentNode.style.width=""
		this.position = null;
	},



	// is the target possibly ok ?
	// This function is run on dragOver, but drop possibility is also determined by position over node
	// that's why acceptsWithPosition is called
	// doesnt take index into account ( can change while moving mouse w/o changing target )
	/**
	 * Coarse (tree-level) access check.
	 * We can't determine real accepts status w/o position
	*/
	onDragOver: function(e){
		//dojo.debug("onDragOver for "+e);

		var accepts = dojo.dnd.HtmlDropTarget.prototype.onDragOver.apply(this, arguments);

		//dojo.debug("TreeDropTarget.onDragOver accepts:"+accepts)

		if (accepts && this.treeNode.isFolder && !this.treeNode.isExpanded) {
			this.setAutoExpandTimer();
		}
		
		if (accepts) {
			this.cacheNodeCoords();
		}


		return accepts;
	},

	/* Parent.onDragOver calls this function to get accepts status */
	accepts: function(dragObjects) {

		var accepts = dojo.dnd.HtmlDropTarget.prototype.accepts.apply(this, arguments);

		//dojo.debug("accepts "+accepts);

		if (!accepts) return false;

		for(var i=0; i<dragObjects.length; i++) {
			// there may be NO treeNode
			var sourceTreeNode = dragObjects[i].dragSource.treeNode;
			
			if (sourceTreeNode === this.treeNode) return false;
		}

		return true;
	},



	setAutoExpandTimer: function() {
		// set up autoexpand timer
		var _this = this;

		var autoExpand = function () {
			if (dojo.dnd.dragManager.currentDropTarget === _this) {
				_this.controller.expand(_this.treeNode);
				// SLOW. Coordinates will not be recalculated if collapse occurs, or
				// other (generic) resize. So that's a kind of hack.
				dojo.dnd.dragManager.cacheTargetLocations();
			}
		}

		this.autoExpandTimer = dojo.lang.setTimeout(autoExpand, _this.autoExpandDelay);
	},

		

	getAcceptPosition: function(e, dragObjects) {


		var DndMode = this.treeNode.tree.DndMode;

		// disable ONTO mode possibility if impossible 
		if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO &&
			// check if ONTO is allowed localy
			// check dynamically cause may change w/o regeneration of dropTarget
			this.treeNode.actionIsDisabledNow(this.treeNode.actions.ADDCHILD) 
		) {
			// disable ONTO if can't move
			DndMode &= ~dojo.widget.TreeV3.prototype.DndModes.ONTO;
		}
		

		var position = this.getPosition(e, DndMode);

		//dojo.debug(DndMode & +" : "+position);


		// if onto is here => it was allowed before, no accept check is needed
		if (position=="onto") {
			return position;
		}
		
		for(var i=0; i<dragObjects.length; i++) {
			var source = dragObjects[i].dragSource;
			if (source.treeNode && this.isAdjacentNode(source.treeNode, position)) { // skip check if same parent
				continue;
			}		
						
			if (!this.controller.canMove(source.treeNode ? source.treeNode : source, this.treeNode.parent)) {
				return false;
			}
		}
		
		return position;
	
	},

	

	onDropEnd: function(e) {
		this.clearAutoExpandTimer();

		this.hideIndicator();
	},


	onDragOut: function(e) {
		this.clearAutoExpandTimer();

		this.hideIndicator();
	},

	clearAutoExpandTimer: function() {
		if (this.autoExpandTimer) {
			clearTimeout(this.autoExpandTimer);
			this.autoExpandTimer = null;
		}
	},



	onDragMove: function(e, dragObjects){
		
		var position = this.getAcceptPosition(e, dragObjects);

		if (position) {
			this.showIndicator(position);
		}

	},

	isAdjacentNode: function(sourceNode, position) {

		if (sourceNode === this.treeNode) return true;
		if (sourceNode.getNextSibling() === this.treeNode && position=="before") return true;
		if (sourceNode.getPreviousSibling() === this.treeNode && position=="after") return true;

		return false;
	},


	/**
	 * cache node coordinates to speed up onDragMove
	 */
	cacheNodeCoords: function() {
		var node = this.treeNode.contentNode;
		
		this.cachedNodeY = dojo.html.getAbsolutePosition(node).y;
		this.cachedNodeHeight = dojo.html.getBorderBox(node).height;
	},
	
	

	/* get DndMode and see which position e fits */
	getPosition: function(e, DndMode) {
		var mousey = e.pageY || e.clientY + dojo.body().scrollTop;
		
		var relY = mousey - this.cachedNodeY;
		var p = relY / this.cachedNodeHeight;

		var position = ""; // "" <=> forbidden
		if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO
		  && DndMode & dojo.widget.TreeV3.prototype.DndModes.BETWEEN) {
			//dojo.debug("BOTH");
			if (p<=0.33) {
				position = "before";
				// if children are expanded then I ignore understrike, cause it is confusing with firstChild
				// but for last nodes I put understrike there
			} else if (p<=0.66 || this.treeNode.isExpanded && this.treeNode.children.length && !this.treeNode.isLastChild()) {
				position = "onto";
			} else {
				position = "after";
			}
		} else if (DndMode & dojo.widget.TreeV3.prototype.DndModes.BETWEEN) {
			//dojo.debug("BETWEEN");
			if (p<=0.5 || this.treeNode.isExpanded && this.treeNode.children.length && !this.treeNode.isLastChild()) {
				position = "before";
			} else {
				position = "after";
			}
		}
		else if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO) {
			//dojo.debug("ONTO");
			position = "onto";
		}

		//dojo.debug(position);

		return position;
	},



	getTargetParentIndex: function(source, position) {

		var index = position == "before" ? this.treeNode.getParentIndex() : this.treeNode.getParentIndex()+1;
		if (source.treeNode
		  && this.treeNode.parent === source.treeNode.parent
		  && this.treeNode.getParentIndex() > source.treeNode.getParentIndex()) {
		  	index--;  // dragging a node is different for simple move bacause of before-after issues
		}

		return index;
	},


	onDrop: function(e) {
		// onDropEnd will clean position

		
		var position = this.position;

//dojo.debug(position);
		var source = e.dragObject.dragSource;
		
		//dojo.debug("onDrop "+source.treeNode+" " + position + " "+this.treeNode);


		var targetParent, targetIndex;
		if (position == "onto") {
			targetParent = this.treeNode;
			targetIndex = 0;
		} else {
			targetIndex = this.getTargetParentIndex(source, position);
			targetParent = this.treeNode.parent;
		}
		
		//dojo.profile.start("onDrop "+sourceTreeNode);
		var r = this.getDropHandler(e, source, targetParent, targetIndex)();
		
		//dojo.profile.end("onDrop "+sourceTreeNode);
			
		return r;

	},
	
	/**
	 * determine, which action I should perform with nodes
	 * e.g move, clone..
	 */
	getDropHandler: function(e, source, targetParent, targetIndex) {
		var handler;
		var _this = this;
		handler = function () {
			var result;
			
			//dojo.debug("Move "+source.treeNode+" to parent "+targetParent+":"+targetIndex);
			if (source.treeNode) {
				result = _this.controller.move(source.treeNode, targetParent, targetIndex, true);
				//dojo.debug("moved "+result);
			} else {
				if (dojo.lang.isFunction(source.onDrop)) {
					source.onDrop(targetParent, targetIndex);
				}
				
				var treeNode = source.getTreeNode();
				if (treeNode) {
					result = _this.controller.createChild(targetParent, targetIndex, treeNode, true);
				} else {
					result = true;
				}
			}
			
			if (result instanceof dojo.Deferred) {
				// this Deferred is always sync
				var isSuccess = result.fired == 0;
				if (!isSuccess) {
					_this.handleDropError(source, targetParent, targetIndex, result);
				}
				
				return isSuccess;				
				
			} else {
				return result;
			}
		}
		
		return handler;
	},
	
	
	handleDropError: function(source, parent, index, result) {
		dojo.debug("TreeDropTargetV3.handleDropError: DND error occured");
		dojo.debugShallow(result);
	}


});


__CPAN_FILE__ src/dnd/Sortable.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.dnd.Sortable");
dojo.require("dojo.dnd.*");

dojo.dnd.Sortable = function () {}

dojo.lang.extend(dojo.dnd.Sortable, {

	ondragstart: function (e) {
		var dragObject = e.target;
		while (dragObject.parentNode && dragObject.parentNode != this) {
			dragObject = dragObject.parentNode;
		}
		// TODO: should apply HtmlDropTarget interface to self
		// TODO: should apply HtmlDragObject interface?
		return dragObject;
	}

});

__CPAN_FILE__ src/dnd/HtmlDragManager.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.dnd.HtmlDragManager");
dojo.require("dojo.dnd.DragAndDrop");
dojo.require("dojo.event.*");
dojo.require("dojo.lang.array");
dojo.require("dojo.html.common");
dojo.require("dojo.html.layout");

// NOTE: there will only ever be a single instance of HTMLDragManager, so it's
// safe to use prototype properties for book-keeping.
dojo.declare("dojo.dnd.HtmlDragManager", dojo.dnd.DragManager, {
	/**
	 * There are several sets of actions that the DnD code cares about in the
	 * HTML context:
	 *	1.) mouse-down ->
	 *			(draggable selection)
	 *			(dragObject generation)
	 *		mouse-move ->
	 *			(draggable movement)
	 *			(droppable detection)
	 *			(inform droppable)
	 *			(inform dragObject)
	 *		mouse-up
	 *			(inform/destroy dragObject)
	 *			(inform draggable)
	 *			(inform droppable)
	 *	2.) mouse-down -> mouse-down
	 *			(click-hold context menu)
	 *	3.) mouse-click ->
	 *			(draggable selection)
	 *		shift-mouse-click ->
	 *			(augment draggable selection)
	 *		mouse-down ->
	 *			(dragObject generation)
	 *		mouse-move ->
	 *			(draggable movement)
	 *			(droppable detection)
	 *			(inform droppable)
	 *			(inform dragObject)
	 *		mouse-up
	 *			(inform draggable)
	 *			(inform droppable)
	 *	4.) mouse-up
	 *			(clobber draggable selection)
	 */
	disabled: false, // to kill all dragging!
	nestedTargets: false,
	mouseDownTimer: null, // used for click-hold operations
	dsCounter: 0,
	dsPrefix: "dojoDragSource",

	// dimension calculation cache for use durring drag
	dropTargetDimensions: [],

	currentDropTarget: null,
	// currentDropTargetPoints: null,
	previousDropTarget: null,
	_dragTriggered: false,

	selectedSources: [],
	dragObjects: [],

	// mouse position properties
	currentX: null,
	currentY: null,
	lastX: null,
	lastY: null,
	mouseDownX: null,
	mouseDownY: null,
	threshold: 7,

	dropAcceptable: false,

	cancelEvent: function(e){ e.stopPropagation(); e.preventDefault();},

	// method over-rides
	registerDragSource: function(ds){
		//dojo.profile.start("register DragSource");

		if(ds["domNode"]){
			// FIXME: dragSource objects SHOULD have some sort of property that
			// references their DOM node, we shouldn't just be passing nodes and
			// expecting it to work.
			//dojo.profile.start("register DragSource 1");
			var dp = this.dsPrefix;
			var dpIdx = dp+"Idx_"+(this.dsCounter++);
			ds.dragSourceId = dpIdx;
			this.dragSources[dpIdx] = ds;
			ds.domNode.setAttribute(dp, dpIdx);
			//dojo.profile.end("register DragSource 1");

			//dojo.profile.start("register DragSource 2");

			// so we can drag links
			if(dojo.render.html.ie){
				//dojo.profile.start("register DragSource IE");
				
				dojo.event.browser.addListener(ds.domNode, "ondragstart", this.cancelEvent);
				// terribly slow
				//dojo.event.connect(ds.domNode, "ondragstart", this.cancelEvent);
				//dojo.profile.end("register DragSource IE");

			}
			//dojo.profile.end("register DragSource 2");

		}
		//dojo.profile.end("register DragSource");
	},

	unregisterDragSource: function(ds){
		if (ds["domNode"]){
			var dp = this.dsPrefix;
			var dpIdx = ds.dragSourceId;
			delete ds.dragSourceId;
			delete this.dragSources[dpIdx];
			ds.domNode.setAttribute(dp, null);
			if(dojo.render.html.ie){
				dojo.event.browser.removeListener(ds.domNode, "ondragstart", this.cancelEvent);			
			}
		}
	},

	registerDropTarget: function(dt){
		this.dropTargets.push(dt);
	},

	unregisterDropTarget: function(dt){
		var index = dojo.lang.find(this.dropTargets, dt, true);
		if (index>=0) {
			this.dropTargets.splice(index, 1);
		}
	},

	/**
	* Get the DOM element that is meant to drag.
	* Loop through the parent nodes of the event target until
	* the element is found that was created as a DragSource and 
	* return it.
	*
	* @param event object The event for which to get the drag source.
	*/
	getDragSource: function(e){
		var tn = e.target;
		if(tn === dojo.body()){ return; }
		var ta = dojo.html.getAttribute(tn, this.dsPrefix);
		while((!ta)&&(tn)){
			tn = tn.parentNode;
			if((!tn)||(tn === dojo.body())){ return; }
			ta = dojo.html.getAttribute(tn, this.dsPrefix);
		}
		return this.dragSources[ta];
	},

	onKeyDown: function(e){
	},

	onMouseDown: function(e){
		if(this.disabled) { return; }

		// only begin on left click
		if(dojo.render.html.ie) {
			if(e.button != 1) { return; }
		} else if(e.which != 1) {
			return;
		}

		var target = e.target.nodeType == dojo.html.TEXT_NODE ?
			e.target.parentNode : e.target;

		// do not start drag involvement if the user is interacting with
		// a form element.
		if(dojo.html.isTag(target, "button", "textarea", "input", "select", "option")) {
			return;
		}

		// find a selection object, if one is a parent of the source node
		var ds = this.getDragSource(e);
		
		// this line is important.  if we aren't selecting anything then
		// we need to return now, so preventDefault() isn't called, and thus
		// the event is propogated to other handling code
		if(!ds){ return; }

		if(!dojo.lang.inArray(this.selectedSources, ds)){
			this.selectedSources.push(ds);
			ds.onSelected();
		}

 		this.mouseDownX = e.pageX;
 		this.mouseDownY = e.pageY;

		// Must stop the mouse down from being propogated, or otherwise can't
		// drag links in firefox.
		// WARNING: preventing the default action on all mousedown events
		// prevents user interaction with the contents.
		e.preventDefault();

		dojo.event.connect(document, "onmousemove", this, "onMouseMove");
	},

	onMouseUp: function(e, cancel){
		// if we aren't dragging then ignore the mouse-up
		// (in particular, don't call preventDefault(), because other
		// code may need to process this event)
		if(this.selectedSources.length==0){
			return;
		}

		this.mouseDownX = null;
		this.mouseDownY = null;
		this._dragTriggered = false;
 		// e.preventDefault();
		e.dragSource = this.dragSource;
		// let ctrl be used for multiselect or another action
		// if I use same key to trigger treeV3 node selection and here,
		// I have bugs with drag'n'drop. why ?? no idea..
		if((!e.shiftKey)&&(!e.ctrlKey)){ 
		//if(!e.shiftKey){
			if(this.currentDropTarget) {
				this.currentDropTarget.onDropStart();
			}
			dojo.lang.forEach(this.dragObjects, function(tempDragObj){
				var ret = null;
				if(!tempDragObj){ return; }
				if(this.currentDropTarget) {
					e.dragObject = tempDragObj;

					// NOTE: we can't get anything but the current drop target
					// here since the drag shadow blocks mouse-over events.
					// This is probelematic for dropping "in" something
					var ce = this.currentDropTarget.domNode.childNodes;
					if(ce.length > 0){
						e.dropTarget = ce[0];
						while(e.dropTarget == tempDragObj.domNode){
							e.dropTarget = e.dropTarget.nextSibling;
						}
					}else{
						e.dropTarget = this.currentDropTarget.domNode;
					}
					if(this.dropAcceptable){
						ret = this.currentDropTarget.onDrop(e);
					}else{
						 this.currentDropTarget.onDragOut(e);
					}
				}

				e.dragStatus = this.dropAcceptable && ret ? "dropSuccess" : "dropFailure";
				// decouple the calls for onDragEnd, so they don't block the execution here
				// ie. if the onDragEnd would call an alert, the execution here is blocked until the
				// user has confirmed the alert box and then the rest of the dnd code is executed
				// while the mouse doesnt "hold" the dragged object anymore ... and so on
				dojo.lang.delayThese([
					function() {
						// in FF1.5 this throws an exception, see 
						// http://dojotoolkit.org/pipermail/dojo-interest/2006-April/006751.html
						try{
							tempDragObj.dragSource.onDragEnd(e)
						} catch(err) {
							// since the problem seems passing e, we just copy all 
							// properties and try the copy ...
							var ecopy = {};
							for (var i in e) {
								if (i=="type") { // the type property contains the exception, no idea why...
									ecopy.type = "mouseup";
									continue;
								}
								ecopy[i] = e[i];
							}
							tempDragObj.dragSource.onDragEnd(ecopy);
						}
					}
					, function() {tempDragObj.onDragEnd(e)}]);
			}, this);

			this.selectedSources = [];
			this.dragObjects = [];
			this.dragSource = null;
			if(this.currentDropTarget) {
				this.currentDropTarget.onDropEnd();
			}
		} else {
			//dojo.debug("special click");
		}

		dojo.event.disconnect(document, "onmousemove", this, "onMouseMove");
		this.currentDropTarget = null;
	},

	onScroll: function(){
		//dojo.profile.start("DNDManager updateoffset");
		for(var i = 0; i < this.dragObjects.length; i++) {
			if(this.dragObjects[i].updateDragOffset) {
				this.dragObjects[i].updateDragOffset();
			}
		}
		//dojo.profile.end("DNDManager updateoffset");

		// TODO: do not recalculate, only adjust coordinates
		if (this.dragObjects.length) {
			this.cacheTargetLocations();
		}
	},

	_dragStartDistance: function(x, y){
		if((!this.mouseDownX)||(!this.mouseDownX)){
			return;
		}
		var dx = Math.abs(x-this.mouseDownX);
		var dx2 = dx*dx;
		var dy = Math.abs(y-this.mouseDownY);
		var dy2 = dy*dy;
		return parseInt(Math.sqrt(dx2+dy2), 10);
	},

	cacheTargetLocations: function(){
		dojo.profile.start("cacheTargetLocations");

		this.dropTargetDimensions = [];
		dojo.lang.forEach(this.dropTargets, function(tempTarget){
			var tn = tempTarget.domNode;
			//only cache dropTarget which can accept current dragSource
			if(!tn || dojo.lang.find(tempTarget.acceptedTypes, this.dragSource.type) < 0){ return; }
			var abs = dojo.html.getAbsolutePosition(tn, true);
			var bb = dojo.html.getBorderBox(tn);
			this.dropTargetDimensions.push([
				[abs.x, abs.y],	// upper-left
				// lower-right
				[ abs.x+bb.width, abs.y+bb.height ],
				tempTarget
			]);
			//dojo.debug("Cached for "+tempTarget)
		}, this);

		dojo.profile.end("cacheTargetLocations");

		//dojo.debug("Cache locations")
	},

	onMouseMove: function(e){
		if((dojo.render.html.ie)&&(e.button != 1)){
			// Oooops - mouse up occurred - e.g. when mouse was not over the
			// window. I don't think we can detect this for FF - but at least
			// we can be nice in IE.
			this.currentDropTarget = null;
			this.onMouseUp(e, true);
			return;
		}

		// if we've got some sources, but no drag objects, we need to send
		// onDragStart to all the right parties and get things lined up for
		// drop target detection

		if(	(this.selectedSources.length)&&
			(!this.dragObjects.length) ){
			var dx;
			var dy;
			if(!this._dragTriggered){
				this._dragTriggered = (this._dragStartDistance(e.pageX, e.pageY) > this.threshold);
				if(!this._dragTriggered){ return; }
				dx = e.pageX - this.mouseDownX;
				dy = e.pageY - this.mouseDownY;
			}

			// the first element is always our dragSource, if there are multiple
			// selectedSources (elements that move along) then the first one is the master
			// and for it the events will be fired etc.
			this.dragSource = this.selectedSources[0];
			
			dojo.lang.forEach(this.selectedSources, function(tempSource){
				if(!tempSource){ return; }
				var tdo = tempSource.onDragStart(e);
				if(tdo){
					tdo.onDragStart(e);

					// "bump" the drag object to account for the drag threshold
					tdo.dragOffset.y += dy;
					tdo.dragOffset.x += dx;
					tdo.dragSource = tempSource;

					this.dragObjects.push(tdo);
				}
			}, this);

			/* clean previous drop target in dragStart */
			this.previousDropTarget = null;

			this.cacheTargetLocations();
		}

		// FIXME: we need to add dragSources and dragObjects to e
		dojo.lang.forEach(this.dragObjects, function(dragObj){
			if(dragObj){ dragObj.onDragMove(e); }
		});

		// if we have a current drop target, check to see if we're outside of
		// it. If so, do all the actions that need doing.
		if(this.currentDropTarget){
			//dojo.debug(dojo.html.hasParent(this.currentDropTarget.domNode))
			var c = dojo.html.toCoordinateObject(this.currentDropTarget.domNode, true);
			//		var dtp = this.currentDropTargetPoints;
			var dtp = [
				[c.x,c.y], [c.x+c.width, c.y+c.height]
			];
		}

		if((!this.nestedTargets)&&(dtp)&&(this.isInsideBox(e, dtp))){
			if(this.dropAcceptable){
				this.currentDropTarget.onDragMove(e, this.dragObjects);
			}
		}else{
			// FIXME: need to fix the event object!
			// see if we can find a better drop target
			var bestBox = this.findBestTarget(e);

			if(bestBox.target === null){
				if(this.currentDropTarget){
					this.currentDropTarget.onDragOut(e);
					this.previousDropTarget = this.currentDropTarget;
					this.currentDropTarget = null;
					// this.currentDropTargetPoints = null;
				}
				this.dropAcceptable = false;
				return;
			}

			if(this.currentDropTarget !== bestBox.target){
				if(this.currentDropTarget){
					this.previousDropTarget = this.currentDropTarget;
					this.currentDropTarget.onDragOut(e);
				}
				this.currentDropTarget = bestBox.target;
				// this.currentDropTargetPoints = bestBox.points;
				e.dragObjects = this.dragObjects;
				this.dropAcceptable = this.currentDropTarget.onDragOver(e);

			}else{
				if(this.dropAcceptable){
					this.currentDropTarget.onDragMove(e, this.dragObjects);
				}
			}
		}
	},

	findBestTarget: function(e) {
		var _this = this;
		var bestBox = new Object();
		bestBox.target = null;
		bestBox.points = null;
		dojo.lang.every(this.dropTargetDimensions, function(tmpDA) {
			if(!_this.isInsideBox(e, tmpDA)){
				return true;
			}

			bestBox.target = tmpDA[2];
			bestBox.points = tmpDA;
			// continue iterating only if _this.nestedTargets == true
			return Boolean(_this.nestedTargets);
		});

		return bestBox;
	},

	isInsideBox: function(e, coords){
		if(	(e.pageX > coords[0][0])&&
			(e.pageX < coords[1][0])&&
			(e.pageY > coords[0][1])&&
			(e.pageY < coords[1][1]) ){
			return true;
		}
		return false;
	},

	onMouseOver: function(e){
	},

	onMouseOut: function(e){
	}
});

dojo.dnd.dragManager = new dojo.dnd.HtmlDragManager();

// global namespace protection closure
(function(){
	var d = document;
	var dm = dojo.dnd.dragManager;
	//TODO: when focus manager is ready, dragManager should be rewritten to use it
	// set up event handlers on the document (or no?)
	dojo.event.connect(d, "onkeydown", dm, "onKeyDown");
	dojo.event.connect(d, "onmouseover", dm, "onMouseOver");
	dojo.event.connect(d, "onmouseout", dm, "onMouseOut");
	dojo.event.connect(d, "onmousedown", dm, "onMouseDown");
	dojo.event.connect(d, "onmouseup", dm, "onMouseUp");
	// TODO: process scrolling of elements, not only window (focus manager would 
	// probably come to rescue here as well)
	dojo.event.connect(window, "onscroll", dm, "onScroll");
})();

__CPAN_FILE__ src/dnd/HtmlDragCopy.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.dnd.HtmlDragCopy");
dojo.require("dojo.dnd.*");

dojo.declare("dojo.dnd.HtmlDragCopySource", dojo.dnd.HtmlDragSource,
function(node, type, copyOnce){
		this.copyOnce = copyOnce;
		this.makeCopy = true;
},
{
	onDragStart: function(){
		var dragObj = new dojo.dnd.HtmlDragCopyObject(this.dragObject, this.type, this);
		if(this.dragClass) { dragObj.dragClass = this.dragClass; }

		if (this.constrainToContainer) {
			dragObj.constrainTo(this.constrainingContainer || this.domNode.parentNode);
		}

		return dragObj;
	},
	onSelected: function() {
		for (var i=0; i<this.dragObjects.length; i++) {
			dojo.dnd.dragManager.selectedSources.push(new dojo.dnd.HtmlDragCopySource(this.dragObjects[i]));
		}
	}
});

dojo.declare("dojo.dnd.HtmlDragCopyObject", dojo.dnd.HtmlDragObject,
function(dragObject, type, source){
		this.copySource = source;
},
{
	onDragStart: function(e) {
		dojo.dnd.HtmlDragCopyObject.superclass.onDragStart.apply(this, arguments);
		if(this.copySource.makeCopy) {
			this.sourceNode = this.domNode;
			this.domNode    = this.domNode.cloneNode(true);
		}
	},
	onDragEnd: function(e){
		switch(e.dragStatus){
			case "dropFailure": // slide back to the start
				var startCoords = dojo.html.getAbsolutePosition(this.dragClone, true);
				// offset the end so the effect can be seen
				var endCoords = { left: this.dragStartPosition.x + 1,
					top: this.dragStartPosition.y + 1};

				// animate
				var anim = dojo.lfx.slideTo(this.dragClone, endCoords, 500, dojo.lfx.easeOut);
				var dragObject = this;
				dojo.event.connect(anim, "onEnd", function (e) {
					// pause for a second (not literally) and disappear
					dojo.lang.setTimeout(function() {
							dojo.html.removeNode(dragObject.dragClone);
							dragObject.dragClone = null;
							if(dragObject.copySource.makeCopy) {
								dojo.html.removeNode(dragObject.domNode);
								dragObject.domNode = dragObject.sourceNode;
								dragObject.sourceNode = null;
							}
						},
						200);
				});
				anim.play();
				dojo.event.topic.publish('dragEnd', { source: this } );
				return;
		}
		dojo.dnd.HtmlDragCopyObject.superclass.onDragEnd.apply(this, arguments);
		this.copySource.dragObject = this.domNode;
		if(this.copySource.copyOnce){
			this.copySource.makeCopy = false;
		}
		new dojo.dnd.HtmlDragCopySource(this.sourceNode, this.type, this.copySource.copyOnce);
		this.sourceNode = null;
	}
});

__CPAN_FILE__ src/dnd/HtmlDragMove.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.dnd.HtmlDragMove");
dojo.require("dojo.dnd.*");

dojo.declare("dojo.dnd.HtmlDragMoveSource", dojo.dnd.HtmlDragSource, {
	onDragStart: function(){
		var dragObj =  new dojo.dnd.HtmlDragMoveObject(this.dragObject, this.type);
		if (this.constrainToContainer) {
			dragObj.constrainTo(this.constrainingContainer);
		}
		return dragObj;
	},
	/*
	 * see dojo.dnd.HtmlDragSource.onSelected
	 */
	onSelected: function() {
		for (var i=0; i<this.dragObjects.length; i++) {
			dojo.dnd.dragManager.selectedSources.push(new dojo.dnd.HtmlDragMoveSource(this.dragObjects[i]));
		}
	}
});

dojo.declare("dojo.dnd.HtmlDragMoveObject", dojo.dnd.HtmlDragObject, {
	onDragEnd: function(e){
		// shortly the browser will fire an onClick() event,
		// but since this was really a drag, just squelch it
		dojo.event.connect(this.domNode, "onclick", this, "squelchOnClick");
	},
	onDragStart: function(e){
		dojo.html.clearSelection();

		this.dragClone = this.domNode;

		this.scrollOffset = dojo.html.getScroll().offset;
		this.dragStartPosition = dojo.html.abs(this.domNode, true);
		
		this.dragOffset = {y: this.dragStartPosition.y - e.pageY,
			x: this.dragStartPosition.x - e.pageX};

		this.containingBlockPosition = this.domNode.offsetParent ? 
			dojo.html.abs(this.domNode.offsetParent, true) : {x:0, y:0};

		this.dragClone.style.position = "absolute";

		if (this.constrainToContainer) {
			this.constraints = this.getConstraints();
		}
	},
	/**
	 * Set the position of the drag node.  (x,y) is relative to <body>.
	 */
	setAbsolutePosition: function(x, y){
		// The drag clone is attached to it's constraining container so offset for that
		if(!this.disableY) { this.domNode.style.top = (y-this.containingBlockPosition.y) + "px"; }
		if(!this.disableX) { this.domNode.style.left = (x-this.containingBlockPosition.x) + "px"; }
	}
});

__CPAN_FILE__ src/dnd/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: ["dojo.dnd.DragAndDrop"],
	browser: ["dojo.dnd.HtmlDragAndDrop"],
	dashboard: ["dojo.dnd.HtmlDragAndDrop"]
});
dojo.provide("dojo.dnd.*");

__CPAN_FILE__ src/dnd/HtmlDragAndDrop.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.dnd.HtmlDragAndDrop");

dojo.require("dojo.dnd.HtmlDragManager");
dojo.require("dojo.dnd.DragAndDrop");

dojo.require("dojo.html.*");
dojo.require("dojo.html.display");
dojo.require("dojo.html.util");
dojo.require("dojo.html.selection");
dojo.require("dojo.html.iframe");
dojo.require("dojo.lang.extras");
dojo.require("dojo.lfx.*");
dojo.require("dojo.event.*");

dojo.declare("dojo.dnd.HtmlDragSource", dojo.dnd.DragSource, {
	dragClass: "", // CSS classname(s) applied to node when it is being dragged

	onDragStart: function(){
		var dragObj = new dojo.dnd.HtmlDragObject(this.dragObject, this.type);
		if(this.dragClass) { dragObj.dragClass = this.dragClass; }

		if (this.constrainToContainer) {
			dragObj.constrainTo(this.constrainingContainer || this.domNode.parentNode);
		}

		return dragObj;
	},

	setDragHandle: function(node){
		node = dojo.byId(node);
		dojo.dnd.dragManager.unregisterDragSource(this);
		this.domNode = node;
		dojo.dnd.dragManager.registerDragSource(this);
	},

	setDragTarget: function(node){
		this.dragObject = node;
	},

	constrainTo: function(container) {
		this.constrainToContainer = true;
		if (container) {
			this.constrainingContainer = container;
		}
	},
	
	/*
	*
	* see dojo.dnd.DragSource.onSelected
	*/
	onSelected: function() {
		for (var i=0; i<this.dragObjects.length; i++) {
			dojo.dnd.dragManager.selectedSources.push(new dojo.dnd.HtmlDragSource(this.dragObjects[i]));
		}
	},

	/**
	* Register elements that should be dragged along with
	* the actual DragSource.
	*
	* Example usage:
	* 	var dragSource = new dojo.dnd.HtmlDragSource(...);
	*	// add a single element
	*	dragSource.addDragObjects(dojo.byId('id1'));
	*	// add multiple elements to drag along
	*	dragSource.addDragObjects(dojo.byId('id2'), dojo.byId('id3'));
	*
	* el A dom node to add to the drag list.
	*/
	addDragObjects: function(/*DOMNode*/ el) {
		for (var i=0; i<arguments.length; i++) {
			this.dragObjects.push(arguments[i]);
		}
	}
}, function(node, type){
	node = dojo.byId(node);
	this.dragObjects = [];
	this.constrainToContainer = false;
	if(node){
		this.domNode = node;
		this.dragObject = node;
		// register us
		dojo.dnd.DragSource.call(this);
		// set properties that might have been clobbered by the mixin
		this.type = (type)||(this.domNode.nodeName.toLowerCase());
	}

});

dojo.declare("dojo.dnd.HtmlDragObject", dojo.dnd.DragObject, {
	dragClass: "",
	opacity: 0.5,
	createIframe: true,		// workaround IE6 bug

	// if true, node will not move in X and/or Y direction
	disableX: false,
	disableY: false,

	createDragNode: function() {
		var node = this.domNode.cloneNode(true);
		if(this.dragClass) { dojo.html.addClass(node, this.dragClass); }
		if(this.opacity < 1) { dojo.html.setOpacity(node, this.opacity); }
		if(node.tagName.toLowerCase() == "tr"){
			// dojo.debug("Dragging table row")
			// Create a table for the cloned row
			var doc = this.domNode.ownerDocument;
			var table = doc.createElement("table");
			var tbody = doc.createElement("tbody");
			table.appendChild(tbody);
			tbody.appendChild(node);

			// Set a fixed width to the cloned TDs
			var domTds = this.domNode.childNodes;
			var cloneTds = node.childNodes;
			for(var i = 0; i < domTds.length; i++){
			    if((cloneTds[i])&&(cloneTds[i].style)){
				    cloneTds[i].style.width = dojo.html.getContentBox(domTds[i]).width + "px";
			    }
			}
			node = table;
		}

		if((dojo.render.html.ie55||dojo.render.html.ie60) && this.createIframe){
			with(node.style) {
				top="0px";
				left="0px";
			}
			var outer = document.createElement("div");
			outer.appendChild(node);
			this.bgIframe = new dojo.html.BackgroundIframe(outer);
			outer.appendChild(this.bgIframe.iframe);
			node = outer;
		}
		node.style.zIndex = 999;

		return node;
	},

	onDragStart: function(e){
		dojo.html.clearSelection();

		this.scrollOffset = dojo.html.getScroll().offset;
		this.dragStartPosition = dojo.html.getAbsolutePosition(this.domNode, true);

		this.dragOffset = {y: this.dragStartPosition.y - e.pageY,
			x: this.dragStartPosition.x - e.pageX};

		this.dragClone = this.createDragNode();

		this.containingBlockPosition = this.domNode.offsetParent ? 
			dojo.html.getAbsolutePosition(this.domNode.offsetParent, true) : {x:0, y:0};

		if (this.constrainToContainer) {
			this.constraints = this.getConstraints();
		}

		// set up for dragging
		with(this.dragClone.style){
			position = "absolute";
			top = this.dragOffset.y + e.pageY + "px";
			left = this.dragOffset.x + e.pageX + "px";
		}

		dojo.body().appendChild(this.dragClone);

		// shortly the browser will fire an onClick() event,
		// but since this was really a drag, just squelch it
		dojo.event.connect(this.domNode, "onclick", this, "squelchOnClick");

		dojo.event.topic.publish('dragStart', { source: this } );
	},

	/** Return min/max x/y (relative to document.body) for this object) **/
	getConstraints: function() {
		if (this.constrainingContainer.nodeName.toLowerCase() == 'body') {
			var viewport = dojo.html.getViewport();
			var width = viewport.width;
			var height = viewport.height;
			var x = 0;
			var y = 0;
		} else {
			var content = dojo.html.getContentBox(this.constrainingContainer);
			width = content.width;
			height = content.height;
			x =
				this.containingBlockPosition.x +
				dojo.html.getPixelValue(this.constrainingContainer, "padding-left", true) +
				dojo.html.getBorderExtent(this.constrainingContainer, "left");
			y =
				this.containingBlockPosition.y +
				dojo.html.getPixelValue(this.constrainingContainer, "padding-top", true) +
				dojo.html.getBorderExtent(this.constrainingContainer, "top");
		}
		
		var mb = dojo.html.getMarginBox(this.domNode);
		return {
			minX: x,
			minY: y,
			maxX: x + width - mb.width,
			maxY: y + height - mb.height
		}
	},

	updateDragOffset: function() {
		var scroll = dojo.html.getScroll().offset;
		if(scroll.y != this.scrollOffset.y) {
			var diff = scroll.y - this.scrollOffset.y;
			this.dragOffset.y += diff;
			this.scrollOffset.y = scroll.y;
		}
		if(scroll.x != this.scrollOffset.x) {
			var diff = scroll.x - this.scrollOffset.x;
			this.dragOffset.x += diff;
			this.scrollOffset.x = scroll.x;
		}
	},

	/** Moves the node to follow the mouse */
	onDragMove: function(e){
		this.updateDragOffset();
		var x = this.dragOffset.x + e.pageX;
		var y = this.dragOffset.y + e.pageY;

		if (this.constrainToContainer) {
			if (x < this.constraints.minX) { x = this.constraints.minX; }
			if (y < this.constraints.minY) { y = this.constraints.minY; }
			if (x > this.constraints.maxX) { x = this.constraints.maxX; }
			if (y > this.constraints.maxY) { y = this.constraints.maxY; }
		}

		this.setAbsolutePosition(x, y);

		dojo.event.topic.publish('dragMove', { source: this } );
	},

	/**
	 * Set the position of the drag clone.  (x,y) is relative to <body>.
	 */
	setAbsolutePosition: function(x, y){
		// The drag clone is attached to document.body so this is trivial
		if(!this.disableY) { this.dragClone.style.top = y + "px"; }
		if(!this.disableX) { this.dragClone.style.left = x + "px"; }
	},


	/**
	 * If the drag operation returned a success we reomve the clone of
	 * ourself from the original position. If the drag operation returned
	 * failure we slide back over to where we came from and end the operation
	 * with a little grace.
	 */
	onDragEnd: function(e){
		switch(e.dragStatus){

			case "dropSuccess":
				dojo.html.removeNode(this.dragClone);
				this.dragClone = null;
				break;

			case "dropFailure": // slide back to the start
				var startCoords = dojo.html.getAbsolutePosition(this.dragClone, true);
				// offset the end so the effect can be seen
				var endCoords = { left: this.dragStartPosition.x + 1,
					top: this.dragStartPosition.y + 1};

				// animate
				var anim = dojo.lfx.slideTo(this.dragClone, endCoords, 500, dojo.lfx.easeOut);
				var dragObject = this;
				dojo.event.connect(anim, "onEnd", function (e) {
					// pause for a second (not literally) and disappear
					dojo.lang.setTimeout(function() {
							dojo.html.removeNode(dragObject.dragClone);
							// Allow drag clone to be gc'ed
							dragObject.dragClone = null;
						},
						200);
				});
				anim.play();
				break;
		}

		dojo.event.topic.publish('dragEnd', { source: this } );
	},

	squelchOnClick: function(e){
		// squelch this onClick() event because it's the result of a drag (it's not a real click)
		dojo.event.browser.stopEvent(e);

		// disconnect after a short delay to prevent "Null argument to unrollAdvice()" warning
		dojo.lang.setTimeout(function() {
				dojo.event.disconnect(this.domNode, "onclick", this, "squelchOnClick");
			},50);
	},

	constrainTo: function(container) {
		this.constrainToContainer=true;
		if (container) {
			this.constrainingContainer = container;
		} else {
			this.constrainingContainer = this.domNode.parentNode;
		}
	}
}, function(node, type){
	this.domNode = dojo.byId(node);
	this.type = type;
	this.constrainToContainer = false;
	this.dragSource = null;
});

dojo.declare("dojo.dnd.HtmlDropTarget", dojo.dnd.DropTarget, {
	vertical: false,
	onDragOver: function(e){
		if(!this.accepts(e.dragObjects)){ return false; }

		// cache the positions of the child nodes
		this.childBoxes = [];
		for (var i = 0, child; i < this.domNode.childNodes.length; i++) {
			child = this.domNode.childNodes[i];
			if (child.nodeType != dojo.html.ELEMENT_NODE) { continue; }
			var pos = dojo.html.getAbsolutePosition(child, true);
			var inner = dojo.html.getBorderBox(child);
			this.childBoxes.push({top: pos.y, bottom: pos.y+inner.height,
				left: pos.x, right: pos.x+inner.width, height: inner.height, 
				width: inner.width, node: child});
		}

		// TODO: use dummy node

		return true;
	},

	_getNodeUnderMouse: function(e){
		// find the child
		for (var i = 0, child; i < this.childBoxes.length; i++) {
			with (this.childBoxes[i]) {
				if (e.pageX >= left && e.pageX <= right &&
					e.pageY >= top && e.pageY <= bottom) { return i; }
			}
		}

		return -1;
	},

	createDropIndicator: function() {
		this.dropIndicator = document.createElement("div");
		with (this.dropIndicator.style) {
			position = "absolute";
			zIndex = 999;
			if(this.vertical){
				borderLeftWidth = "1px";
				borderLeftColor = "black";
				borderLeftStyle = "solid";
				height = dojo.html.getBorderBox(this.domNode).height + "px";
				top = dojo.html.getAbsolutePosition(this.domNode, true).y + "px";
			}else{
				borderTopWidth = "1px";
				borderTopColor = "black";
				borderTopStyle = "solid";
				width = dojo.html.getBorderBox(this.domNode).width + "px";
				left = dojo.html.getAbsolutePosition(this.domNode, true).x + "px";
			}
		}
	},

	onDragMove: function(e, dragObjects){
		var i = this._getNodeUnderMouse(e);

		if(!this.dropIndicator){
			this.createDropIndicator();
		}

		var gravity = this.vertical ? dojo.html.gravity.WEST : dojo.html.gravity.NORTH;
		var hide = false;
		if(i < 0) {
			if(this.childBoxes.length) {
				var before = (dojo.html.gravity(this.childBoxes[0].node, e) & gravity);
				if(before){ hide = true; }
			} else {
				var before = true;
			}
		} else {
			var child = this.childBoxes[i];
			var before = (dojo.html.gravity(child.node, e) & gravity);
			if(child.node === dragObjects[0].dragSource.domNode){
				hide = true;
			}else{
				var currentPosChild = before ? 
						(i>0?this.childBoxes[i-1]:child) : 
						(i<this.childBoxes.length-1?this.childBoxes[i+1]:child);
				if(currentPosChild.node === dragObjects[0].dragSource.domNode){
					hide = true;
				}
			}
		}

		if(hide){
			this.dropIndicator.style.display="none";
			return;
		}else{
			this.dropIndicator.style.display="";
		}

		this.placeIndicator(e, dragObjects, i, before);

		if(!dojo.html.hasParent(this.dropIndicator)) {
			dojo.body().appendChild(this.dropIndicator);
		}
	},

	/**
	 * Position the horizontal line that indicates "insert between these two items"
	 */
	placeIndicator: function(e, dragObjects, boxIndex, before) {
		var targetProperty = this.vertical ? "left" : "top";
		var child;
		if (boxIndex < 0) {
			if (this.childBoxes.length) {
				child = before ? this.childBoxes[0]
					: this.childBoxes[this.childBoxes.length - 1];
			} else {
				this.dropIndicator.style[targetProperty] = dojo.html.getAbsolutePosition(this.domNode, true)[this.vertical?"x":"y"] + "px";
			}
		} else {
			child = this.childBoxes[boxIndex];
		}
		if(child){
			this.dropIndicator.style[targetProperty] = (before ? child[targetProperty] : child[this.vertical?"right":"bottom"]) + "px";
			if(this.vertical){
				this.dropIndicator.style.height = child.height + "px";
				this.dropIndicator.style.top = child.top + "px";
			}else{
				this.dropIndicator.style.width = child.width + "px";
				this.dropIndicator.style.left = child.left + "px";
			}
		}
	},

	onDragOut: function(e) {
		if(this.dropIndicator) {
			dojo.html.removeNode(this.dropIndicator);
			delete this.dropIndicator;
		}
	},

	/**
	 * Inserts the DragObject as a child of this node relative to the
	 * position of the mouse.
	 *
	 * @return true if the DragObject was inserted, false otherwise
	 */
	onDrop: function(e){
		this.onDragOut(e);

		var i = this._getNodeUnderMouse(e);

		var gravity = this.vertical ? dojo.html.gravity.WEST : dojo.html.gravity.NORTH;
		if (i < 0) {
			if (this.childBoxes.length) {
				if (dojo.html.gravity(this.childBoxes[0].node, e) & gravity) {
					return this.insert(e, this.childBoxes[0].node, "before");
				} else {
					return this.insert(e, this.childBoxes[this.childBoxes.length-1].node, "after");
				}
			}
			return this.insert(e, this.domNode, "append");
		}

		var child = this.childBoxes[i];
		if (dojo.html.gravity(child.node, e) & gravity) {
			return this.insert(e, child.node, "before");
		} else {
			return this.insert(e, child.node, "after");
		}
	},

	insert: function(e, refNode, position) {
		var node = e.dragObject.domNode;

		if(position == "before") {
			return dojo.html.insertBefore(node, refNode);
		} else if(position == "after") {
			return dojo.html.insertAfter(node, refNode);
		} else if(position == "append") {
			refNode.appendChild(node);
			return true;
		}

		return false;
	}
}, function(node, types){
	if (arguments.length == 0) { return; }
	this.domNode = dojo.byId(node);
	dojo.dnd.DropTarget.call(this);
	if(types && dojo.lang.isString(types)) {
		types = [types];
	}
	this.acceptedTypes = types || [];
});

__CPAN_FILE__ src/dnd/TreeDragAndDrop.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
 * TreeDrag* specialized on managing subtree drags
 * It selects nodes and visualises what's going on,
 * but delegates real actions upon tree to the controller
 *
 * This code is considered a part of controller
*/

dojo.provide("dojo.dnd.TreeDragAndDrop");

dojo.require("dojo.dnd.HtmlDragAndDrop");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.html.layout");

dojo.dnd.TreeDragSource = function(node, syncController, type, treeNode){
	this.controller = syncController;
	this.treeNode = treeNode;

	dojo.dnd.HtmlDragSource.call(this, node, type);
}

dojo.inherits(dojo.dnd.TreeDragSource, dojo.dnd.HtmlDragSource);

dojo.lang.extend(dojo.dnd.TreeDragSource, {
	onDragStart: function(){
		/* extend adds functions to prototype */
		var dragObject = dojo.dnd.HtmlDragSource.prototype.onDragStart.call(this);
		//dojo.debugShallow(dragObject)

		dragObject.treeNode = this.treeNode;

		dragObject.onDragStart = dojo.lang.hitch(dragObject, function(e) {

			/* save selection */
			this.savedSelectedNode = this.treeNode.tree.selector.selectedNode;
			if (this.savedSelectedNode) {
				this.savedSelectedNode.unMarkSelected();
			}

			var result = dojo.dnd.HtmlDragObject.prototype.onDragStart.apply(this, arguments);


			/* remove background grid from cloned object */
			var cloneGrid = this.dragClone.getElementsByTagName('img');
			for(var i=0; i<cloneGrid.length; i++) {
				cloneGrid.item(i).style.backgroundImage='url()';
			}

			return result;


		});

		dragObject.onDragEnd = function(e) {

			/* restore selection */
			if (this.savedSelectedNode) {
				this.savedSelectedNode.markSelected();
			}
			//dojo.debug(e.dragStatus);

			return dojo.dnd.HtmlDragObject.prototype.onDragEnd.apply(this, arguments);
		}
		//dojo.debug(dragObject.domNode.outerHTML)


		return dragObject;
	},

	onDragEnd: function(e){


		 var res = dojo.dnd.HtmlDragSource.prototype.onDragEnd.call(this, e);


		 return res;
	}
});

// .......................................

dojo.dnd.TreeDropTarget = function(domNode, controller, type, treeNode){

	this.treeNode = treeNode;
	this.controller = controller; // I will sync-ly process drops
	
	dojo.dnd.HtmlDropTarget.apply(this, [domNode, type]);
}

dojo.inherits(dojo.dnd.TreeDropTarget, dojo.dnd.HtmlDropTarget);

dojo.lang.extend(dojo.dnd.TreeDropTarget, {

	autoExpandDelay: 1500,
	autoExpandTimer: null,


	position: null,

	indicatorStyle: "2px black solid",

	showIndicator: function(position) {

		// do not change style too often, cause of blinking possible
		if (this.position == position) {
			return;
		}

		//dojo.debug(position)

		this.hideIndicator();

		this.position = position;

		if (position == "before") {
			this.treeNode.labelNode.style.borderTop = this.indicatorStyle;
		} else if (position == "after") {
			this.treeNode.labelNode.style.borderBottom = this.indicatorStyle;
		} else if (position == "onto") {
			this.treeNode.markSelected();
		}


	},

	hideIndicator: function() {
		this.treeNode.labelNode.style.borderBottom="";
		this.treeNode.labelNode.style.borderTop="";
		this.treeNode.unMarkSelected();
		this.position = null;
	},



	// is the target possibly ok ?
	// This function is run on dragOver, but drop possibility is also determined by position over node
	// that's why acceptsWithPosition is called
	// doesnt take index into account ( can change while moving mouse w/o changing target )


	/**
	 * Coarse (tree-level) access check.
	 * We can't determine real accepts status w/o position
	*/
	onDragOver: function(e){
//dojo.debug("onDragOver for "+e);


		var accepts = dojo.dnd.HtmlDropTarget.prototype.onDragOver.apply(this, arguments);

		//dojo.debug("TreeDropTarget.onDragOver accepts:"+accepts)

		if (accepts && this.treeNode.isFolder && !this.treeNode.isExpanded) {
			this.setAutoExpandTimer();
		}

		return accepts;
	},

	/* Parent.onDragOver calls this function to get accepts status */
	accepts: function(dragObjects) {

		var accepts = dojo.dnd.HtmlDropTarget.prototype.accepts.apply(this, arguments);

		if (!accepts) return false;

		var sourceTreeNode = dragObjects[0].treeNode;

		if (dojo.lang.isUndefined(sourceTreeNode) || !sourceTreeNode || !sourceTreeNode.isTreeNode) {
			dojo.raise("Source is not TreeNode or not found");
		}

		if (sourceTreeNode === this.treeNode) return false;

		return true;
	},



	setAutoExpandTimer: function() {
		// set up autoexpand timer
		var _this = this;

		var autoExpand = function () {
			if (dojo.dnd.dragManager.currentDropTarget === _this) {
				_this.controller.expand(_this.treeNode);
			}
		}

		this.autoExpandTimer = dojo.lang.setTimeout(autoExpand, _this.autoExpandDelay);
	},


	getDNDMode: function() {
		return this.treeNode.tree.DNDMode;
	},
		

	getAcceptPosition: function(e, sourceTreeNode) {

		var DNDMode = this.getDNDMode();

		if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO &&
			// check if ONTO is allowed localy
			!(
			  !this.treeNode.actionIsDisabled(dojo.widget.TreeNode.prototype.actions.ADDCHILD) // check dynamically cause may change w/o regeneration of dropTarget
			  && sourceTreeNode.parent !== this.treeNode
			  && this.controller.canMove(sourceTreeNode, this.treeNode)
			 )
		) {
			// disable ONTO if can't move
			DNDMode &= ~dojo.widget.Tree.prototype.DNDModes.ONTO;
		}


		var position = this.getPosition(e, DNDMode);

		//dojo.debug(DNDMode & +" : "+position);


		// if onto is here => it was allowed before, no accept check is needed
		if (position=="onto" ||
			(!this.isAdjacentNode(sourceTreeNode, position)
			 && this.controller.canMove(sourceTreeNode, this.treeNode.parent)
			)
		) {
			return position;
		} else {
			return false;
		}

	},

	onDragOut: function(e) {
		this.clearAutoExpandTimer();

		this.hideIndicator();
	},


	clearAutoExpandTimer: function() {
		if (this.autoExpandTimer) {
			clearTimeout(this.autoExpandTimer);
			this.autoExpandTimer = null;
		}
	},



	onDragMove: function(e, dragObjects){

		var sourceTreeNode = dragObjects[0].treeNode;

		var position = this.getAcceptPosition(e, sourceTreeNode);

		if (position) {
			this.showIndicator(position);
		}

	},

	isAdjacentNode: function(sourceNode, position) {

		if (sourceNode === this.treeNode) return true;
		if (sourceNode.getNextSibling() === this.treeNode && position=="before") return true;
		if (sourceNode.getPreviousSibling() === this.treeNode && position=="after") return true;

		return false;
	},


	/* get DNDMode and see which position e fits */
	getPosition: function(e, DNDMode) {
		var node = dojo.byId(this.treeNode.labelNode);
		var mousey = e.pageY || e.clientY + dojo.body().scrollTop;
		var nodey = dojo.html.getAbsolutePosition(node).y;
		var height = dojo.html.getBorderBox(node).height;

		var relY = mousey - nodey;
		var p = relY / height;

		var position = ""; // "" <=> forbidden
		if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO
		  && DNDMode & dojo.widget.Tree.prototype.DNDModes.BETWEEN) {
			if (p<=0.3) {
				position = "before";
			} else if (p<=0.7) {
				position = "onto";
			} else {
				position = "after";
			}
		} else if (DNDMode & dojo.widget.Tree.prototype.DNDModes.BETWEEN) {
			if (p<=0.5) {
				position = "before";
			} else {
				position = "after";
			}
		}
		else if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO) {
			position = "onto";
		}


		return position;
	},



	getTargetParentIndex: function(sourceTreeNode, position) {

		var index = position == "before" ? this.treeNode.getParentIndex() : this.treeNode.getParentIndex()+1;
		if (this.treeNode.parent === sourceTreeNode.parent
		  && this.treeNode.getParentIndex() > sourceTreeNode.getParentIndex()) {
		  	index--;  // dragging a node is different for simple move bacause of before-after issues
		}

		return index;
	},


	onDrop: function(e){
		// onDragOut will clean position


		var position = this.position;

//dojo.debug(position);

		this.onDragOut(e);

		var sourceTreeNode = e.dragObject.treeNode;

		if (!dojo.lang.isObject(sourceTreeNode)) {
			dojo.raise("TreeNode not found in dragObject")
		}

		if (position == "onto") {
			return this.controller.move(sourceTreeNode, this.treeNode, 0);
		} else {
			var index = this.getTargetParentIndex(sourceTreeNode, position);
			return this.controller.move(sourceTreeNode, this.treeNode.parent, index);
		}

		//dojo.debug('drop2');



	}


});



dojo.dnd.TreeDNDController = function(treeController) {

	// I use this controller to perform actions
	this.treeController = treeController;

	this.dragSources = {};

	this.dropTargets = {};

}

dojo.lang.extend(dojo.dnd.TreeDNDController, {


	listenTree: function(tree) {
		//dojo.debug("Listen tree "+tree);
		dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
		dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
		dojo.event.topic.subscribe(tree.eventNames.moveTo, this, "onMoveTo");
		dojo.event.topic.subscribe(tree.eventNames.addChild, this, "onAddChild");
		dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
	},


	unlistenTree: function(tree) {
		//dojo.debug("Listen tree "+tree);
		dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
		dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
		dojo.event.topic.unsubscribe(tree.eventNames.moveTo, this, "onMoveTo");
		dojo.event.topic.unsubscribe(tree.eventNames.addChild, this, "onAddChild");
		dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
	},

	onTreeDestroy: function(message) {
		this.unlistenTree(message.source);
		// I'm not widget so don't use destroy() call and dieWithTree
	},

	onCreateDOMNode: function(message) {
		this.registerDNDNode(message.source);
	},

	onAddChild: function(message) {
		this.registerDNDNode(message.child);
	},

	onMoveFrom: function(message) {
		var _this = this;
		dojo.lang.forEach(
			message.child.getDescendants(),
			function(node) { _this.unregisterDNDNode(node); }
		);
	},

	onMoveTo: function(message) {
		var _this = this;
		dojo.lang.forEach(
			message.child.getDescendants(),
			function(node) { _this.registerDNDNode(node); }
		);
	},

	/**
	 * Controller(node model) creates DNDNodes because it passes itself to node for synchroneous drops processing
	 * I can't process DnD with events cause an event can't return result success/false
	*/
	registerDNDNode: function(node) {
		if (!node.tree.DNDMode) return;

//dojo.debug("registerDNDNode "+node);

		/* I drag label, not domNode, because large domNodes are very slow to copy and large to drag */

		var source = null;
		var target = null;

		if (!node.actionIsDisabled(node.actions.MOVE)) {
			//dojo.debug("reg source")
			var source = new dojo.dnd.TreeDragSource(node.labelNode, this, node.tree.widgetId, node);
			this.dragSources[node.widgetId] = source;
		}

		var target = new dojo.dnd.TreeDropTarget(node.labelNode, this.treeController, node.tree.DNDAcceptTypes, node);

		this.dropTargets[node.widgetId] = target;

	},


	unregisterDNDNode: function(node) {

		if (this.dragSources[node.widgetId]) {
			dojo.dnd.dragManager.unregisterDragSource(this.dragSources[node.widgetId]);
			delete this.dragSources[node.widgetId];
		}

		if (this.dropTargets[node.widgetId]) {
			dojo.dnd.dragManager.unregisterDropTarget(this.dropTargets[node.widgetId]);
			delete this.dropTargets[node.widgetId];
		}
	}





});

__CPAN_DIR__ src/graphics
__CPAN_FILE__ src/graphics/color.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.graphics.color");
dojo.require("dojo.gfx.color");

dojo.deprecated("dojo.graphics.color.Color is now dojo.gfx.color.Color.", "0.5");
dojo.graphics.color.Color = dojo.gfx.color.Color;

dojo.graphics.color.named = dojo.gfx.color.named;
dojo.graphics.color.blend = function(a, b, weight) {
	dojo.deprecated("dojo.graphics.color.blend is now dojo.gfx.color.blend", "0.5");
	return dojo.gfx.color.blend(a, b, weight);
}
dojo.graphics.color.blendHex = function(a, b, weight) {
	dojo.deprecated("dojo.graphics.color.blendHex is now dojo.gfx.color.blendHex", "0.5");
	return dojo.gfx.color.rgb2hex(dojo.gfx.color.blend(dojo.gfx.color.hex2rgb(a), dojo.gfx.color.hex2rgb(b), weight));
}
dojo.graphics.color.extractRGB = function(color) {
	dojo.deprecated("dojo.graphics.color.extractRGB is now dojo.gfx.color.extractRGB", "0.5");
	return dojo.gfx.color.extractRGB(color);
}
dojo.graphics.color.hex2rgb = function(hex) {
	dojo.deprecated("dojo.graphics.color.hex2rgb is now dojo.gfx.color.hex2rgb", "0.5");
	return dojo.gfx.color.hex2rgb(hex);
}
dojo.graphics.color.rgb2hex = function(r, g, b) {
	dojo.deprecated("dojo.graphics.color.rgb2hex is now dojo.gfx.color.rgb2hex", "0.5");
	return dojo.gfx.color.rgb2hex;
}

__CPAN_FILE__ src/graphics/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

// By default... don't pull in anything?  (todo: figure out what should be in list)
dojo.provide("dojo.graphics.*");

__CPAN_FILE__ src/graphics/Colorspace.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.graphics.Colorspace");
dojo.require("dojo.gfx.Colorspace");

dojo.deprecated("dojo.graphics.Colorspace: use dojo.gfx.Colorspace instead.", "0.5");
dojo.graphics.Colorspace = dojo.gfx.Colorspace;

__CPAN_DIR__ src/graphics/color
__CPAN_FILE__ src/graphics/color/hsl.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.graphics.color.hsl");
dojo.require("dojo.gfx.color.hsl");

dojo.deprecated("dojo.graphics.color.hsl has been replaced with dojo.gfx.color.hsl", "0.5");

dojo.graphics.color.rgb2hsl = function(r, g, b){
	dojo.deprecated("dojo.graphics.color.rgb2hsl has been replaced with dojo.gfx.color.rgb2hsl", "0.5");
	return dojo.gfx.color.rgb2hsl(r, g, b);
}
dojo.graphics.color.hsl2rgb = function(h, s, l){
	dojo.deprecated("dojo.graphics.color.hsl2rgb has been replaced with dojo.gfx.color.hsl2rgb", "0.5");
	return dojo.gfx.color.hsl2rgb(h, s, l);
}

dojo.graphics.color.hsl2hex = function(h, s, l){
	dojo.deprecated("dojo.graphics.color.hsl2hex has been replaced with dojo.gfx.color.hsl2hex", "0.5");
	return dojo.gfx.color.hsl2hex(h, s, l);
}

dojo.graphics.color.hex2hsl = function(hex){
	dojo.deprecated("dojo.graphics.color.hex2hsl has been replaced with dojo.gfx.color.hex2hsl", "0.5");
	return dojo.gfx.color.hex2hsl(hex);
}

__CPAN_FILE__ src/graphics/color/hsv.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.graphics.color.hsv");
dojo.require("dojo.gfx.color.hsv");

dojo.deprecated("dojo.graphics.color.hsv has been replaced by dojo.gfx.color.hsv", "0.5");

dojo.graphics.color.rgb2hsv = function(r, g, b){
	dojo.deprecated("dojo.graphics.color.rgb2hsv has been replaced by dojo.gfx.color.rgb2hsv", "0.5");
	return dojo.gfx.color.rgb2hsv(r, g, b);
}
dojo.graphics.color.hsv2rgb = function(h, s, v){
	dojo.deprecated("dojo.graphics.color.hsv2rgb has been replaced by dojo.gfx.color.hsv2rgb", "0.5");
	return dojo.gfx.color.hsv2rgb(h, s, v);
}

__CPAN_DIR__ src/widget
__CPAN_FILE__ src/widget/TreeEditor.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.RichText");

dojo.provide("dojo.widget.TreeEditor");

dojo.widget.defineWidget(
	"dojo.widget.TreeEditor",
	dojo.widget.HtmlWidget,
{
		
		
	singleLineMode: false, // enter saves
	saveOnBlur: true, // blur or new edit saves current
	sync: false,  // finish editing in sync/async mode
	selectOnOpen: true,
	
	controller: null,
		
	node: null,
	
	richTextParams: {},
	
	
	
	getContents: function() {
		return this.richText.getEditorContent();
	},
	
	open: function(node) {
		
		if (!this.richText) {
			this.richText = dojo.widget.createWidget("RichText", this.richTextParams, node.labelNode);
		
			dojo.event.connect("around", this.richText, "onKeyDown", this, "richText_onKeyDown" );
			dojo.event.connect(this.richText, "onBlur", this, "richText_onBlur" );
			
			var self = this;
			dojo.event.connect(this.richText, "onLoad", function(){
				if (self.selectOnOpen) {
					self.richText.execCommand("selectall");
				}
			});
		} else {
			this.richText.open(node.labelNode);
		}
		
		this.node = node;		
	},
	
	close: function(save) {
		
		this.richText.close(save);
		
		
		this.node = null;	
	},
	
	isClosed: function() {
		return !this.richText || this.richText.isClosed;
	},
	
	execCommand: function() {
		this.richText.execCommand.apply(this.richText, arguments);
	},
	
	richText_onKeyDown: function(invocation) {
		var e = invocation.args[0];
		if((!e)&&(this.object)) {
			e = dojo.event.browser.fixEvent(this.editor.window.event);
		}
		
		switch (e.keyCode) {
			case e.KEY_ESCAPE:
				this.finish(false);
				dojo.event.browser.stopEvent(e);		
				break;
			case e.KEY_ENTER:
				if( e.ctrlKey && !this.singleLineMode ) {
					this.execCommand( "inserthtml", "<br/>" );
							
				}
				else {
					this.finish(true);					
					//dojo.debug("finish");
				}
				dojo.event.browser.stopEvent(e);
				break;
			default:
				return invocation.proceed();
		}
	},
	
	richText_onBlur: function() {
		this.finish(this.saveOnBlur);
	},
	
	
	finish: function(save) {
		return this.controller.editLabelFinish(save, this.sync);
	}
		
		
	
});

__CPAN_FILE__ src/widget/Form.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Form");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.Form", dojo.widget.HtmlWidget,
	{
		isContainer: true,
   		templateString: "<form dojoAttachPoint='containerNode' dojoAttachEvent='onSubmit:onSubmit'></form>",
		formElements: [],

		postCreate: function(args,frag){
			for (var key in args) {
				if (key == "dojotype") continue;
				var attr= document.createAttribute(key);
      				attr.nodeValue=args[key];
      				this.containerNode.setAttributeNode(attr);
    			}
  		},
		_createFormElements: function() {
   			if(dojo.render.html.safari) {
				// bug in safari (not registering form-elements)
				var elems = ["INPUT", "SELECT", "TEXTAREA"];
				for (var k=0; k < elems.length; k++) {
					var list = this.containerNode.getElementsByTagName(elems[k]);
					for (var j=0,len2=list.length; j<len2; j++) {
						this.formElements.push(list[j]);
					}
				}
				// fixed in safari nightly
			} else {
				this.formElements=this.containerNode.elements;
			}
		},
		onSubmit: function(e) {
    			e.preventDefault();
  		},

		submit: function() {
			this.containerNode.submit();
		},

		_getFormElement: function(name) {
			for(var i=0, len=this.formElements.length; i<len; i++) {
				var element = this.formElements[i];
				if (element.name == name) {
					return element;
				} // if
			} // for
			return null;
		},

		_getObject: function(obj, searchString) {
			var namePath = [];
			namePath=searchString.split(".");
			var myObj=obj;
			var name=namePath[namePath.length-1];

			for(var j=0, len=namePath.length;j<len;++j) {
				var p=namePath[j];
				if (typeof(myObj[p]) == "undefined") {
					myObj[p]={};
				}
				myObj=myObj[p];
			}
			return myObj;
		},
		_setToContainers: function (obj, widget) {
			for(var i=0, len=widget.children.length; i<len; ++i) {
				if (widget.children[i].widgetType == "Repeater") {
					var rIndex=widget.children[i].pattern;
					var rIndexPos=rIndex.indexOf("%{index}");
					rIndex=rIndex.substr(0,rIndexPos-1);
					var myObj = this._getObject(obj, rIndex);
					if (typeof(myObj) == "object" && typeof(myObj.length) == "undefined") {
						myObj=[];
					}
					var rowCount = widget.children[i].getRowCount();
					if (myObj.length > rowCount) {
						for (var j=rowCount, len2=myObj.length; j<len2; j++) {
							widget.children[i].addRow();
						}
					} else if (myObj.length < rowCount) {
						for (var j=rowCount, len2=myObj.length; j>len2; j--) {
							widget.children[i].deleteRow(0);
						}
					}
					for (var j=0, len2=myObj.length;j<len2; ++j) {
						for (var key in myObj[j]) {
							var prefix = dojo.string.substituteParams(widget.children[i].index, {"index": "" + j});
							this._getFormElement(prefix+"."+key).value=myObj[j][key];
						}
					}
				}

				if (widget.children[i].isContainer) {
					this._setToContainers (obj, widget.children[i]);
					continue;
				}

				switch(widget.children[i].widgetType) {
					case "Checkbox":
						continue;
						break;
					case "DropdownDatePicker":
						if(widget.children[i].valueNode.value == "") {
							widget.children[i].inputNode.value="";
							widget.children[i].datePicker.storedDate="";
						} else {
							widget.children[i].datePicker.setDate(widget.children[i].valueNode.value);
							//widget.children[i].datePicker.date=dojo.widget.DatePicker.util.fromRfcDate(widget.children[i].valueNode.value);
							widget.children[i].onSetDate();
						}
						break;
					case "Select":
						//widget.children[i].setValue(myObj[name]);
						continue;
						break;
					case "ComboBox":
						//widget.children[i].setSelectedValue(myObj[name]);
						continue;
						break;
					default:
						break;
				}
			}
		},
		setValues: function(obj) {
			this._createFormElements();
			for(var i=0, len=this.formElements.length; i<len; i++) {
				var element = this.formElements[i];
				if (element.name == '') {continue};
				var namePath = new Array();
				namePath=element.name.split(".");
				var myObj=obj;
				var name=namePath[namePath.length-1];
				for(var j=1,len2=namePath.length;j<len2;++j) {
					var p=namePath[j - 1];
					if(typeof(myObj[p]) == "undefined") {
						myObj=undefined;
						break;
						//myObj[p]={}
					};
					myObj=myObj[p];
				}

				if (typeof(myObj) == "undefined") {
					continue;
				}

				var type=element.type;
				if (type == "hidden" || type == "text" || type == "textarea" || type == "password") {
					type = "text";
				}
				switch(type) {
					case "checkbox":
						this.formElements[i].checked=false;
						if (typeof(myObj[name]) == 'undefined') continue;
						for (var j=0,len2=myObj[name].length; j<len2; ++j) {
							if(element.value == myObj[name][j]) {
								element.checked=true;
							}
						}
						break;
					case "radio":
						this.formElements[i].checked=false;
						if (typeof(myObj[name]) == 'undefined') {continue};
						if (myObj[name] == this.formElements[i].value) {
							this.formElements[i].checked=true;
						}
						break;
					case "select-one":
						this.formElements[i].selectedIndex="0";
						for (var j=0,len2=element.options.length; j<len2; ++j) {
							if (element.options[j].value == myObj[name]) {
								element.options[j].selected=true;
							} else {
								//element.options[j].selected=false;
							}
						}
						break;
					case "text":
						var value="";
						if (typeof(myObj[name]) == 'string') {
							value = myObj[name];
						}
						this.formElements[i].value=value;
						break;
					default:
						//dojo.debug("Not supported type ("+type+")");
						break;
				}
      			}
			this._setToContainers(obj,this);
		},
		getValues: function() {
			this._createFormElements();
			var obj = { };

			for(var i=0,len=this.formElements.length; i<len; i++) {
				// FIXME: would be better to give it an attachPoint:
				var elm = this.formElements[i];
				var namePath = [];
				if (elm.name == '') { continue;}
				namePath=elm.name.split(".");
				var myObj=obj;
				var name=namePath[namePath.length-1];
				for(var j=1,len2=namePath.length;j<len2;++j) {
					var nameIndex = null;
					var p=namePath[j - 1];
					var nameA=p.split("[");
					if (nameA.length > 1) {
						if(typeof(myObj[nameA[0]]) == "undefined") {
							myObj[nameA[0]]=[ ];
						} // if
						nameIndex=parseInt(nameA[1]);
						if(typeof(myObj[nameA[0]][nameIndex]) == "undefined") {
							myObj[nameA[0]][nameIndex]={};
						}
					} else if(typeof(myObj[nameA[0]]) == "undefined") {
						myObj[nameA[0]]={}
					} // if

					if (nameA.length == 1) {
						myObj=myObj[nameA[0]];
					} else {
						myObj=myObj[nameA[0]][nameIndex];
					} // if
				} // for

				if ((elm.type != "checkbox" && elm.type != "radio") || (elm.type=="radio" && elm.checked)) {
					if(name == name.split("[")[0]) {
						myObj[name]=elm.value;
					} else {
						// can not set value when there is no name
					}
				} else if (elm.type == "checkbox" && elm.checked) {
					if(typeof(myObj[name]) == 'undefined') {
						myObj[name]=[ ];
					}
					myObj[name].push(elm.value);
				} // if
				name=undefined;
			} // for
		return obj;
	}
});

__CPAN_FILE__ src/widget/Widget.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Widget");

dojo.require("dojo.lang.func");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.lang.declare");
dojo.require("dojo.ns");
dojo.require("dojo.widget.Manager");
dojo.require("dojo.event.*");
dojo.require("dojo.a11y");

dojo.declare("dojo.widget.Widget", null,
	function(){
		//dojo.debug("NEW "+this.widgetType);
		// these properties aren't primitives and need to be created on a per-item
		// basis.
		this.children = [];
		// this.selection = new dojo.widget.Selection();
		// FIXME: need to replace this with context menu stuff
		this.extraArgs = {};
	},
{
	// FIXME: need to be able to disambiguate what our rendering context is
	//        here!
	//
	// needs to be a string with the end classname. Every subclass MUST
	// over-ride.
	//
	// base widget properties

	// Widget: the parent of this widget
	parent: null, 

	// NOTE: "children" and "extraArgs" re-defined in the constructor as they need to be local to the widget

	// Array:
	//		a list of all of the widgets that have been added as children of
	//		this component. Should only have values if isContainer is true.
	children: [],

	// Object:
	//		a map of properties which the widget system tried to assign from
	//		user input but did not correspond to any of the properties set on
	//		the class prototype. These names will also be available in all
	//		lower-case form in this map
	extraArgs: {},

	// obviously, top-level and modal widgets should set these appropriately

	// Boolean: should this widget eat all events that bubble up to it?
	isTopLevel:  false, 

	// Boolean: should this widget block other widgets?
	isModal: false, 

	// Boolean: should this widget respond to user input?
	isEnabled: true,

	// Boolean: have we hidden the widget via hide()?
	isHidden: false,

	// Boolean: can this widget contain other widgets?
	isContainer: false, 

	// String:
	//		a unique, opaque ID string that can be assigned by users or by the
	//		system. If the developer passes an ID which is known not to be
	//		unique, the specified ID is ignored and the system-generated ID is
	//		used instead.
	widgetId: "",

	// String: used for building generic widgets
	widgetType: "Widget",

	// String: defaults to 'dojo'.  "namespace" is a reserved word in JavaScript, so we abbreviate
	ns: "dojo",

	getNamespacedType: function(){ 
		// summary:
		//		get the "full" name of the widget. If the widget comes from the
		//		"dojo" namespace and is a Button, calling this method will
		//		return "dojo:button", all lower-case
		return (this.ns ? this.ns + ":" + this.widgetType : this.widgetType).toLowerCase(); // String
	},
	
	toString: function(){
		// summary:
		//		returns a string that represents the widget. When a widget is
		//		cast to a string, this method will be used to generate the
		//		output. Currently, it does not implement any sort of reversable
		//		serialization.
		return '[Widget ' + this.getNamespacedType() + ', ' + (this.widgetId || 'NO ID') + ']'; // String
	},

	repr: function(){
		// summary: returns the string representation of the widget.
		return this.toString(); // String
	},

	enable: function(){
		// summary:
		//		enables the widget, usually involving unmasking inputs and
		//		turning on event handlers. Not implemented here.
		this.isEnabled = true;
	},

	disable: function(){
		// summary:
		//		disables the widget, usually involves masking inputs and
		//		unsetting event handlers. Not implemented here.
		this.isEnabled = false;
	},

	hide: function(){
		// summary: hides the widget from view. Not implemented here.
		this.isHidden = true;
	},

	show: function(){
		// summary: re-adds the widget to the view. Not implemented here.
		this.isHidden = false;
	},

	onResized: function(){
		// summary:
		//		A signal that widgets will call when they have been resized.
		//		Can be connected to for determining if a layout needs to be
		//		reflowed. Clients should override this function to do special
		//		processing, then call this.notifyChildrenOfResize() to notify
		//		children of resize.
		this.notifyChildrenOfResize();
	},
	
	notifyChildrenOfResize: function(){
		// summary: dispatches resized events to all children of this widget
		for(var i=0; i<this.children.length; i++){
			var child = this.children[i];
			//dojo.debug(this.widgetId + " resizing child " + child.widgetId);
			if( child.onResized ){
				child.onResized();
			}
		}
	},

	create: function(/*Object*/ args, /*Object*/fragment, /*Widget, optional*/parent, /*String, optional*/ns){
		// summary:
		//		'create' manages the initialization part of the widget
		//		lifecycle. It's called implicitly when any widget is created.
		//		All other initialization functions for widgets, except for the
		//		constructor, are called as a result of 'create' being fired.
		// args:
		//		a normalized view of the parameters that the widget should take
		// fragment:
		//		if the widget is being instantiated from markup, this object 
		// parent:
		//		the widget, if any, that this widget will be the child of.  If
		//		none is passed, the global default widget is used.
		// ns: what namespace the widget belongs to
		// description:
		//		to understand the process by which widgets are instantiated, it
		//		is critical to understand what other methods 'create' calls and
		//		which of them you'll want to over-ride. Of course, adventurous
		//		developers could over-ride 'create' entirely, but this should
		//		only be done as a last resort.
		//
		//		Below is a list of the methods that are called, in the order
		//		they are fired, along with notes about what they do and if/when
		//		you should over-ride them in your widget:
		//			
		//			mixInProperties:
		//				takes the args and does lightweight type introspection
		//				on pre-existing object properties to initialize widget
		//				values by casting the values that are passed in args
		//			postMixInProperties:
		//				a stub function that you can over-ride to modify
		//				variables that may have been naively assigned by
		//				mixInProperties
		//			# widget is added to manager object here
		//			buildRendering
		//				subclasses use this method to handle all UI initialization
		//			initialize:
		//				a stub function that you can over-ride.
		//			postInitialize:
		//				a stub function that you can over-ride.
		//			postCreate
		//				a stub function that you can over-ride to modify take
		//				actions once the widget has been placed in the UI
		//
		//		all of these functions are passed the same arguments as are
		//		passed to 'create'

		//dojo.profile.start(this.widgetType + " create");
		if(ns){
			this.ns = ns;
		}
		// dojo.debug(this.widgetType, "create");
		//dojo.profile.start(this.widgetType + " satisfyPropertySets");
		this.satisfyPropertySets(args, fragment, parent);
		//dojo.profile.end(this.widgetType + " satisfyPropertySets");
		// dojo.debug(this.widgetType, "-> mixInProperties");
		//dojo.profile.start(this.widgetType + " mixInProperties");
		this.mixInProperties(args, fragment, parent);
		//dojo.profile.end(this.widgetType + " mixInProperties");
		// dojo.debug(this.widgetType, "-> postMixInProperties");
		//dojo.profile.start(this.widgetType + " postMixInProperties");
		this.postMixInProperties(args, fragment, parent);
		//dojo.profile.end(this.widgetType + " postMixInProperties");
		// dojo.debug(this.widgetType, "-> dojo.widget.manager.add");
		dojo.widget.manager.add(this);
		// dojo.debug(this.widgetType, "-> buildRendering");
		//dojo.profile.start(this.widgetType + " buildRendering");
		this.buildRendering(args, fragment, parent);
		//dojo.profile.end(this.widgetType + " buildRendering");
		// dojo.debug(this.widgetType, "-> initialize");
		//dojo.profile.start(this.widgetType + " initialize");
		this.initialize(args, fragment, parent);
		//dojo.profile.end(this.widgetType + " initialize");
		// dojo.debug(this.widgetType, "-> postInitialize");
		// postinitialize includes subcomponent creation
		// profile is put directly to function
		this.postInitialize(args, fragment, parent);
		// dojo.debug(this.widgetType, "-> postCreate");
		//dojo.profile.start(this.widgetType + " postCreate");
		this.postCreate(args, fragment, parent);
		//dojo.profile.end(this.widgetType + " postCreate");
		// dojo.debug(this.widgetType, "done!");
		
		//dojo.profile.end(this.widgetType + " create");
		
		return this;
	},

	destroy: function(/*Boolean*/finalize){
		// summary:
		// 		Destroy this widget and it's descendants. This is the generic
		// 		"destructor" function that all widget users should call to
		// 		clealy discard with a widget. Once a widget is destroyed, it's
		// 		removed from the manager object.
		// finalize:
		//		is this function being called part of global environment
		//		tear-down?

		// FIXME: this is woefully incomplete
		this.destroyChildren();
		this.uninitialize();
		this.destroyRendering(finalize);
		dojo.widget.manager.removeById(this.widgetId);
	},

	destroyChildren: function(){
		// summary:
		//		Recursively destroy the children of this widget and their
		//		descendents.
		var widget;
		var i=0;
		while(this.children.length > i){
			widget = this.children[i];
			if (widget instanceof dojo.widget.Widget) { // find first widget
				this.removeChild(widget);
				widget.destroy();
				continue;
			}
			
			i++; // skip data object
		}
				
	},

	getChildrenOfType: function(/*String*/type, /*Boolean*/recurse){
		// summary: 
		//		return an array of descendant widgets who match the passed type
		// recurse:
		//		should we try to get all descendants that match? Defaults to
		//		false.
		var ret = [];
		var isFunc = dojo.lang.isFunction(type);
		if(!isFunc){
			type = type.toLowerCase();
		}
		for(var x=0; x<this.children.length; x++){
			if(isFunc){
				if(this.children[x] instanceof type){
					ret.push(this.children[x]);
				}
			}else{
				if(this.children[x].widgetType.toLowerCase() == type){
					ret.push(this.children[x]);
				}
			}
			if(recurse){
				ret = ret.concat(this.children[x].getChildrenOfType(type, recurse));
			}
		}
		return ret; // Array
	},

	getDescendants: function(){
		// summary: returns a flattened array of all direct descendants including self
		var result = [];
		var stack = [this];
		var elem;
		while ((elem = stack.pop())){
			result.push(elem);
			// a child may be data object without children field set (not widget)
			if (elem.children) {
				dojo.lang.forEach(elem.children, function(elem) { stack.push(elem); });
			}
		}
		return result; // Array
	},


	isFirstChild: function(){
		return this === this.parent.children[0]; // Boolean
	},

	isLastChild: function() {
		return this === this.parent.children[this.parent.children.length-1]; // Boolean
	},

	satisfyPropertySets: function(args){
		// summary: not implemented!

		// dojo.profile.start("satisfyPropertySets");
		// get the default propsets for our component type
		/*
		var typePropSets = []; // FIXME: need to pull these from somewhere!
		var localPropSets = []; // pull out propsets from the parser's return structure

		// for(var x=0; x<args.length; x++){
		// }

		for(var x=0; x<typePropSets.length; x++){
		}

		for(var x=0; x<localPropSets.length; x++){
		}
		*/
		// dojo.profile.end("satisfyPropertySets");
		
		return args;
	},

	mixInProperties: function(/*Object*/args, /*Object*/frag){
		// summary:
		// 		takes the list of properties listed in args and sets values of
		// 		the current object based on existence of properties with the
		// 		same name (case insensitive) and the type of the pre-existing
		// 		property. This is a lightweight conversion and is not intended
		// 		to capture custom type semantics.
		// args:
		//		A map of properties and values to set on the current object. By
		//		default it is assumed that properties in args are in string
		//		form and need to be converted. However, if there is a
		//		'fastMixIn' property with the value 'true' in the args param,
		//		this assumption is ignored and all values in args are copied
		//		directly to the current object without any form of type
		//		casting.
		// description:
		//		The mix-in code attempts to do some type-assignment based on
		//		PRE-EXISTING properties of the "this" object. When a named
		//		property of args is located, it is first tested to make
		//		sure that the current object already "has one". Properties
		//		which are undefined in the base widget are NOT settable here.
		//		The next step is to try to determine type of the pre-existing
		//		property. If it's a string, the property value is simply
		//		assigned. If a function, it is first cast using "new
		//		Function()" and the execution scope modified such that it
		//		always evaluates in the context of the current object. This
		//		listener is then added to the original function via
		//		dojo.event.connect(). If an Array, the system attempts to split
		//		the string value on ";" chars, and no further processing is
		//		attempted (conversion of array elements to a integers, for
		//		instance). If the property value is an Object
		//		(testObj.constructor === Object), the property is split first
		//		on ";" chars, secondly on ":" chars, and the resulting
		//		key/value pairs are assigned to an object in a map style. The
		//		onus is on the property user to ensure that all property values
		//		are converted to the expected type before usage. Properties
		//		which do not occur in the "this" object are assigned to the
		//		this.extraArgs map using both the original name and the
		//		lower-case name of the property. This allows for consistent
		//		access semantics regardless of the case preservation of the
		//		source of the property names.
		
		if((args["fastMixIn"])||(frag["fastMixIn"])){
			// dojo.profile.start("mixInProperties_fastMixIn");
			// fast mix in assumes case sensitivity, no type casting, etc...
			// dojo.lang.mixin(this, args);
			for(var x in args){
				this[x] = args[x];
			}
			// dojo.profile.end("mixInProperties_fastMixIn");
			return;
		}
		// dojo.profile.start("mixInProperties");

		var undef;

		// NOTE: we cannot assume that the passed properties are case-correct
		// (esp due to some browser bugs). Therefore, we attempt to locate
		// properties for assignment regardless of case. This may cause
		// problematic assignments and bugs in the future and will need to be
		// documented with big bright neon lights.

		// FIXME: fails miserably if a mixin property has a default value of null in 
		// a widget

		// NOTE: caching lower-cased args in the prototype is only 
		// acceptable if the properties are invariant.
		// if we have a name-cache, get it
		var lcArgs = dojo.widget.lcArgsCache[this.widgetType];
		if ( lcArgs == null ){
			// build a lower-case property name cache if we don't have one
			lcArgs = {};
			for(var y in this){
				lcArgs[((new String(y)).toLowerCase())] = y;
			}
			dojo.widget.lcArgsCache[this.widgetType] = lcArgs;
		}
		var visited = {};
		for(var x in args){
			if(!this[x]){ // check the cache for properties
				var y = lcArgs[(new String(x)).toLowerCase()];
				if(y){
					args[y] = args[x];
					x = y; 
				}
			}
			if(visited[x]){ continue; }
			visited[x] = true;
			if((typeof this[x]) != (typeof undef)){
				if(typeof args[x] != "string"){
					this[x] = args[x];
				}else{
					if(dojo.lang.isString(this[x])){
						this[x] = args[x];
					}else if(dojo.lang.isNumber(this[x])){
						this[x] = new Number(args[x]); // FIXME: what if NaN is the result?
					}else if(dojo.lang.isBoolean(this[x])){
						this[x] = (args[x].toLowerCase()=="false") ? false : true;
					}else if(dojo.lang.isFunction(this[x])){

						// FIXME: need to determine if always over-writing instead
						// of attaching here is appropriate. I suspect that we
						// might want to only allow attaching w/ action items.
						
						// RAR, 1/19/05: I'm going to attach instead of
						// over-write here. Perhaps function objects could have
						// some sort of flag set on them? Or mixed-into objects
						// could have some list of non-mutable properties
						// (although I'm not sure how that would alleviate this
						// particular problem)? 

						// this[x] = new Function(args[x]);

						// after an IRC discussion last week, it was decided
						// that these event handlers should execute in the
						// context of the widget, so that the "this" pointer
						// takes correctly.
						
						// argument that contains no punctuation other than . is 
						// considered a function spec, not code
						if(args[x].search(/[^\w\.]+/i) == -1){
							this[x] = dojo.evalObjPath(args[x], false);
						}else{
							var tn = dojo.lang.nameAnonFunc(new Function(args[x]), this);
							dojo.event.kwConnect({
								srcObj: this, 
								srcFunc: x, 
								adviceObj: this, 
								adviceFunc: tn
							});
						}
					}else if(dojo.lang.isArray(this[x])){ // typeof [] == "object"
						this[x] = args[x].split(";");
					} else if (this[x] instanceof Date) {
						this[x] = new Date(Number(args[x])); // assume timestamp
					}else if(typeof this[x] == "object"){ 
						// FIXME: should we be allowing extension here to handle
						// other object types intelligently?

						// if we defined a URI, we probably want to allow plain strings
						// to override it
						if (this[x] instanceof dojo.uri.Uri){

							this[x] = args[x];
						}else{

							// FIXME: unlike all other types, we do not replace the
							// object with a new one here. Should we change that?
							var pairs = args[x].split(";");
							for(var y=0; y<pairs.length; y++){
								var si = pairs[y].indexOf(":");
								if((si != -1)&&(pairs[y].length>si)){
									this[x][pairs[y].substr(0, si).replace(/^\s+|\s+$/g, "")] = pairs[y].substr(si+1);
								}
							}
						}
					}else{
						// the default is straight-up string assignment. When would
						// we ever hit this?
						this[x] = args[x];
					}
				}
			}else{
				// collect any extra 'non mixed in' args
				this.extraArgs[x.toLowerCase()] = args[x];
			}
		}
		// dojo.profile.end("mixInProperties");
	},
	
	postMixInProperties: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
		// summary:
		//		stub function. Can be over-ridden to handle advanced property
		//		casting and object configuration.
	},

	initialize: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
		// summary: stub function.
		return false;
		// dojo.unimplemented("dojo.widget.Widget.initialize");
	},

	postInitialize: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
		// summary: stub function.
		return false;
	},

	postCreate: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
		// summary: stub function.
		return false;
	},

	uninitialize: function(){
		// summary: 
		//		stub function. Over-ride to implement custom widget tear-down
		//		behavior.
		return false;
	},

	buildRendering: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		dojo.unimplemented("dojo.widget.Widget.buildRendering, on "+this.toString()+", ");
		return false;
	},

	destroyRendering: function(){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		dojo.unimplemented("dojo.widget.Widget.destroyRendering");
		return false;
	},

	cleanUp: function(){
		// summary: 
		//		stub function for destruction finalization. SUBCLASSES MUST
		//		IMPLEMENT
		dojo.unimplemented("dojo.widget.Widget.cleanUp");
		return false;
	},

	addedTo: function(/*Widget*/parent){
		// summary:
		//		stub function this is just a signal that can be caught
		// parent: instance of dojo.widget.Widget that we were added to
	},

	addChild: function(child){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		dojo.unimplemented("dojo.widget.Widget.addChild");
		return false;
	},

	// Detach the given child widget from me, but don't destroy it
	removeChild: function(/*Widget*/widget){
		// summary: 
		//		removes the passed widget instance from this widget but does
		//		not destroy it
		for(var x=0; x<this.children.length; x++){
			if(this.children[x] === widget){
				this.children.splice(x, 1);
				break;
			}
		}
		return widget; // Widget
	},

	resize: function(/*String or int*/width, /*String or int*/height){
		// summary:
		// 		both width and height may be set as percentages. The setWidth
		// 		and setHeight  functions attempt to determine if the passed
		// 		param is specified in percentage or native units. Integers
		// 		without a measurement are assumed to be in the native unit of
		// 		measure.
		// width:
		//		the width, either in native measures, or as a percentage. If as
		//		percentage, pass it as a string in the form "30%".
		// height:
		//		the height, either in native measures, or as a percentage. If as
		//		percentage, pass it as a string in the form "30%".
		this.setWidth(width);
		this.setHeight(height);
	},

	setWidth: function(/*String or int*/width){
		// summary: like it says on the tin...
		// width:
		//		the width, either in native measures, or as a percentage. If as
		//		percentage, pass it as a string in the form "30%".
		if((typeof width == "string")&&(width.substr(-1) == "%")){
			this.setPercentageWidth(width);
		}else{
			this.setNativeWidth(width);
		}
	},

	setHeight: function(/*String or int*/height){
		// summary: like it says on the tin...
		// height:
		//		the height, either in native measures, or as a percentage. If
		//		as percentage, pass it as a string in the form "30%".
		if((typeof height == "string")&&(height.substr(-1) == "%")){
			this.setPercentageHeight(height);
		}else{
			this.setNativeHeight(height);
		}
	},

	setPercentageHeight: function(/*int*/height){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		return false;
	},

	setNativeHeight: function(/*int*/height){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		return false;
	},

	setPercentageWidth: function(/*int*/width){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		return false;
	},

	setNativeWidth: function(/*int*/width){
		// summary: stub function. SUBCLASSES MUST IMPLEMENT
		return false;
	},

	getPreviousSibling: function(){
		// summary:
		//		returns null if this is the first child of the parent,
		//		otherwise returns the next sibling to the "left".
		var idx = this.getParentIndex();
 
		 // first node is idx=0 not found is idx<0
		if (idx<=0) return null;
 
		return this.parent.children[idx-1]; // Widget
	},
 
	getSiblings: function(){
		// summary: gets an array of all children of our parent, including "this"
		return this.parent.children; // Array
	},
 
	getParentIndex: function(){
		// summary: what index are we at in the parent's children array?
		return dojo.lang.indexOf(this.parent.children, this, true); // int
	},
 
	getNextSibling: function(){
		// summary:
		//		returns null if this is the last child of the parent,
		//		otherwise returns the next sibling to the "right".
 
		var idx = this.getParentIndex();
 
		if (idx == this.parent.children.length-1){return null;} // last node
		if (idx < 0){return null;} // not found
 
		return this.parent.children[idx+1]; // Widget
	}
});

// Lower case name cache: listing of the lower case elements in each widget.
// We can't store the lcArgs in the widget itself because if B subclasses A,
// then B.prototype.lcArgs might return A.prototype.lcArgs, which is not what we
// want
dojo.widget.lcArgsCache = {};

// TODO: should have a more general way to add tags or tag libraries?
// TODO: need a default tags class to inherit from for things like getting propertySets
// TODO: parse properties/propertySets into component attributes
// TODO: parse subcomponents
// TODO: copy/clone raw markup fragments/nodes as appropriate
dojo.widget.tags = {};
dojo.widget.tags.addParseTreeHandler = function(/*String*/type){
	// summary: deprecated!
	dojo.deprecated("addParseTreeHandler", ". ParseTreeHandlers are now reserved for components. Any unfiltered DojoML tag without a ParseTreeHandler is assumed to be a widget", "0.5");
	/*
	var ltype = type.toLowerCase();
	this[ltype] = function(fragment, widgetParser, parentComp, insertionIndex, localProps){
		var _ltype = ltype;
		dojo.profile.start(_ltype);
		var n = dojo.widget.buildWidgetFromParseTree(ltype, fragment, widgetParser, parentComp, insertionIndex, localProps);
		dojo.profile.end(_ltype);
		return n;
	}
	*/
}

//dojo.widget.tags.addParseTreeHandler("dojo:widget");

dojo.widget.tags["dojo:propertyset"] = function(fragment, widgetParser, parentComp){
	// FIXME: Is this needed?
	// FIXME: Not sure that this parses into the structure that I want it to parse into...
	// FIXME: add support for nested propertySets
	var properties = widgetParser.parseProperties(fragment["dojo:propertyset"]);
}

// FIXME: need to add the <dojo:connect />
dojo.widget.tags["dojo:connect"] = function(fragment, widgetParser, parentComp){
	var properties = widgetParser.parseProperties(fragment["dojo:connect"]);
}

// FIXME: if we know the insertion point (to a reasonable location), why then do we:
//	- create a template node
//	- clone the template node
//	- render the clone and set properties
//	- remove the clone from the render tree
//	- place the clone
// this is quite dumb
dojo.widget.buildWidgetFromParseTree = function(/*String*/				type,
												/*Object*/				frag, 
												/*dojo.widget.Parse*/	parser,
												/*Widget, optional*/	parentComp, 
												/*int, optional*/		insertionIndex,
												/*Object*/				localProps){

	// summary: creates a tree of widgets from the data structure produced by the first-pass parser (frag)
	
	// test for accessibility mode 
	dojo.a11y.setAccessibleMode();
	//dojo.profile.start("buildWidgetFromParseTree");
	// FIXME: for codepath from createComponentFromScript, we are now splitting a path 
	// that we already split and then joined
	var stype = type.split(":");
	stype = (stype.length == 2) ? stype[1] : type;
	
	// FIXME: we don't seem to be doing anything with this!
	// var propertySets = parser.getPropertySets(frag);
	var localProperties = localProps || parser.parseProperties(frag[frag["ns"]+":"+stype]);
	var twidget = dojo.widget.manager.getImplementation(stype,null,null,frag["ns"]);
	if(!twidget){
		throw new Error('cannot find "' + type + '" widget');
	}else if (!twidget.create){
		throw new Error('"' + type + '" widget object has no "create" method and does not appear to implement *Widget');
	}
	localProperties["dojoinsertionindex"] = insertionIndex;
	// FIXME: we lose no less than 5ms in construction!
	var ret = twidget.create(localProperties, frag, parentComp, frag["ns"]);
	// dojo.profile.end("buildWidgetFromParseTree");
	return ret;
}

dojo.widget.defineWidget = function(/*String*/			widgetClass, 
									/*String*/			renderer,
									/*function||array*/	superclasses, 
									/*function*/		init,
									/*Object*/			props){

	// summary: Create a widget constructor function (aka widgetClass)
	// widgetClass: the location in the object hierarchy to place the new widget class constructor
	// renderer: usually "html", determines when this delcaration will be used
	// superclasses:
	//		can be either a single function or an array of functions to be
	//		mixed in as superclasses. If an array, only the first will be used
	//		to set prototype inheritance.
	// init: an optional constructor function. Will be called after superclasses are mixed in.
	// props: a map of properties and functions to extend the class prototype with

	// This meta-function does parameter juggling for backward compat and overloading
	// if 4th argument is a string, we are using the old syntax
	// old sig: widgetClass, superclasses, props (object), renderer (string), init (function)
	if(dojo.lang.isString(arguments[3])){
		dojo.widget._defineWidget(arguments[0], arguments[3], arguments[1], arguments[4], arguments[2]);
	}else{
		// widgetClass
		var args = [ arguments[0] ], p = 3;
		if(dojo.lang.isString(arguments[1])){
			// renderer, superclass
			args.push(arguments[1], arguments[2]);
		}else{
			// superclass
			args.push('', arguments[1]);
			p = 2;
		}
		if(dojo.lang.isFunction(arguments[p])){
			// init (function), props (object) 
			args.push(arguments[p], arguments[p+1]);
		}else{
			// props (object) 
			args.push(null, arguments[p]);
		}
		dojo.widget._defineWidget.apply(this, args);
	}
}

dojo.widget.defineWidget.renderers = "html|svg|vml";

dojo.widget._defineWidget = function(widgetClass /*string*/, renderer /*string*/, superclasses /*function||array*/, init /*function*/, props /*object*/){
	// FIXME: uncomment next line to test parameter juggling ... remove when confidence improves
	// dojo.debug('(c:)' + widgetClass + '\n\n(r:)' + renderer + '\n\n(i:)' + init + '\n\n(p:)' + props);
	// widgetClass takes the form foo.bar.baz<.renderer>.WidgetName (e.g. foo.bar.baz.WidgetName or foo.bar.baz.html.WidgetName)
	var module = widgetClass.split(".");
	var type = module.pop(); // type <= WidgetName, module <= foo.bar.baz<.renderer>
	var regx = "\\.(" + (renderer ? renderer + '|' : '') + dojo.widget.defineWidget.renderers + ")\\.";
	var r = widgetClass.search(new RegExp(regx));
	module = (r < 0 ? module.join(".") : widgetClass.substr(0, r));

	// deprecated in favor of namespace system, remove for 0.5
	dojo.widget.manager.registerWidgetPackage(module);
	
	var pos = module.indexOf(".");
	var nsName = (pos > -1) ? module.substring(0,pos) : module;

	// FIXME: hrm, this might make things simpler
	//dojo.widget.tags.addParseTreeHandler(nsName+":"+type.toLowerCase());
	
	props=(props)||{};
	props.widgetType = type;
	if((!init)&&(props["classConstructor"])){
		init = props.classConstructor;
		delete props.classConstructor;
	}
	dojo.declare(widgetClass, superclasses, init, props);
}

__CPAN_FILE__ src/widget/DropdownDatePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DropdownDatePicker");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.DropdownContainer");
dojo.require("dojo.widget.DatePicker");
dojo.require("dojo.event.*");
dojo.require("dojo.html.*");
dojo.require("dojo.date.format");
dojo.require("dojo.date.serialize");
dojo.require("dojo.string.common");
dojo.require("dojo.i18n.common");
dojo.requireLocalization("dojo.widget", "DropdownDatePicker");

dojo.widget.defineWidget(
	"dojo.widget.DropdownDatePicker",
	dojo.widget.DropdownContainer,
	{
		/*
		summary: 
			A form input for entering dates with a pop-up dojo.widget.DatePicker to aid in selection

	 	description: 
			This is DatePicker in a DropdownContainer, it supports all features of DatePicker.
	
			The value displayed in the widget is localized according to the default algorithm provided
			in dojo.date.format and dojo.date.parse.  It is possible to customize the user-visible formatting
			with either the formatLength or displayFormat attributes.  The value sent to the server is
			typically a locale-independent value in a hidden field as defined by the name attribute.
			RFC3339 representation is used by default, but other options are available with saveFormat.

	 	usage: 
	 	              var ddp = dojo.widget.createWidget("DropdownDatePicker", {},   
	 	              dojo.byId("DropdownDatePickerNode")); 
	 	 
	 	              <input dojoType="DropdownDatePicker">
		*/

		iconURL: dojo.uri.dojoUri("src/widget/templates/images/dateIcon.gif"),
		zIndex: "10",

		//String
		// 	Type of visible formatting used, appropriate to locale (choice of long, short, medium or full)
		//  See dojo.date.format for details.
		formatLength: "short",
		//String
		// 	Pattern used to display formatted date.  Setting this overrides the locale-specific settings
		//  which are used by default.  See dojo.date.format for a reference which defines the formatting patterns.
		displayFormat: "",
		dateFormat: "", // deprecated in 0.5
		//String
		//	Formatting scheme used when submitting the form element.  This formatting is used in a hidden
		//  field (name) intended for server use, and is therefore typically locale-independent.
		//  By default, uses rfc3339 style date formatting (rfc)
		//	Use a pattern string like displayFormat or one of the following:
		//	rfc|iso|posix|unix
		saveFormat: "",
		//String|Date
		//	form value property if =='today' will default to todays date
		value: "", 
		//String
		// 	name of the form element, used to create a hidden field by this name for form element submission.
		name: "",

		// Implement various attributes from DatePicker

		//Integer
		//	total weeks to display default 
		displayWeeks: 6, 
		//Boolean
		//	if true, weekly size of calendar changes to accomodate the month if false, 42 day format is used
		adjustWeeks: false,
		//String|Date
		//	first available date in the calendar set
		startDate: "1492-10-12",
		//String|Date
		//	last available date in the calendar set
		endDate: "2941-10-12",
		//Integer
		//	adjusts the first day of the week 0==Sunday..6==Saturday
		weekStartsOn: "",
		//Boolean
		//	disable all incremental controls, must pick a date in the current display
		staticDisplay: false,
		
		postMixInProperties: function(localProperties, frag){
			// summary: see dojo.widget.DomWidget

			dojo.widget.DropdownDatePicker.superclass.postMixInProperties.apply(this, arguments);
			var messages = dojo.i18n.getLocalization("dojo.widget", "DropdownDatePicker", this.lang);
			this.iconAlt = messages.selectDate;
			
			if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
				this.value = new Date();
			}
			if(this.value && isNaN(this.value)){
				var orig = this.value;
				this.value = dojo.date.fromRfc3339(this.value);
				if(!this.value){this.value = new Date(orig); dojo.deprecated("dojo.widget.DropdownDatePicker", "date attributes must be passed in Rfc3339 format", "0.5");}
			}
			if(this.value && !isNaN(this.value)){
				this.value = new Date(this.value);
			}
		},

		fillInTemplate: function(args, frag){
			// summary: see dojo.widget.DomWidget
			dojo.widget.DropdownDatePicker.superclass.fillInTemplate.call(this, args, frag);
			//attributes to be passed on to DatePicker
			var dpArgs = {widgetContainerId: this.widgetId, lang: this.lang, value: this.value,
				startDate: this.startDate, endDate: this.endDate, displayWeeks: this.displayWeeks,
				weekStartsOn: this.weekStartsOn, adjustWeeks: this.adjustWeeks, staticDisplay: this.staticDisplay};

			//build the args for DatePicker based on the public attributes of DropdownDatePicker
			this.datePicker = dojo.widget.createWidget("DatePicker", dpArgs, this.containerNode, "child");
			dojo.event.connect(this.datePicker, "onValueChanged", this, "onSetDate");
			
			if(this.value){
				this.onSetDate();
			}
			this.containerNode.style.zIndex = this.zIndex;
			this.containerNode.explodeClassName = "calendarBodyContainer";
			this.valueNode.name=this.name;
		},

		getValue: function(){
			// summary: return current date in RFC 3339 format
			return this.valueNode.value; /*String*/
		},

		getDate: function(){
			// summary: return current date as a Date object
			return this.datePicker.value; /*Date*/
		},

		setValue: function(/*Date|String*/rfcDate){
			//summary: set the current date from RFC 3339 formatted string or a date object, synonymous with setDate
			this.setDate(rfcDate);
		},

		setDate: function(/*Date|String*/dateObj){
		//summary: set the current date and update the UI
			this.datePicker.setDate(dateObj);
			this._synchValueNode();
		},
	
		onSetDate: function(){
			if(this.dateFormat){
				dojo.deprecated("dojo.widget.DropdownDatePicker",
				"Must use displayFormat attribute instead of dateFormat.  See dojo.date.format for specification.", "0.5");
				this.inputNode.value = dojo.date.strftime(this.datePicker.value, this.dateFormat, this.lang);
			}else{
				this.inputNode.value = dojo.date.format(this.datePicker.value,
					{formatLength:this.formatLength, datePattern:this.displayFormat, selector:'dateOnly', locale:this.lang});
			}
			if(this.value < this.datePicker.startDate||this.value>this.datePicker.endDate){
				this.inputNode.value = "";
			}
			this._synchValueNode();
			this.onValueChanged(this.getDate());
			this.hideContainer();
		},

		onValueChanged: function(/*Date*/dateObj){
		//summary: triggered when this.value is changed
		},
		
		onInputChange: function(){
			if(this.dateFormat){
				dojo.deprecated("dojo.widget.DropdownDatePicker",
				"Cannot parse user input.  Must use displayFormat attribute instead of dateFormat.  See dojo.date.format for specification.", "0.5");
			}else{
				var input = dojo.string.trim(this.inputNode.value);
				if(input){
					var inputDate = dojo.date.parse(input,
							{formatLength:this.formatLength, datePattern:this.displayFormat, selector:'dateOnly', locale:this.lang});			
					if(inputDate){
						this.setDate(inputDate);
					}
				} else {
					this.valueNode.value = input;
				}
			}
			// If the date entered didn't parse, reset to the old date.  KISS, for now.
			//TODO: usability?  should we provide more feedback somehow? an error notice?
			// seems redundant to do this if the parse failed, but at least until we have validation,
			// this will fix up the display of entries like 01/32/2006
			if(input){ this.onSetDate(); }
		},

		_synchValueNode: function(){
			var date = this.datePicker.value;
			var value;
			switch(this.saveFormat.toLowerCase()){
				case "rfc": case "iso": case "":
					value = dojo.date.toRfc3339(date, 'dateOnly');
					break;
				case "posix": case "unix":
					value = Number(date);
					break;
				default:
					value = dojo.date.format(date, {datePattern:this.saveFormat, selector:'dateOnly', locale:this.lang});
			}
			this.valueNode.value = value;
		},
		
		enable: function() {
			this.inputNode.disabled = false;
			this.datePicker.enable();
			dojo.widget.DropdownDatePicker.superclass.enable.apply(this, arguments);
		},
		
		disable: function() {
			this.inputNode.disabled = true;
			this.datePicker.disable();
			dojo.widget.DropdownDatePicker.superclass.disable.apply(this, arguments);
		}
	}
);

__CPAN_FILE__ src/widget/Button.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Button");

dojo.require("dojo.lang.extras");
dojo.require("dojo.html.*");
dojo.require("dojo.html.selection");
dojo.require("dojo.widget.*");

/*
 * summary
 *	Basically the same thing as a normal HTML button, but with special styling.
 * usage
 *	<button dojoType="button" onClick="...">Hello world</button>
 *
 *  var button1 = dojo.widget.createWidget("Button", {caption: "hello world", onClick: foo});
 *	document.body.appendChild(button1.domNode);
 */
dojo.widget.defineWidget(
	"dojo.widget.Button",
	dojo.widget.HtmlWidget,
	{
		isContainer: true,

		// String
		//	text to display in button
		caption: "",
		
		// Boolean
		//	if true, cannot click button
		disabled: false,

		templatePath: dojo.uri.dojoUri("src/widget/templates/ButtonTemplate.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/ButtonTemplate.css"),
		
		// Url
		//	prefix of filename holding images (left, center, right) for button in normal state
		inactiveImg: "src/widget/templates/images/soriaButton-",
		
		// Url
		//	prefix of filename holding images (left, center, right) for button when it's being hovered over
		activeImg: "src/widget/templates/images/soriaActive-",

		// Url
		//	prefix of filename holding images (left, center, right) for button between mouse-down and mouse-up
		pressedImg: "src/widget/templates/images/soriaPressed-",

		// Url
		//	prefix of filename holding images (left, center, right) for button when it's disabled (aka, grayed-out)
		disabledImg: "src/widget/templates/images/soriaDisabled-",
		
		// Number
		//	shape of the button's end pieces;
		//	the height of the end pieces is a function of the button's height (which in turn is a function of the button's content),
		//	and then the width of the end pieces is relative to their height.
		width2height: 1.0/3.0,

		fillInTemplate: function(){
			if(this.caption){
				this.containerNode.appendChild(document.createTextNode(this.caption));
			}
			dojo.html.disableSelection(this.containerNode);
		},

		postCreate: function(){
			this._sizeMyself();
		},
	
		_sizeMyself: function(){
			// we cannot size correctly if any of our ancestors are hidden (display:none),
			// so temporarily attach to document.body
			if(this.domNode.parentNode){
				var placeHolder = document.createElement("span");
				dojo.html.insertBefore(placeHolder, this.domNode);
			}
			dojo.body().appendChild(this.domNode);
			
			this._sizeMyselfHelper();
			
			// Put this.domNode back where it was originally
			if(placeHolder){
				dojo.html.insertBefore(this.domNode, placeHolder);
				dojo.html.removeNode(placeHolder);
			}
		},

		_sizeMyselfHelper: function(){
			var mb = dojo.html.getMarginBox(this.containerNode);
			this.height = mb.height;
			this.containerWidth = mb.width;
			var endWidth= this.height * this.width2height;
	
			this.containerNode.style.left=endWidth+"px";
	
			this.leftImage.height = this.rightImage.height = this.centerImage.height = this.height;
			this.leftImage.width = this.rightImage.width = endWidth+1;
			this.centerImage.width = this.containerWidth;
			this.centerImage.style.left=endWidth+"px";
			this._setImage(this.disabled ? this.disabledImg : this.inactiveImg);

			if ( this.disabled ) {
				dojo.html.prependClass(this.domNode, "dojoButtonDisabled");
				this.domNode.removeAttribute("tabIndex");
				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", true);
			} else {
				dojo.html.removeClass(this.domNode, "dojoButtonDisabled");
				this.domNode.setAttribute("tabIndex", "0");
				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", false);
			}
				
			this.domNode.style.height=this.height + "px";
			this.domNode.style.width= (this.containerWidth+2*endWidth) + "px";
		},
	
		onMouseOver: function(/*Event*/ e){
			// summary: callback when user mouses-over the button
			if( this.disabled ){ return; }
			dojo.html.prependClass(this.buttonNode, "dojoButtonHover");
			this._setImage(this.activeImg);
		},
	
		onMouseDown: function(/*Event*/ e){
			// summary: callback when user starts to click the button
			if( this.disabled ){ return; }
			dojo.html.prependClass(this.buttonNode, "dojoButtonDepressed");
			dojo.html.removeClass(this.buttonNode, "dojoButtonHover");
			this._setImage(this.pressedImg);
		},

		onMouseUp: function(/*Event*/ e){
			// summary: callback when the user finishes clicking
			if( this.disabled ){ return; }
			dojo.html.prependClass(this.buttonNode, "dojoButtonHover");
			dojo.html.removeClass(this.buttonNode, "dojoButtonDepressed");
			this._setImage(this.activeImg);
		},
	
		onMouseOut: function(/*Event*/ e){
			// summary: callback when the user moves the mouse off the button
			if( this.disabled ){ return; }
			if( e.toElement && dojo.html.isDescendantOf(e.toElement, this.buttonNode) ){
				return; // Ignore IE mouseOut events that dont actually leave button - Prevents hover image flicker in IE
			}
			dojo.html.removeClass(this.buttonNode, "dojoButtonHover");
			this._setImage(this.inactiveImg);
		},

		onKey: function(/*Event*/ e){
			// summary: callback when the user presses a key (on key-down)
			if (!e.key) { return; }
			var menu = dojo.widget.getWidgetById(this.menuId);
			if (e.key == e.KEY_ENTER || e.key == " "){
				this.onMouseDown(e);
				this.buttonClick(e);
				dojo.lang.setTimeout(this, "onMouseUp", 75, e);
				dojo.event.browser.stopEvent(e);
			}
			if(menu && menu.isShowingNow && e.key == e.KEY_DOWN_ARROW){
				// disconnect onBlur when focus moves into menu
				dojo.event.disconnect(this.domNode, "onblur", this, "onBlur");
				// allow event to propagate to menu
			}
		},

		onFocus: function(/*Event*/ e){
			// summary: callback on focus to the button
			var menu = dojo.widget.getWidgetById(this.menuId);
			if (menu){
				dojo.event.connectOnce(this.domNode, "onblur", this, "onBlur");
			}
		},

		onBlur: function(/*Event*/ e){
			// summary: callback when button loses focus
			var menu = dojo.widget.getWidgetById(this.menuId);
			if ( !menu ) { return; }
	
			if ( menu.close && menu.isShowingNow ){
				menu.close();
			}
		},

		buttonClick: function(/*Event*/ e){
			// summary: internal function for handling button clicks
			if(!this.disabled){ 
				// focus may fail when tabIndex is not supported on div's
				// by the browser, or when the node is disabled
				try { this.domNode.focus(); } catch(e2) {};
				this.onClick(e); 
			}
		},

		onClick: function(/*Event*/ e) {
			// summary: callback for when button is clicked; user can override this function
		},

		_setImage: function(/*String*/ prefix){
			this.leftImage.src=dojo.uri.dojoUri(prefix + "l.gif");
			this.centerImage.src=dojo.uri.dojoUri(prefix + "c.gif");
			this.rightImage.src=dojo.uri.dojoUri(prefix + "r.gif");
		},
		
		_toggleMenu: function(/*String*/ menuId){
			var menu = dojo.widget.getWidgetById(menuId); 
			if ( !menu ) { return; }
			if ( menu.open && !menu.isShowingNow) {
				var pos = dojo.html.getAbsolutePosition(this.domNode, false);
				menu.open(pos.x, pos.y+this.height, this);
			} else if ( menu.close && menu.isShowingNow ){
				menu.close();
			} else {
				menu.toggle();
			}
		},
		
		setCaption: function(/*String*/ content){
			// summary: reset the caption (text) of the button; takes an HTML string
			this.caption=content;
			this.containerNode.innerHTML=content;
			this._sizeMyself();
		},
		
		setDisabled: function(/*Boolean*/ disabled){
			// summary: set disabled state of button
			this.disabled=disabled;
			this._sizeMyself();
		}
	});

/*
 * summary
 *	push the button and a menu shows up
 * usage
 *	<button dojoType="DropDownButton" menuId="mymenu">Hello world</button>
 *
 *  var button1 = dojo.widget.createWidget("DropDownButton", {caption: "hello world", menuId: foo});
 *	document.body.appendChild(button1.domNode);
 */
dojo.widget.defineWidget(
	"dojo.widget.DropDownButton",
	dojo.widget.Button,
	{
		// String
		//	widget id of the menu that this button should activate
		menuId: "",

		// Url
		//	path of arrow image to display to the right of the button text
		downArrow: "src/widget/templates/images/whiteDownArrow.gif",

		// Url
		//	path of arrow image to display to the right of the button text, when the button is disabled
		disabledDownArrow: "src/widget/templates/images/whiteDownArrow.gif",
	
		fillInTemplate: function(){
			dojo.widget.DropDownButton.superclass.fillInTemplate.apply(this, arguments);
	
			this.arrow = document.createElement("img");
			dojo.html.setClass(this.arrow, "downArrow");

			dojo.widget.wai.setAttr(this.domNode, "waiState", "haspopup", this.menuId);
		},

		_sizeMyselfHelper: function(){
			// draw the arrow (todo: why is the arror in containerNode rather than outside it?)
			this.arrow.src = dojo.uri.dojoUri(this.disabled ? this.disabledDownArrow : this.downArrow);
			this.containerNode.appendChild(this.arrow);

			dojo.widget.DropDownButton.superclass._sizeMyselfHelper.call(this);
		},

		onClick: function(/*Event*/ e){
			// summary: callback when button is clicked; user shouldn't override this function or else the menu won't toggle
			this._toggleMenu(this.menuId);
		}
	});

/*
 * summary
 *	left side is normal button, right side displays menu
 * usage
 *	<button dojoType="ComboButton" onClick="..." menuId="mymenu">Hello world</button>
 *
 *  var button1 = dojo.widget.createWidget("DropDownButton", {caption: "hello world", onClick: foo, menuId: "myMenu"});
 *	document.body.appendChild(button1.domNode);
 */
dojo.widget.defineWidget(
	"dojo.widget.ComboButton",
	dojo.widget.Button,
	{
		// String
		//	widget id of the menu that this button should activate
		menuId: "",
	
		templatePath: dojo.uri.dojoUri("src/widget/templates/ComboButtonTemplate.html"),
	
		// Integer
		//	# of pixels between left & right part of button
		splitWidth: 2,
		
		// Integer
		//	width of segment holding down arrow
		arrowWidth: 5,
	
		_sizeMyselfHelper: function(/*Event*/ e){
			var mb = dojo.html.getMarginBox(this.containerNode);
			this.height = mb.height;
			this.containerWidth = mb.width;

			var endWidth= this.height/3;

			if(this.disabled){
				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", true);
				this.domNode.removeAttribute("tabIndex");
			}
			else {
				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", false);
				this.domNode.setAttribute("tabIndex", "0");
			}
	
			// left part
			this.leftImage.height = this.rightImage.height = this.centerImage.height = 
				this.arrowBackgroundImage.height = this.height;
			this.leftImage.width = endWidth+1;
			this.centerImage.width = this.containerWidth;
			this.buttonNode.style.height = this.height + "px";
			this.buttonNode.style.width = endWidth + this.containerWidth + "px";
			this._setImage(this.disabled ? this.disabledImg : this.inactiveImg);

			// right part
			this.arrowBackgroundImage.width=this.arrowWidth;
			this.rightImage.width = endWidth+1;
			this.rightPart.style.height = this.height + "px";
			this.rightPart.style.width = this.arrowWidth + endWidth + "px";
			this._setImageR(this.disabled ? this.disabledImg : this.inactiveImg);
	
			// outer container
			this.domNode.style.height=this.height + "px";
			var totalWidth = this.containerWidth+this.splitWidth+this.arrowWidth+2*endWidth;
			this.domNode.style.width= totalWidth + "px";
		},
	
		_setImage: function(prefix){
			this.leftImage.src=dojo.uri.dojoUri(prefix + "l.gif");
			this.centerImage.src=dojo.uri.dojoUri(prefix + "c.gif");
		},
	
		/*** functions on right part of button ***/
		rightOver: function(/*Event*/ e){
			// summary:
			//	callback when mouse-over right part of button;
			//	onMouseOver() is the callback for the left side of the button.
			if( this.disabled ){ return; }
			dojo.html.prependClass(this.rightPart, "dojoButtonHover");
			this._setImageR(this.activeImg);
		},
	
		rightDown: function(/*Event*/ e){
			// summary:
			//	callback when mouse-down right part of button;
			//	onMouseDown() is the callback for the left side of the button.
			if( this.disabled ){ return; }
			dojo.html.prependClass(this.rightPart, "dojoButtonDepressed");
			dojo.html.removeClass(this.rightPart, "dojoButtonHover");
			this._setImageR(this.pressedImg);
		},

		rightUp: function(/*Event*/ e){
			// summary:
			//	callback when mouse-up right part of button;
			//	onMouseUp() is the callback for the left side of the button.
			if( this.disabled ){ return; }
			dojo.html.prependClass(this.rightPart, "dojoButtonHover");
			dojo.html.removeClass(this.rightPart, "dojoButtonDepressed");
			this._setImageR(this.activeImg);
		},
	
		rightOut: function(/*Event*/ e){
			// summary:
			//	callback when moving the mouse off of the right part of button;
			//	onMouseOut() is the callback for the left side of the button.
			if( this.disabled ){ return; }
			dojo.html.removeClass(this.rightPart, "dojoButtonHover");
			this._setImageR(this.inactiveImg);
		},

		rightClick: function(/*Event*/ e){
			// summary:
			//	callback when clicking the right part of button;
			//	onClick() is the callback for the left side of the button.
			if( this.disabled ){ return; }
			// focus may fail when tabIndex is not supported on div's
			// by the browser, or when the node is disabled
			try { this.domNode.focus(); } catch(e2) {};
			this._toggleMenu(this.menuId);
		},
	
		_setImageR: function(prefix){
			this.arrowBackgroundImage.src=dojo.uri.dojoUri(prefix + "c.gif");
			this.rightImage.src=dojo.uri.dojoUri(prefix + "r.gif");
		},

		/*** keyboard functions ***/
		
		onKey: function(/*Event*/ e){
			if (!e.key) { return; }
			var menu = dojo.widget.getWidgetById(this.menuId);
			if(e.key== e.KEY_ENTER || e.key == " "){
				this.onMouseDown(e);
				this.buttonClick(e);
				dojo.lang.setTimeout(this, "onMouseUp", 75, e);
				dojo.event.browser.stopEvent(e);
			} else if (e.key == e.KEY_DOWN_ARROW && e.altKey){
				this.rightDown(e);
				this.rightClick(e);
				dojo.lang.setTimeout(this, "rightUp", 75, e);
				dojo.event.browser.stopEvent(e);
			} else if(menu && menu.isShowingNow && e.key == e.KEY_DOWN_ARROW){
				// disconnect onBlur when focus moves into menu
				dojo.event.disconnect(this.domNode, "onblur", this, "onBlur");
				// allow event to propagate to menu
			}
		}
	});

__CPAN_FILE__ src/widget/TreeLoadingControllerV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeLoadingControllerV3");

dojo.require("dojo.widget.TreeBasicControllerV3");
dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");
dojo.require("dojo.Deferred");
dojo.require("dojo.DeferredList");

dojo.declare(
	"dojo.Error",
	Error,
	function(message, extra) {
		this.message = message;
		this.extra = extra;
		this.stack = (new Error()).stack;	
	}
);

dojo.declare(
	"dojo.CommunicationError",
	dojo.Error,
	function() {
		this.name="CommunicationError";
	}
);

dojo.declare(
	"dojo.LockedError",
	dojo.Error,
	function() {
		this.name="LockedError";
	}
);

dojo.declare(
	"dojo.FormatError",
	dojo.Error,
	function() {
		this.name="FormatError";
	}
);

dojo.declare(
	"dojo.RpcError",
	dojo.Error,
	function() {
		this.name="RpcError";
	}
);

dojo.widget.defineWidget(
	"dojo.widget.TreeLoadingControllerV3",
	dojo.widget.TreeBasicControllerV3,
{	
	RpcUrl: "",

	RpcActionParam: "action", // used for GET for RpcUrl

	preventCache: true,

	checkValidRpcResponse: function(type, obj) {
		if (type != "load") {
			var extra = {}				
			for(var i=1; i<arguments.length;i++) {
				dojo.lang.mixin(extra, arguments[i]);					
			}
			return new dojo.CommunicationError(obj, extra);				
		}
		
		if (typeof obj != 'object') {
			return new dojo.FormatError("Wrong server answer format "+(obj && obj.toSource ? obj.toSource() : obj)+" type "+(typeof obj), obj);
		}
		
		//dojo.debugShallow(obj);
			
		if (!dojo.lang.isUndefined(obj.error)) {
			return new dojo.RpcError(obj.error, obj);
		}
		
		return false;
	},
		

	getDeferredBindHandler: function(/* dojo.rpc.Deferred */ deferred){
		// summary
		// create callback that calls the Deferred's callback method		
		
		return dojo.lang.hitch(this, 
			function(type, obj){				
				//dojo.debug("getDeferredBindHandler "+obj.toSource());
								
				var error = this.checkValidRpcResponse.apply(this, arguments);
				
				if (error) {
					deferred.errback(error);
					return;
				}
	
				deferred.callback(obj);								
			}
		);
		
	},

	getRpcUrl: function(action) {

		// RpcUrl=local meant SOLELY for DEMO and LOCAL TESTS
		if (this.RpcUrl == "local") {
			var dir = document.location.href.substr(0, document.location.href.lastIndexOf('/'));
			var localUrl = dir+"/local/"+action;
			//dojo.debug(localUrl);
			return localUrl;	
		}

		if (!this.RpcUrl) {
			dojo.raise("Empty RpcUrl: can't load");
		}
		
		var url = this.RpcUrl;
		
		if (url.indexOf("/") != 0) { // not absolute
			var protocol = document.location.href.replace(/:\/\/.*/,'');
			var prefix = document.location.href.substring(protocol.length+3);
			
			if (prefix.lastIndexOf("/") != prefix.length-1) {
				prefix = prefix.replace(/\/[^\/]+$/,'/'); // strip file name
			}
			if (prefix.lastIndexOf("/") != prefix.length-1) {
				prefix = prefix+'/'; // add / if not exists it all
			}
			//dojo.debug(url);
			url = protocol + '://' + prefix + url;
		}
			

		return url + (url.indexOf("?")>-1 ? "&" : "?") + this.RpcActionParam+"="+action;
	},


	/**
	 * Add all loaded nodes from array obj as node children and expand it
	*/
	loadProcessResponse: function(node, result) {
		//dojo.debug("Process response "+node);
				
		if (!dojo.lang.isArray(result)) {
			throw new dojo.FormatError('loadProcessResponse: Not array loaded: '+result);
		}

		node.setChildren(result);
		
	},

	/**
	 * kw = { url, sync, params }
	 */
	runRpc: function(kw) {
		var _this = this;
		
		var deferred = new dojo.Deferred();
		
		dojo.io.bind({
			url: kw.url,			
			handle: this.getDeferredBindHandler(deferred),
			mimetype: "text/javascript",
			preventCache: this.preventCache,
			sync: kw.sync,
			content: { data: dojo.json.serialize(kw.params) }
		});
		
		return deferred;

	},



	/**
	 * Load children of the node from server
	 * Synchroneous loading doesn't break control flow
	 * I need sync mode for DnD
	*/
	loadRemote: function(node, sync){
		var _this = this;

		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		};

		
		var deferred = this.runRpc({
			url: this.getRpcUrl('getChildren'),
			sync: sync,
			params: params
		});
		
		deferred.addCallback(function(res) { return _this.loadProcessResponse(node,res) });
		
				
		
		return deferred;

	},

	batchExpandTimeout: 0,

	recurseToLevel: function(widget, level, callFunc, callObj, skipFirst, sync) {
		if (level == 0) return;


		
		if (!skipFirst) {
			var deferred = callFunc.call(callObj, widget, sync);
		} else {
			var deferred = dojo.Deferred.prototype.makeCalled();
		}
		
		//dojo.debug("expand deferred saved "+node+" sync "+sync);
		
		
		var _this = this;
		
		var recurseOnExpand = function() {
			var children = widget.children;
			var deferreds = [];		
			for(var i=0; i<children.length; i++) {
				//dojo.debug("push recursive call for "+node.children[i]+" level "+level);
				deferreds.push(_this.recurseToLevel(children[i], level-1, callFunc, callObj, sync));
			}
			return new dojo.DeferredList(deferreds);
		}
		
		deferred.addCallback(recurseOnExpand);
		
		return deferred;
	},
	
	
	expandToLevel: function(nodeOrTree, level, sync) {
		return this.recurseToLevel(nodeOrTree, nodeOrTree.isTree ? level+1 : level, this.expand, this, nodeOrTree.isTree, sync);
	},
	
	loadToLevel: function(nodeOrTree, level, sync) {
		return this.recurseToLevel(nodeOrTree, nodeOrTree.isTree ? level+1 : level, this.loadIfNeeded, this, nodeOrTree.isTree, sync);
	},
	
	
	loadAll: function(nodeOrTree, sync) {
		return this.loadToLevel(nodeOrTree, Number.POSITIVE_INFINITY, sync);
	},
		
	
	
	expand: function(node, sync) {		
		// widget which children are data objects, is UNCHECKED, but has children and shouldn't be loaded
		// so I put children check here too
		
		var _this = this;
		
		var deferred = this.startProcessing(node);
		
		deferred.addCallback(function() {
			return _this.loadIfNeeded(node, sync);
		});
				
		deferred.addCallback(function(res) {
			//dojo.debug("Activated callback dojo.widget.TreeBasicControllerV3.prototype.expand(node); "+res);
			dojo.widget.TreeBasicControllerV3.prototype.expand(node);
			return res;
		});
		
		deferred.addBoth(function(res) {
			_this.finishProcessing(node);
			return res;
		});
		
		
		
		return deferred;
	},

	
	loadIfNeeded: function(node, sync) {
		var deferred
		if (node.state == node.loadStates.UNCHECKED && node.isFolder && !node.children.length) {
			// populate deferred with other things to pre-do
			deferred = this.loadRemote(node, sync);			
		} else {
			/* "fake action" here */
			deferred = new dojo.Deferred();
			deferred.callback();
		}
		
		return deferred;
	},
	
	/**
	 * 1) if specified, run check, return false if failed
	 * 2) if specified, run prepare
	 * 3) run make if prepare if no errors
	 * 4) run finalize no matter what happened, pass through make result
	 * 5) if specified, run expose if no errors
	 */
	runStages: function(check, prepare, make, finalize, expose, args) {
		var _this = this;
		
		if (check && !check.apply(this, args)) {
			return false;
		}
		
		var deferred = dojo.Deferred.prototype.makeCalled();
		
		
		if (prepare) {
			deferred.addCallback(function() {
				return prepare.apply(_this, args);
			});
		}
		
		
		//deferred.addCallback(function(res) { dojo.debug("Prepare fired "+res); return res});
		
		if (make) {
			deferred.addCallback(function() {			
			var res = make.apply(_this, args);
			//res.addBoth(function(r) {dojo.debugShallow(r); return r;});
			return res;
			});
		}
		
		//deferred.addCallback(function(res) { dojo.debug("Main fired "+res); return res});
		
		if (finalize) {
			deferred.addBoth(function(res) {
				finalize.apply(_this, args);
				return res;
			});
		}
			
				
		// exposer does not affect result
		if (expose) {
			deferred.addCallback(function(res) {
				expose.apply(_this, args);
				return res;
			});
		}
		
		return deferred;
	},
		
	startProcessing: function(nodesArray) {
		var deferred = new dojo.Deferred();
		
		
		var nodes = dojo.lang.isArray(nodesArray) ? nodesArray : arguments;
		
		/*
		for(var i=0;i<nodes.length;i++) {
			dojo.debug(nodes[i]);
		}*/
		
		for(var i=0;i<nodes.length;i++) {
			if (nodes[i].isLocked()) {
				deferred.errback(new dojo.LockedError("item locked "+nodes[i], nodes[i]));
				//dojo.debug("startProcessing errback "+arguments[i]);
				return deferred;
			}
			if (nodes[i].isTreeNode) {
				//dojo.debug("mark "+nodes[i]);
				nodes[i].markProcessing();
			}
			nodes[i].lock();
		}
				
		//dojo.debug("startProcessing callback");
				
		deferred.callback();
		
		return deferred;
	},
	
	finishProcessing: function(nodesArray) {
		
		var nodes = dojo.lang.isArray(nodesArray) ? nodesArray : arguments;
		
		for(var i=0;i<nodes.length;i++) {
			if (!nodes[i].hasLock()) {
				// is not processed. probably we locked it and then met bad node in startProcessing
				continue; 
			}
			//dojo.debug("has lock");	
			nodes[i].unlock();
			if (nodes[i].isTreeNode) {
				//dojo.debug("unmark "+nodes[i]);
				nodes[i].unmarkProcessing();
			}
		}
	},
	
	// ----------------- refresh -----------------
	
	refreshChildren: function(nodeOrTree, sync) {		
		return this.runStages(null, this.prepareRefreshChildren, this.doRefreshChildren, this.finalizeRefreshChildren, this.exposeRefreshChildren, arguments);
	},


	prepareRefreshChildren: function(nodeOrTree, sync) {
		var deferred = this.startProcessing(nodeOrTree);
		nodeOrTree.destroyChildren();
						
		nodeOrTree.state = nodeOrTree.loadStates.UNCHECKED;
		
		return deferred;
	},
	
	doRefreshChildren: function(nodeOrTree, sync) {
		return this.loadRemote(nodeOrTree, sync);
	},
	
	finalizeRefreshChildren: function(nodeOrTree, sync) {
		this.finishProcessing(nodeOrTree);
	},
	
	exposeRefreshChildren: function(nodeOrTree, sync) {
		nodeOrTree.expand();
	},

	// ----------------- move -----------------

	move: function(child, newParent, index/*,...*/) {
		return this.runStages(this.canMove, this.prepareMove, this.doMove, this.finalizeMove, this.exposeMove, arguments);			
	},

	doMove: function(child, newParent, index) {
		//dojo.debug("MOVE "+child);
		child.tree.move(child, newParent, index);

		return true;
	},
	
	
	prepareMove: function(child, newParent, index, sync) {
		var deferred = this.startProcessing(newParent);
		deferred.addCallback(dojo.lang.hitch(this, function() {
			return this.loadIfNeeded(newParent, sync);
		}));
		return deferred;
	},
	
	finalizeMove: function(child, newParent) {
		this.finishProcessing(newParent);
	},

	// -------------------- createChild ------------

	prepareCreateChild: function(parent, index, data, sync) {
		var deferred = this.startProcessing(parent);
		
		deferred.addCallback(dojo.lang.hitch(this, function() {
			return this.loadIfNeeded(parent, sync);
		}));
		return deferred;
	},
	
	finalizeCreateChild: function(parent) {
		this.finishProcessing(parent);
	},

	// ---------------- clone ---------------
	
	prepareClone: function(child, newParent, index, deep, sync) {
		var deferred = this.startProcessing(child, newParent);
		deferred.addCallback(dojo.lang.hitch(this, function() {
			return this.loadIfNeeded(newParent, sync);
		}));		
		return deferred;	
	},	
	
	finalizeClone: function(child, newParent) {
		this.finishProcessing(child, newParent);
	}

});

__CPAN_FILE__ src/widget/Tooltip.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Tooltip");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.widget.PopupContainer");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.html.style");
dojo.require("dojo.html.util");
dojo.require("dojo.html.iframe");

dojo.widget.defineWidget(
	"dojo.widget.Tooltip",
	[dojo.widget.ContentPane, dojo.widget.PopupContainerBase],
	{
		isContainer: true,

		// Constructor arguments
		caption: "",
		showDelay: 500,
		hideDelay: 100,
		connectId: "",

		templateCssPath: dojo.uri.dojoUri("src/widget/templates/TooltipTemplate.css"),

		fillInTemplate: function(args, frag){
			if(this.caption != ""){
				this.domNode.appendChild(document.createTextNode(this.caption));
			}
			this._connectNode = dojo.byId(this.connectId);
			dojo.widget.Tooltip.superclass.fillInTemplate.call(this, args, frag);

			this.addOnLoad(this, "_loadedContent");
			dojo.html.addClass(this.domNode, "dojoTooltip");

			//copy style from input node to output node
			var source = this.getFragNodeRef(frag);
			dojo.html.copyStyle(this.domNode, source);

			//apply the necessary css rules to the node so that it can popup
			this.applyPopupBasicStyle();
		},

		postCreate: function(args, frag){
			dojo.event.connect(this._connectNode, "onmouseover", this, "onMouseOver");
			dojo.widget.Tooltip.superclass.postCreate.call(this, args, frag);
		},

		onMouseOver: function(e){
			this._mouse = {x: e.pageX, y: e.pageY};

			// Start tracking mouse movements, so we know when to cancel timers or erase the tooltip
			if(!this._tracking){
				dojo.event.connect(document.documentElement, "onmousemove", this, "onMouseMove");
				this.tracking=true;
			}

			this._onHover(e);			
		},

		onMouseMove: function(e) {
			this._mouse = {x: e.pageX, y: e.pageY};

			if(dojo.html.overElement(this._connectNode, e) || dojo.html.overElement(this.domNode, e)){
				this._onHover(e);
			} else {
				// mouse has been moved off the element/tooltip
				// note: can't use onMouseOut to detect this because the "explode" effect causes
				// spurious onMouseOut events (due to interference from outline), w/out corresponding onMouseOver
				this._onUnHover(e);
			}
		},

		_onHover: function(e) {
			if(this._hover){ return; }
			this._hover=true;

			// If the tooltip has been scheduled to be erased, cancel that timer
			// since we are hovering over element/tooltip again
			if(this._hideTimer) {
				clearTimeout(this._hideTimer);
				delete this._hideTimer;
			}
			
			// If tooltip not showing yet then set a timer to show it shortly
			if(!this.isShowingNow && !this._showTimer){
				this._showTimer = setTimeout(dojo.lang.hitch(this, "open"), this.showDelay);
			}
		},

		_onUnHover: function(e){
			if(!this._hover){ return; }
			this._hover=false;

			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			if(this.isShowingNow && !this._hideTimer){
				this._hideTimer = setTimeout(dojo.lang.hitch(this, "close"), this.hideDelay);
			}
			
			// If we aren't showing the tooltip, then we can stop tracking the mouse now;
			// otherwise must track the mouse until tooltip disappears
			if(!this.isShowingNow){
				dojo.event.disconnect(document.documentElement, "onmousemove", this, "onMouseMove");
				this._tracking=false;
			}
		},

		open: function() {
			if (this.isShowingNow) { return; }

			dojo.widget.PopupContainerBase.prototype.open.call(this, this._mouse.x, this._mouse.y, null, [this._mouse.x, this._mouse.y], "TL,TR,BL,BR", [10,15]);
		},

		close: function() {
			if (this.isShowingNow) {
				if ( this._showTimer ) {
					clearTimeout(this._showTimer);
					delete this._showTimer;
				}
				if ( this._hideTimer ) {
					clearTimeout(this._hideTimer);
					delete this._hideTimer;
				}
				dojo.event.disconnect(document.documentElement, "onmousemove", this, "onMouseMove");
				this._tracking=false;
				dojo.widget.PopupContainerBase.prototype.close.call(this);
			}
		},

		_position: function(){
			this.move(this._mouse.x, this._mouse.y, [10,15], "TL,TR,BL,BR");
		},

		_loadedContent: function(){
			if(this.isShowingNow){
				// the tooltip has changed size due to downloaded contents, so reposition it
				this._position();
			}
		},

		checkSize: function(){
			// checkSize() is called when the user has resized the browser window,
			// but that doesn't affect this widget (or this widget's children)
			// so it can be safely ignored
		},

		uninitialize: function(){
			this.close();
			dojo.event.disconnect(this._connectNode, "onmouseover", this, "onMouseOver");
		}

	}
);

__CPAN_FILE__ src/widget/TreeLinkExtension.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeLinkExtension");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeExtension");

dojo.widget.defineWidget(
	"dojo.widget.TreeLinkExtension",
	dojo.widget.TreeExtension,
	function() {
		this.params = {};
	},
{
	/**
	 * can only listen, no unlisten
	 */

	listenTreeEvents: ["afterChangeTree"],	

	listenTree: function(tree) {
		
		dojo.widget.TreeCommon.prototype.listenTree.call(this,tree);
		
		var labelNode = tree.labelNodeTemplate;
		var newLabel = this.makeALabel();
		dojo.html.setClass(newLabel, dojo.html.getClass(labelNode));
		labelNode.parentNode.replaceChild(newLabel, labelNode);		
	},
	
		
	
	makeALabel: function() {		
		var newLabel = document.createElement("a");
		
		for(var key in this.params) {
			if (key in {}) continue;
			newLabel.setAttribute(key, this.params[key]);
		}
		
		return newLabel;
	},
		
	
	onAfterChangeTree: function(message) {
		var _this = this;
		
		
		// only for new nodes
		if (!message.oldTree) {
			this.listenNode(message.node);
		}
		
	},
	
	listenNode: function(node) {
		for(var key in node.object) {
			if (key in {}) continue;
			node.labelNode.setAttribute(key, node.object[key]);
		}
	}


});

__CPAN_FILE__ src/widget/TreeContextMenuV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TreeContextMenuV3");

dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Menu2");
dojo.require("dojo.widget.TreeCommon");

dojo.widget.defineWidget(
	"dojo.widget.TreeContextMenuV3",
	[dojo.widget.PopupMenu2, dojo.widget.TreeCommon],
	function() {
		this.listenedTrees = {};
		
	},
{

	listenTreeEvents: ["afterTreeCreate","beforeTreeDestroy"],
	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget},
	
	onAfterTreeCreate: function(message) {
		var tree = message.source;
		this.bindDomNode(tree.domNode);
	},
	
	onBeforeTreeDestroy: function(message) {
		this.unBindDomNode(message.source.domNode);
	},
	
	
	getTreeNode: function() {
		
		var source = this.getTopOpenEvent().target;
		var treeNode = this.domElement2TreeNode(source);
		return treeNode;
	
	},
		
	open: function() {
		var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);

		for(var i=0; i< this.children.length; i++) {
			/* notify children */
			if (this.children[i].menuOpen) {
				this.children[i].menuOpen(this.getTreeNode());
			}
		}
		return result;
	},
	
	close: function(){
		
		for(var i=0; i< this.children.length; i++) {
			/* notify menu entries */
			if (this.children[i].menuClose) {
				this.children[i].menuClose(this.getTreeNode());
			}
		}
		

		var result = dojo.widget.PopupMenu2.prototype.close.apply(this, arguments);
		
		return result
	}
	
});


dojo.widget.defineWidget(
	"dojo.widget.TreeMenuItemV3",
	[dojo.widget.MenuItem2, dojo.widget.TreeCommon],
	function() {
		this.treeActions = [];
	},
{
	// treeActions menu item performs following actions (to be checked for permissions)
	treeActions: "",

	initialize: function(args, frag) {
		for(var i=0; i<this.treeActions.length; i++) {
			this.treeActions[i] = this.treeActions[i].toUpperCase();
		}
	},

		
	getTreeNode: function() {
		var menu = this;

		// FIXME: change to dojo.widget[this.widgetType]
		while (! (menu instanceof dojo.widget.TreeContextMenuV3) ) {
				menu = menu.parent;
		}

		var treeNode = menu.getTreeNode()

		return treeNode;
	},


	menuOpen: function(treeNode) {

		treeNode.viewEmphase()
		this.setDisabled(false); // enable by default

		var _this = this;
		dojo.lang.forEach(_this.treeActions,
			function(action) {
				_this.setDisabled( treeNode.actionIsDisabledNow(action) );
			}
		);

	},
	
	menuClose: function(treeNode) {

		treeNode.viewUnemphase()
	},

	toString: function() {
		return "["+this.widgetType+" node "+this.getTreeNode()+"]";
	}
});

__CPAN_FILE__ src/widget/TreeCommon.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeCommon");
dojo.require("dojo.widget.*"); // for dojo.widget.manager

dojo.declare(
	"dojo.widget.TreeCommon",
	null,
{
	listenTreeEvents: [],
	listenedTrees: {},
	
	/**
	 * evaluates to false => skip unlistening nodes
	 * provided => use it
	 */	
	listenNodeFilter: null,
	
	listenTree: function(tree) {
		
		//dojo.debug("listenTree in "+this+" tree "+tree);
		
		var _this = this;
		
		if (this.listenedTrees[tree.widgetId]) {
			return; // already listening
		}
		
		dojo.lang.forEach(this.listenTreeEvents, function(event) {
			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
			//dojo.debug("subscribe: event "+tree.eventNames[event]+" widget "+_this+" handler "+eventHandler);
			dojo.event.topic.subscribe(tree.eventNames[event], _this, eventHandler);
		});
		
		
		var filter;
		
		if (this.listenNodeFilter) {			
			this.processDescendants(tree, this.listenNodeFilter, this.listenNode, true);
		}
		
		/**
		 * remember that I listen to this tree. No unbinding/binding/deselection
		 * needed when transfer between listened trees
		 */
		this.listenedTrees[tree.widgetId] = true;
		
	},			
	
	// interface functions
	listenNode: function() {},	
	unlistenNode: function() {},
			
	unlistenTree: function(tree, nodeFilter) {
		
		var _this = this;
	
		if (!this.listenedTrees[tree.widgetId]) {
			return; 
		}
		
		dojo.lang.forEach(this.listenTreeEvents, function(event) {
			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
			dojo.event.topic.unsubscribe(tree.eventNames[event], _this, eventHandler);
		});
		
		
		if (this.listenNodeFilter) {
			this.processDescendants(tree, this.listenNodeFilter, this.unlistenNode, true);
		}
		
		delete this.listenedTrees[tree.widgetId];
		
	},
	
	
	/**
	 * check condition for node.domNode -> .. -> any node chain
	 */
	checkPathCondition: function(domElement, condition) {
		
		while (domElement && !domElement.widgetId) {
			if (condition.call(null, domElement)) {
				return true;
			}
			
			domElement = domElement.parentNode;
		}
		
		return false;
	},
		
	
	/**
	 * get node widget id by its descendant dom node
	 */
	domElement2TreeNode: function(domElement) {
		
		while (domElement && !domElement.widgetId) {
			domElement = domElement.parentNode;
		}
		
		if (!domElement) {
			return null;
		}
		
		var widget = dojo.widget.byId(domElement.widgetId);
		
		if (!widget.isTreeNode) {
			return null;
		}
		
		return widget;
	},
	
	/**
	 * it is here, not in Widget, because mostly tree needs it
	 */
	processDescendants: function(elem, filter, func, skipFirst) {
		
		var _this = this;
		
		if (!skipFirst) {
			if (!filter.call(_this,elem)) {
				return;
			}
			func.call(_this,elem);	        
		}
		
		
		var stack = [elem];
		while (elem = stack.pop()) {
			dojo.lang.forEach(elem.children, function(elem) {
				if (filter.call(_this, elem)) {		
					func.call(_this, elem);
					stack.push(elem);
				}
			});
		}
    }
});

__CPAN_FILE__ src/widget/Toaster.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Toaster");

dojo.require("dojo.widget.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.html.iframe");

// This is mostly taken from Jesse Kuhnert's MessageNotifier.
// Modified by Bryan Forbes to support topics and a variable delay.

dojo.widget.defineWidget(
	"dojo.widget.Toaster",
	dojo.widget.HtmlWidget,
	{
		templateString: '<div dojoAttachPoint="clipNode"><div dojoAttachPoint="containerNode" dojoAttachEvent="onClick:onSelect"><div dojoAttachPoint="contentNode"></div></div></div>',
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/Toaster.css"),
		
		clipNode: null,

		messageTopic: "",
		contentNode: null,

		_scrollConnected: false,
		
		// possible message types
		messageTypes: {
			MESSAGE: "MESSAGE",
			WARNING: "WARNING",
			ERROR: "ERROR",
			FATAL: "FATAL"
		},
		defaultType: "MESSAGE",

		// css classes
		clipCssClass: "dojoToasterClip",
		containerCssClass: "dojoToasterContainer",
		contentCssClass: "dojoToasterContent",
		messageCssClass: "dojoToasterMessage",
		warningCssClass: "dojoToasterWarning",
		errorCssClass: "dojoToasterError",
		fatalCssClass: "dojoToasterFatal",
		
		positionDirection: "br-up",
		positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"],
		showDelay: 2000,

		slideAnim: null,
		fadeAnim: null,

		bgIframe: null,

		postCreate: function(){
			this.hide();
			dojo.html.setClass(this.clipNode, this.clipCssClass);
			dojo.html.addClass(this.containerNode, this.containerCssClass);
			dojo.html.setClass(this.contentNode, this.contentCssClass);
			if(this.messageTopic){
				dojo.event.topic.subscribe(this.messageTopic, this, "handleMessage");
			}
			if(!this.positionDirection || !dojo.lang.inArray(this.positionDirectionTypes, this.positionDirection)){
				this.positionDirection = this.positionDirectionTypes.BRU;
			}
		},

		handleMessage: function(msg){
			if(dojo.lang.isString(msg)){
				this.setContent(msg);
			}else{
				this.setContent(msg["message"], msg["type"], msg["delay"]);
			}
		},

		setContent: function(msg, messageType, delay){
			var delay = delay||this.showDelay;
			// sync animations so there are no ghosted fades and such
			if(this.slideAnim && this.slideAnim.status() == "playing"){
				dojo.lang.setTimeout(50, dojo.lang.hitch(this, function(){
					this.setContent(msg, messageType);
				}));
				return;
			}else if(this.slideAnim){
				this.slideAnim.stop();
				if(this.fadeAnim) this.fadeAnim.stop();
			}
			if(!msg){
				dojo.debug(this.widgetId + ".setContent() incoming content was null, ignoring.");
				return;
			}
			if(!this.positionDirection || !dojo.lang.inArray(this.positionDirectionTypes, this.positionDirection)){
				dojo.raise(this.widgetId + ".positionDirection is an invalid value: " + this.positionDirection);
			}

			// determine type of content and apply appropriately
			dojo.html.removeClass(this.containerNode, this.messageCssClass);
			dojo.html.removeClass(this.containerNode, this.warningCssClass);
			dojo.html.removeClass(this.containerNode, this.errorCssClass);
			dojo.html.removeClass(this.containerNode, this.fatalCssClass);

			dojo.html.clearOpacity(this.containerNode);
			
			if(msg instanceof String || typeof msg == "string"){
				this.contentNode.innerHTML = msg;
			}else if(dojo.html.isNode(msg)){
				this.contentNode.innerHTML = dojo.html.getContentAsString(msg);
			}else{
				dojo.raise("Toaster.setContent(): msg is of unknown type:" + msg);
			}

			switch(messageType){
				case this.messageTypes.WARNING:
					dojo.html.addClass(this.containerNode, this.warningCssClass);
					break;
				case this.messageTypes.ERROR:
					dojo.html.addClass(this.containerNode, this.errorCssClass);
					break
				case this.messageTypes.FATAL:
					dojo.html.addClass(this.containerNode, this.fatalCssClass);
					break;
				case this.messageTypes.MESSAGE:
				default:
					dojo.html.addClass(this.containerNode, this.messageCssClass);
					break;
			}

			// now do funky animation of widget appearing from
			// bottom right of page and up
			this.show();

			var nodeSize = dojo.html.getMarginBox(this.containerNode);

			// sets up initial position of container node and slide-out direction
			if(this.positionDirection.indexOf("-up") >= 0){
				this.containerNode.style.left=0+"px";
				this.containerNode.style.top=nodeSize.height + 10 + "px";
			}else if(this.positionDirection.indexOf("-left") >= 0){
				this.containerNode.style.left=nodeSize.width + 10 +"px";
				this.containerNode.style.top=0+"px";
			}else if(this.positionDirection.indexOf("-right") >= 0){
				this.containerNode.style.left = 0 - nodeSize.width - 10 + "px";
				this.containerNode.style.top = 0+"px";
			}else if(this.positionDirection.indexOf("-down") >= 0){
				this.containerNode.style.left = 0+"px";
				this.containerNode.style.top = 0 - nodeSize.height - 10 + "px";
			}else{
				dojo.raise(this.widgetId + ".positionDirection is an invalid value: " + this.positionDirection);
			}

			this.slideAnim = dojo.lfx.html.slideTo(
				this.containerNode,
				{ top: 0, left: 0 },
				450,
				null,
				dojo.lang.hitch(this, function(nodes, anim){
					dojo.lang.setTimeout(dojo.lang.hitch(this, function(evt){
						// we must hide the iframe in order to fade
						// TODO: figure out how to fade with a BackgroundIframe
						if(this.bgIframe){
							this.bgIframe.hide();
						}
						// can't do a fadeHide because we're fading the
						// inner node rather than the clipping node
						this.fadeAnim = dojo.lfx.html.fadeOut(
							this.containerNode,
							1000,
							null,
							dojo.lang.hitch(this, function(evt){
								this.hide();
							})).play();
					}), delay);
				})).play();
		},

		placeClip: function(){
			var scroll = dojo.html.getScroll();
			var view = dojo.html.getViewport();

			var nodeSize = dojo.html.getMarginBox(this.containerNode);

			// sets up the size of the clipping node
			this.clipNode.style.height = nodeSize.height+"px";
			this.clipNode.style.width = nodeSize.width+"px";

			// sets up the position of the clipping node
			if(this.positionDirection.match(/^t/)){
				this.clipNode.style.top = scroll.top+"px";
			}else if(this.positionDirection.match(/^b/)){
				this.clipNode.style.top = (view.height - nodeSize.height - 2 + scroll.top)+"px";
			}
			if(this.positionDirection.match(/^[tb]r-/)){
				this.clipNode.style.left = (view.width - nodeSize.width - 1 - scroll.left)+"px";
			}else if(this.positionDirection.match(/^[tb]l-/)){
				this.clipNode.style.left = 0 + "px";
			}

			this.clipNode.style.clip = "rect(0px, " + nodeSize.width + "px, " + nodeSize.height + "px, 0px)";

			if(dojo.render.html.ie){
				if(!this.bgIframe){
					this.bgIframe = new dojo.html.BackgroundIframe(this.containerNode);
					this.bgIframe.setZIndex(this.containerNode);
				}
				this.bgIframe.onResized();
				this.bgIframe.show();
			}
		},

		onSelect: function(e) { },

		onScroll: function(){
			this.placeClip();
		},

		show: function(){
			dojo.widget.Toaster.superclass.show.call(this);

			this.placeClip();

			if(!this._scrollConnected){
				this._scrollConnected = true;
				dojo.event.connect(window, "onscroll", this, "onScroll");
			}
		},

		hide: function(){
			dojo.widget.Toaster.superclass.hide.call(this);

			if(this._scrollConnected){
				this._scrollConnected = false;
				dojo.event.disconnect(window, "onscroll", this, "onScroll");
			}

			dojo.html.setOpacity(this.containerNode, 1.0);
		}
	},
	"html"
);

__CPAN_FILE__ src/widget/ContentPane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ContentPane");

dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.string");
dojo.require("dojo.string.extras");
dojo.require("dojo.html.style");


// summary:
//		dojo.widget.ContentPane, a widget that can be used as a standalone widget 
//		or as a baseclass for other widgets
//		Handles replacement of document fragment using either external uri or javascript/java 
//		generated markup or DomNode content, instanciating widgets within content and runs scripts.
//		Dont confuse it with an iframe, it only needs document fragments.
//		It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
//		But note that those classes can contain any widget as a child.
dojo.widget.defineWidget(
	"dojo.widget.ContentPane",
	dojo.widget.HtmlWidget,
	function(){
		// per widgetImpl variables
		this._styleNodes =  [];
		this._onLoadStack = [];
		this._onUnloadStack = [];
		this._callOnUnload = false;
		this._ioBindObj;
		// Function:
		//		reference holder to the inline scripts container, if scriptSeparation is true
		//	Note:
		//		dont change this value externally
		this.scriptScope; // undefined for now

		// loading option
		// Object:
		//		Send in extra args to the dojo.io.bind call
		//	example:
		//		bindArgs="preventCache:false;" overrides cacheContent
		this.bindArgs = {};

	
	}, {
		isContainer: true,

		// loading options
		// Boolean:
		//		adjust relative paths in markup to fit this page
		adjustPaths: true,

		// String:
		//		The href of the content that displays now
		//		Set this at construction if you want to load externally,
		//		changing href after creation doesnt have any effect, see setUrl
		href: "",

		// Boolean: Extract visible content from inside of <body> .... </body>
		extractContent: true,

		// Boolean: Construct all widgets that is in content
		parseContent:	true,

		// Boolean: Cache content retreived externally
		cacheContent:	true,

		// Boolean:
		//		Force load of data even if pane is hidden
		//	Note:
		//		In order to delay download you need to initially hide the node it constructs from
		preload: false,

		// Boolean:
		//		Refresh (re-download) content when pane goes from hidden to shown
		refreshOnShow: false,

		// String||Function:
		//		Generate pane content from a java function
		//		The name of the java proxy function
		handler: "",

		// Boolean:
		//		Run scripts within content, extractContent has NO effect on this
		//	Note:
		//		if true scripts in content will be evaled after content is innerHTML'ed
		executeScripts: false,

		// Boolean:
		//		Run scripts in a separate scope, unique for each ContentPane
		scriptSeparation: true,

		// String: Message that shows while downloading
		loadingMessage: "Loading...",

		// Boolean: Tells loading status
		isLoaded: false,

		postCreate: function(args, frag, parentComp){
			if (this.handler!==""){
				this.setHandler(this.handler);
			}
			if(this.isShowing() || this.preload){
				this.loadContents(); 
			}
		},
	
		show: function(){
			// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
			if(this.refreshOnShow){
				this.refresh();
			}else{
				this.loadContents();
			}
			dojo.widget.ContentPane.superclass.show.call(this);
		},
	
		refresh: function(){
			// summary:
			//		Force a refresh (re-download) of content, be sure to turn of cache
			this.isLoaded=false;
			this.loadContents();
		},
	
		loadContents: function() {
			// summary:
			//		Download if isLoaded is false, else ignore
			if ( this.isLoaded ){
				return;
			}
			if ( dojo.lang.isFunction(this.handler)) {
				this._runHandler();
			} else if ( this.href != "" ) {
				this._downloadExternalContent(this.href, this.cacheContent && !this.refreshOnShow);
			}
		},
		
		setUrl: function(/*String||dojo.uri.Uri*/ url) {
			// summary:
			//		Reset the (external defined) content of this pane and replace with new url
			//	Note:
			//		It delays the download until widget is shown if preload is false
			this.href = url;
			this.isLoaded = false;
			if ( this.preload || this.isShowing() ){
				this.loadContents();
			}
		},

		abort: function(){
			// summary
			//		Aborts a inflight download of content
			var bind = this._ioBindObj;
			if(!bind || !bind.abort){ return; }
			bind.abort();
			delete this._ioBindObj;
		},
	
		_downloadExternalContent: function(url, useCache) {
			this.abort();
			this._handleDefaults(this.loadingMessage, "onDownloadStart");
			var self = this;
			this._ioBindObj = dojo.io.bind(
				this._cacheSetting({
					url: url,
					mimetype: "text/html",
					handler: function(type, data, xhr){
						delete self._ioBindObj; // makes sure abort doesnt clear cache
						if(type=="load"){
							self.onDownloadEnd.call(self, url, data);
						}else{
							// XHR isnt a normal JS object, IE doesnt have prototype on XHR so we cant extend it or shallowCopy it
							var e = {
								responseText: xhr.responseText,
								status: xhr.status,
								statusText: xhr.statusText,
								responseHeaders: xhr.getAllResponseHeaders(),
								text: "Error loading '" + url + "' (" + xhr.status + " "+  xhr.statusText + ")"
							};
							self._handleDefaults.call(self, e, "onDownloadError");
							self.onLoad();
						}
					}
				}, useCache)
			);
		},
	
		_cacheSetting: function(bindObj, useCache){
			for(var x in this.bindArgs){
				if(dojo.lang.isUndefined(bindObj[x])){
					bindObj[x] = this.bindArgs[x];
				}
			}

			if(dojo.lang.isUndefined(bindObj.useCache)){ bindObj.useCache = useCache; }
			if(dojo.lang.isUndefined(bindObj.preventCache)){ bindObj.preventCache = !useCache; }
			if(dojo.lang.isUndefined(bindObj.mimetype)){ bindObj.mimetype = "text/html"; }
			return bindObj;
		},

		onLoad: function(e){
			// summary:
			//		Event hook, is called after everything is loaded and widgetified 
			this._runStack("_onLoadStack");
			this.isLoaded=true;
		},
	
		onUnLoad: function(e){
			// summary:
			//		Deprecated, use onUnload (lowercased load)
			dojo.deprecated(this.widgetType+".onUnLoad, use .onUnload (lowercased load)", 0.5);
		},

		onUnload: function(e){
			// summary:
			//		Event hook, is called before old content is cleared
			this._runStack("_onUnloadStack");
			delete this.scriptScope;
			// FIXME: remove for 0.5 along with onUnLoad
			if(this.onUnLoad !== dojo.widget.ContentPane.prototype.onUnLoad){
				this.onUnLoad.apply(this, arguments);
			}
		},
	
		_runStack: function(stName){
			var st = this[stName]; var err = "";
			var scope = this.scriptScope || window;
			for(var i = 0;i < st.length; i++){
				try{
					st[i].call(scope);
				}catch(e){ 
					err += "\n"+st[i]+" failed: "+e.description;
				}
			}
			this[stName] = [];
	
			if(err.length){
				var name = (stName== "_onLoadStack") ? "addOnLoad" : "addOnUnLoad";
				this._handleDefaults(name+" failure\n "+err, "onExecError", "debug");
			}
		},
	
		addOnLoad: function(/*Function||Object, optional*/ obj, /*Function*/ func){
			// summary
			//		Stores function refs and calls them one by one in the order they came in
			//		when load event occurs.
			//	obj:
			//		holder object
			//	func:
			//		function that will be called 
			this._pushOnStack(this._onLoadStack, obj, func);
		},
	
		addOnUnload: function(/*Function||Object, optional*/ obj, /*Function*/ func){
			// summary
			//		Stores function refs and calls them one by one in the order they came in
			//		when unload event occurs.
			//	obj:
			//		holder object
			//	func:
			//		function that will be called 
			this._pushOnStack(this._onUnloadStack, obj, func);
		},

		addOnUnLoad: function(){
			// summary:
			//		Deprecated use addOnUnload (lower cased load)
			dojo.deprecated(this.widgetType + ".addOnUnLoad, use addOnUnload instead. (lowercased Load)", 0.5);
			this.addOnUnload.apply(this, arguments);
		},
	
		_pushOnStack: function(stack, obj, func){
			if(typeof func == 'undefined') {
				stack.push(obj);
			}else{
				stack.push(function(){ obj[func](); });
			}
		},
	
		destroy: function(){
			// make sure we call onUnload
			this.onUnload();
			dojo.widget.ContentPane.superclass.destroy.call(this);
		},
 
		onExecError: function(/*Object*/e){
			// summary:
			//		called when content script eval error or Java error occurs, preventDefault-able
			//		default is to debug not alert as in 0.3.1
		},
	
		onContentError: function(/*Object*/e){
			// summary: 
			//		called on DOM faults, require fault etc in content, preventDefault-able
			//		default is to display errormessage inside pane
		},
	
		onDownloadError: function(/*Object*/e){
			// summary: 
			//		called when download error occurs, preventDefault-able
			//		default is to display errormessage inside pane
		},
	
		onDownloadStart: function(/*Object*/e){
			// summary:
			//		called before download starts, preventDefault-able
			//		default is to display loadingMessage inside pane
			//		by changing e.text in your event handler you can change loading message
		},
	
		// 
		onDownloadEnd: function(/*String*/ url, /*String*/ data){
			// summary:
			//		called when download is finished
			//
			//	url: url that downloaded data
			//	data: the markup that was downloaded
			data = this.splitAndFixPaths(data, url);
			this.setContent(data);
		},
	
		// useful if user wants to prevent default behaviour ie: _setContent("Error...")
		_handleDefaults: function(e, handler, messType){
			if(!handler){ handler = "onContentError"; }

			if(dojo.lang.isString(e)){ e = {text: e}; }

			if(!e.text){ e.text = e.toString(); }

			e.toString = function(){ return this.text; };

			if(typeof e.returnValue != "boolean"){
				e.returnValue = true; 
			}
			if(typeof e.preventDefault != "function"){
				e.preventDefault = function(){ this.returnValue = false; };
			}
			// call our handler
			this[handler](e);
			if(e.returnValue){
				switch(messType){
					case true: // fallthrough, old compat
					case "alert":
						alert(e.toString()); break;
					case "debug":
						dojo.debug(e.toString()); break;
					default:
					// makes sure scripts can clean up after themselves, before we setContent
					if(this._callOnUnload){ this.onUnload(); } 
					// makes sure we dont try to call onUnLoad again on this event,
					// ie onUnLoad before 'Loading...' but not before clearing 'Loading...'
					this._callOnUnload = false;

					// we might end up in a endless recursion here if domNode cant append content
					if(arguments.callee._loopStop){
						dojo.debug(e.toString());
					}else{
						arguments.callee._loopStop = true;
						this._setContent(e.toString());
					}
				}
			}
			arguments.callee._loopStop = false;
		},
	
		// pathfixes, require calls, css stuff and neccesary content clean
		splitAndFixPaths: function(/*String*/s, /*String||dojo.uri.Uri, optional*/url){
			// summary:
			// 		adjusts all relative paths in (hopefully) all cases, images, remote scripts, links etc.
			// 		splits up content in different pieces, scripts, title, style, link and whats left becomes .xml

			//	s:	The markup in string
			//	url: url that pulled in markup

			var titles = [], scripts = [],tmp = [];// init vars
			var match = [], requires = [], attr = [], styles = [];
			var str = '', path = '', fix = '', tagFix = '', tag = '', origPath = '';
	
			if(!url) { url = "./"; } // point to this page if not set

			if(s){ // make sure we dont run regexes on empty content

				/************** <title> ***********/
				// khtml is picky about dom faults, you can't attach a <style> or <title> node as child of body
				// must go into head, so we need to cut out those tags
				var regex = /<title[^>]*>([\s\S]*?)<\/title>/i;
				while(match = regex.exec(s)){
					titles.push(match[1]);
					s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
				};
		
				/************** adjust paths *****************/
				if(this.adjustPaths){
					// attributepaths one tag can have multiple paths example:
					// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
					// strip out the tag and run fix on that.
					// this guarantees that we won't run replace on another tag's attribute + it was easier do
					var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i;
					var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i;
					// these are the supported protocols, all other is considered relative
					var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/;
		
					while(tag = regexFindTag.exec(s)){
						str += s.substring(0, tag.index);
						s = s.substring((tag.index + tag[0].length), s.length);
						tag = tag[0];
			
						// loop through attributes
						tagFix = '';
						while(attr = regexFindAttr.exec(tag)){
							path = ""; origPath = attr[3];
							switch(attr[1].toLowerCase()){
								case "src":// falltrough
								case "href":
									if(regexProtocols.exec(origPath)){
										path = origPath;
									} else {
										path = (new dojo.uri.Uri(url, origPath).toString());
									}
									break;
								case "style":// style
									path = dojo.html.fixPathsInCssText(origPath, url);
									break;
								default:
									path = origPath;
							}
							fix = " " + attr[1] + "=" + attr[2] + path + attr[2];
							// slices up tag before next attribute check
							tagFix += tag.substring(0, attr.index) + fix;
							tag = tag.substring((attr.index + attr[0].length), tag.length);
						}
						str += tagFix + tag; //dojo.debug(tagFix + tag);
					}
					s = str+s;
				}

				/****************  cut out all <style> and <link rel="stylesheet" href=".."> **************/
				regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i;
				while(match = regex.exec(s)){
					if(match[1] && match[1].toLowerCase() == "style"){
						styles.push(dojo.html.fixPathsInCssText(match[2],url));
					}else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){
						styles.push({path: attr[2]});
					}
					s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
				};

				/***************** cut out all <script> tags, push them into scripts array ***************/
				var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i;
				var regexSrc = /src=(['"]?)([^"']*)\1/i;
				var regexDojoJs = /.*(\bdojo\b\.js(?:\.uncompressed\.js)?)$/;
				var regexInvalid = /(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g;
				var regexRequires = /dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix|registerModulePath)|defineNamespace)\((['"]).*?\1\)\s*;?/;

				while(match = regex.exec(s)){
					if(this.executeScripts && match[1]){
						if(attr = regexSrc.exec(match[1])){
							// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
							// we declare all files named dojo.js as bad, regardless of path
							if(regexDojoJs.exec(attr[2])){
								dojo.debug("Security note! inhibit:"+attr[2]+" from  being loaded again.");
							}else{
								scripts.push({path: attr[2]});
							}
						}
					}
					if(match[2]){
						// remove all invalid variables etc like djConfig and dojo.hostenv.writeIncludes()
						var sc = match[2].replace(regexInvalid, "");
						if(!sc){ continue; }
		
						// cut out all dojo.require (...) calls, if we have execute 
						// scripts false widgets dont get there require calls
						// takes out possible widgetpackage registration as well
						while(tmp = regexRequires.exec(sc)){
							requires.push(tmp[0]);
							sc = sc.substring(0, tmp.index) + sc.substr(tmp.index + tmp[0].length);
						}
						if(this.executeScripts){
							scripts.push(sc);
						}
					}
					s = s.substr(0, match.index) + s.substr(match.index + match[0].length);
				}

				/********* extract content *********/
				if(this.extractContent){
					match = s.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
					if(match) { s = match[1]; }
				}
	
				/*** replace scriptScope prefix in html Event handler
				* working order: find tags with scriptScope in a tag attribute
				* then replace all standalone scriptScope occurencies with reference to to this widget
				* valid onClick="scriptScope.func()" or onClick="scriptScope['func']();scriptScope.i++"
				* not valid onClick="var.scriptScope.ref" nor onClick="var['scriptScope'].ref" */
				if(this.executeScripts && this.scriptSeparation){
					var regex = /(<[a-zA-Z][a-zA-Z0-9]*\s[^>]*?\S=)((['"])[^>]*scriptScope[^>]*>)/;
					var regexAttr = /([\s'";:\(])scriptScope(.*)/; // we rely on that attribute begins ' or "
					str = ""; 
					while(tag = regex.exec(s)){
						tmp = ((tag[3]=="'") ? '"': "'");fix= "";
						str += s.substring(0, tag.index) + tag[1];
						while(attr = regexAttr.exec(tag[2])){
							tag[2] = tag[2].substring(0, attr.index) + attr[1] + "dojo.widget.byId("+ tmp + this.widgetId + tmp + ").scriptScope" + attr[2];
						}
						str += tag[2];
						s = s.substr(tag.index + tag[0].length);
					}
					s = str + s;
				}
	 		}

			return {"xml": 		s, // Object
				"styles":		styles,
				"titles": 		titles,
				"requires": 	requires,
				"scripts": 		scripts,
				"url": 			url};
		},
	
		
		_setContent: function(cont){
			this.destroyChildren();
	
			// remove old stylenodes from HEAD
			for(var i = 0; i < this._styleNodes.length; i++){
				if(this._styleNodes[i] && this._styleNodes[i].parentNode){
					this._styleNodes[i].parentNode.removeChild(this._styleNodes[i]);
				}
			}
			this._styleNodes = [];
	
			var node = this.containerNode || this.domNode;
			while(node.firstChild){
				try{
					dojo.event.browser.clean(node.firstChild);
				}catch(e){}
				node.removeChild(node.firstChild);
			}
			try{
				if(typeof cont != "string"){
					node.innerHTML = "";
					node.appendChild(cont);
				}else{
					node.innerHTML = cont;
				}
			}catch(e){
				e.text = "Couldn't load content:"+e.description;
				this._handleDefaults(e, "onContentError");
			}
		},
	
		setContent: function(/*String||DomNode*/ data){
			// summary:
			//		Replaces old content with data content, include style classes from old content
			//	data:	new content, be it Document fragment or a DomNode chain
			//			If data contains style tags, link rel=stylesheet it inserts those styles into DOM
			this.abort();
			if(this._callOnUnload){ this.onUnload(); }// this tells a remote script clean up after itself
			this._callOnUnload = true;
	
			if(!data || dojo.html.isNode(data)){
				// if we do a clean using setContent(""); or setContent(#node) bypass all parsing, extractContent etc
				this._setContent(data);
				this.onResized();
				this.onLoad();
			}else{
				// need to run splitAndFixPaths? ie. manually setting content
				// adjustPaths is taken care of inside splitAndFixPaths
				if(typeof data.xml != "string"){ 
					this.href = ""; // so we can refresh safely
					data = this.splitAndFixPaths(data); 
				}

				this._setContent(data.xml);

				// insert styles from content (in same order they came in)
				for(var i = 0; i < data.styles.length; i++){
					if(data.styles[i].path){
						this._styleNodes.push(dojo.html.insertCssFile(data.styles[i].path));
					}else{
						this._styleNodes.push(dojo.html.insertCssText(data.styles[i]));
					}
				}
	
				if(this.parseContent){
					for(var i = 0; i < data.requires.length; i++){
						try{
							eval(data.requires[i]);
						} catch(e){
							e.text = "ContentPane: error in package loading calls, " + (e.description||e);
							this._handleDefaults(e, "onContentError", "debug");
						}
					}
				}
				// need to allow async load, Xdomain uses it
				// is inline function because we cant send args to dojo.addOnLoad
				var _self = this;
				function asyncParse(){
					if(_self.executeScripts){
						_self._executeScripts(data.scripts);
					}
	
					if(_self.parseContent){
						var node = _self.containerNode || _self.domNode;
						var parser = new dojo.xml.Parse();
						var frag = parser.parseElement(node, null, true);
						// createSubComponents not createComponents because frag has already been created
						dojo.widget.getParser().createSubComponents(frag, _self);
					}
	
					_self.onResized();
					_self.onLoad();
				}
				// try as long as possible to make setContent sync call
				if(dojo.hostenv.isXDomain && data.requires.length){
					dojo.addOnLoad(asyncParse);
				}else{
					asyncParse();
				}
			}
		},

		setHandler: function(/*Function*/ handler) {
			// summary:
			//		Generate pane content from given java function
			var fcn = dojo.lang.isFunction(handler) ? handler : window[handler];
			if(!dojo.lang.isFunction(fcn)) {
				// FIXME: needs testing! somebody with java knowledge needs to try this
				this._handleDefaults("Unable to set handler, '" + handler + "' not a function.", "onExecError", true);
				return;
			}
			this.handler = function() {
				return fcn.apply(this, arguments);
			}
		},
	
		_runHandler: function() {
			var ret = true;
			if(dojo.lang.isFunction(this.handler)) {
				this.handler(this, this.domNode);
				ret = false;
			}
			this.onLoad();
			return ret;
		},
	
		_executeScripts: function(scripts) {
			// loop through the scripts in the order they came in
			var self = this;
			var tmp = "", code = "";
			for(var i = 0; i < scripts.length; i++){
				if(scripts[i].path){ // remotescript
					dojo.io.bind(this._cacheSetting({
						"url": 		scripts[i].path,
						"load":     function(type, scriptStr){
								dojo.lang.hitch(self, tmp = ";"+scriptStr);
						},
						"error":    function(type, error){
								error.text = type + " downloading remote script";
								self._handleDefaults.call(self, error, "onExecError", "debug");
						},
						"mimetype": "text/plain",
						"sync":     true
					}, this.cacheContent));
					code += tmp;
				}else{
					code += scripts[i];
				}
			}


			try{
				if(this.scriptSeparation){
					// initialize a new anonymous container for our script, dont make it part of this widgets scope chain
					// instead send in a variable that points to this widget, useful to connect events to onLoad, onUnload etc..
					delete this.scriptScope;
					this.scriptScope = new (new Function('_container_', code+'; return this;'))(self);
				}else{
					// exec in global, lose the _container_ feature
					var djg = dojo.global();
					if(djg.execScript){
						djg.execScript(code);
					}else{
						var djd = dojo.doc();
						var sc = djd.createElement("script");
						sc.appendChild(djd.createTextNode(code));
						(this.containerNode||this.domNode).appendChild(sc);
					}
				}
			}catch(e){
				e.text = "Error running scripts from content:\n"+e.description;
				this._handleDefaults(e, "onExecError", "debug");
			}
		}
	}
);

__CPAN_FILE__ src/widget/Select.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Select");

dojo.require("dojo.widget.ComboBox");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.html.stabile");

/*
 * The Select widget is an enhanced version of HTML's <select> tag.
 *
 * Similar features:
 *   - There is a drop down list of possible values.
 *   - You can only enter a value from the drop down list.  (You can't enter an arbitrary value.)
 *   - The value submitted with the form is the hidden value (ex: CA),
       not the displayed value a.k.a. label (ex: California)
 *
 * Enhancements over plain HTML version:
 *   - If you type in some text then it will filter down the list of possible values in the drop down list.
 *   - List can be specified either as a static list or via a javascript function (that can get the list from a server)
 */

dojo.widget.defineWidget(
	"dojo.widget.Select",
	dojo.widget.ComboBox,
	{
		forceValidOption: true,

		setValue: function(value) {
			this.comboBoxValue.value = value;
			dojo.widget.html.stabile.setState(this.widgetId, this.getState(), true);
			this.onValueChanged(value);
		},

		setLabel: function(value){
			// FIXME, not sure what to do here!
			this.comboBoxSelectionValue.value = value;
			if (this.textInputNode.value != value) { // prevent mucking up of selection
				this.textInputNode.value = value;
			}
		},	  

		getLabel: function(){
			return this.comboBoxSelectionValue.value;
		},

		getState: function() {
			return {
				value: this.getValue(),
				label: this.getLabel()
			};
		},

		onKeyUp: function(evt){
			this.setLabel(this.textInputNode.value);
		},

		setState: function(state) {
			this.setValue(state.value);
			this.setLabel(state.label);
		},

		setAllValues: function(value1, value2){
			this.setLabel(value1);
			this.setValue(value2);
		}
	}
);

__CPAN_FILE__ src/widget/TreeTimeoutIterator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeTimeoutIterator");


dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TreeCommon");


/**
 * Iterates the tree processNext
 * filterFunc/filterObj called to determine if I need to pass the node
 * 
 * callFunc/callObj called to process the node
 *    callObj.callFunc(elem, iterator) should call iterator.forward() to go on
 *    callFunc may change elem to another object (e.g create widget from it),
 *       keeping its parent and parent position are untouched *
 *
 * finishFunc/finishObj called at the end
 *
 * TODO: it should work only sync-way to solve CPU-hungry tasks 
 */
 dojo.declare(
 	"dojo.widget.TreeTimeoutIterator",
 	null,
 	
function(elem, callFunc, callObj) {
	var _this = this;
	
	this.currentParent = elem;
	
	this.callFunc = callFunc;
	this.callObj = callObj ? callObj: this;
	this.stack = [];	
},

{
	// public
	maxStackDepth: Number.POSITIVE_INFINITY,
	
	stack: null,
	currentParent: null,
		
	currentIndex: 0,
	
	filterFunc: function() { return true },
	
	finishFunc: function() { return true },
	
	
	setFilter: function(func, obj) {
		this.filterFunc = func;
		this.filterObj = obj;
	},
	
	
	setMaxLevel: function(level) {
		this.maxStackDepth = level-2;
	},
	
	forward: function(timeout) {
		var _this = this;
		
		if (this.timeout) { // if timeout required between forwards
			// tid will be assigned at the end of outer func execution
			var tid = setTimeout(function() {_this.processNext(); clearTimeout(tid); }, _this.timeout);
		} else {
			return this.processNext();
		}
	},
	
	start: function(processFirst) {
		if (processFirst) {			
			return this.callFunc.call(this.callObj, this.currentParent, this);			
		}
				
		return this.processNext();
	},
	
	/**
	 * @private
	 * find next node, move current parent to it if possible & process
	 */
	processNext: function() {
				
		//dojo.debug("processNext with currentParent "+this.currentParent+" index "+this.currentIndex);
		var handler;
		
		var _this = this;
		
		var found;
		
		var next;
			
		if (this.maxStackDepth == -2) {   
			return; // process only first cause level=0, do not process children
		}
		
		while (true) {
			var children = this.currentParent.children;
		
			if (children && children.length) {
		
				// look for a node that can be the next target
				do {					
					next = children[this.currentIndex];
					//dojo.debug("check "+next);
				} while (this.currentIndex++ < children.length && !(found = this.filterFunc.call(this.filterObj,next)));
			
			
				if (found) {
					//dojo.debug("found "+next);
					// move to next node as new parent if depth is fine
					// I can't check current children to decide whether to move it or not,
					// because expand may populate children					
					if (next.isFolder && this.stack.length <= this.maxStackDepth) {
						this.moveParent(next,0);
					}
					//dojo.debug("Run callFunc on "+next);
					return this.callFunc.call(this.callObj, next, this);					
				}
			}
				
			if (this.stack.length) {
				this.popParent();
				continue;
			}
			
			break;
		}

		/**
		 * couldn't find next node to process, finish here
		 */
		return this.finishFunc.call(this.finishObj);

	},
	
	setFinish: function(func, obj) {
		this.finishFunc = func;
		this.finishObj = obj;
	},
		
	popParent: function() {
		var p = this.stack.pop();
		//dojo.debug("Pop "+p[0]+":"+p[1]);		
		this.currentParent = p[0];
		this.currentIndex = p[1];
	},
	
	moveParent: function(nextParent, nextIndex) {
		//dojo.debug("Move from "+this.currentParent+":"+this.currentIndex+" to "+nextParent+":"+nextIndex);
		this.stack.push([this.currentParent, this.currentIndex]);
		this.currentParent = nextParent;
		this.currentIndex = nextIndex;
	}

});
__CPAN_FILE__ src/widget/DocPane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DocPane");

dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.Editor2");
dojo.require("dojo.widget.Dialog");

dojo.require("dojo.html.common");
dojo.require("dojo.html.display");

dojo.widget.DocPane = function(){
	dojo.event.topic.subscribe("/docs/function/results", this, "onDocResults");
	dojo.event.topic.subscribe("/docs/package/results", this, "onPkgResults");
	dojo.event.topic.subscribe("/docs/function/detail", this, "onDocSelectFunction");
}

dojo.widget.defineWidget(
	"dojo.widget.DocPane",
	dojo.widget.HtmlWidget,
	{
		// Template parameters
		dialog: null,
		dialogBg: null,
		dialogFg: null,
		logIn: null,
		edit: null,
		save: null,
		cancel: null,
		detail: null,
		result: null,
		packag: null,
		fn: null,
		fnLink: null,
		count: null,
		row: null,
		summary: null,
		description: null,
		variables: null,
		vRow: null,
		vLink: null,
		vDesc: null,
		methods: null,
		mRow: null,
		mLink: null,
		mDesc: null,
		requires: null,
		rRow: null,
		rRow2: null,
		rH3: null,
		rLink: null,
		parameters: null,
		pRow: null,
		pLink: null,
		pDesc: null,
		pOpt: null,
		pType: null,
		sType: null,
		sName: null,
		sParams: null,
		sPType: null,
		sPTypeSave: null,
		sPName: null,
		sPNameSave: null,
		pkgDescription: null,

		// Fields and methods
		_appends: [],
		templatePath: dojo.uri.dojoUri("src/widget/templates/DocPane.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/DocPane.css"),
		isContainer: true,
		fillInTemplate: function(){
			this.requires = dojo.html.removeNode(this.requires);
			this.rRow.style.display = "none";
			this.rRow2.style.display = "none";
			
			this.methods = dojo.html.removeNode(this.methods);
			this.mRow.style.display = "none";
			
			this.dialog = dojo.widget.createWidget("dialog", {}, this.dialog);
			this.dialog.setCloseControl(this.cancel);
			dojo.html.setOpacity(this.dialogBg, 0.8);
			dojo.html.setOpacity(this.dialogFg, 1);

			dojo.event.connect(this.edit, "onclick", dojo.lang.hitch(this, function(){
				if(!this._isLoggedIn){
					this.dialog.show();
				}
			}));
			dojo.event.connect(this.logIn, "onclick", this, "_logIn");
			dojo.event.connect(this.save, "onclick", this, "_save");
			dojo.event.connect(dojo.docs, "logInSuccess", this, "_loggedIn");
			
			/*
			this.pkgDescription = dojo.widget.createWidget("editor2", {
				toolbarAlwaysVisible: true
			}, this.pkgDescription);
			*/
			
			this.homeSave = this.containerNode.cloneNode(true);
			this.detailSave = dojo.html.removeNode(this.detail);
			this.resultSave = dojo.html.removeNode(this.result);
			this.packageSave = dojo.html.removeNode(this.packag);
			this.results = dojo.html.removeNode(this.results);
			this.rowParent = this.row.parentNode;
			this.rowSave = dojo.html.removeNode(this.row);
			this.vParent = this.vRow.parentNode;
			this.vSave = dojo.html.removeNode(this.vRow);
			this.pParent = this.pRow.parentNode;
			this.pSave = dojo.html.removeNode(this.pRow);
			this.sPTypeSave = dojo.html.removeNode(this.sPType);
			this.sPNameSave = dojo.html.removeNode(this.sPName);
			this.navSave = dojo.html.removeNode(this.nav);
		},

		_logIn: function(){
			dojo.docs.setUserName(this.userName.value);
			dojo.docs.setPassword(this.password.value);
		},

		_loggedIn: function(){
			this._isLoggedIn = true;
			this.dialog.hide();
			this.pkgEditor = dojo.widget.createWidget("editor2", {
				toolbarAlwaysVisible: true
			}, this.pkgDescription);
		},

		_save: function(){
			if(this.pkgEditor){
				dojo.docs.savePackage(this._pkgPath, {
					description: this.pkgEditor.getEditorContent()
				});
			}
		},

		onDocSelectFunction: function(message){
			dojo.debug("onDocSelectFunction()");
			for(var key in message){
				dojo.debug(key + ": " + dojo.json.serialize(message[key]));
			}
			var meta = message.meta;
			if(meta){
				var variables = meta.variables;
				var this_variables = meta.this_variables;
				var child_variables = meta.child_variables;
				var parameters = meta.parameters;
			}
			var doc = message.doc;
			dojo.debug(dojo.json.serialize(doc));

			var appends = this._appends;
			dojo.html.removeChildren(this.domNode);
			this.fn.innerHTML = message.name;

			this.variables.style.display = "block";
			var all = [];
			if(variables){
				all = variables;
			}
			if(this_variables){
				all = all.concat(this_variables);
			}
			if(child_variables){
				all = all.concat(child_variables);
			}
			if(!all.length){
				this.variables.style.display = "none";
			}else{
				for(var i = 0, one; one = all[i]; i++){
					this.vLink.innerHTML = one;
					this.vDesc.parentNode.style.display = "none";
					appends.push(this.vParent.appendChild(this.vSave.cloneNode(true)));
				}
			}

			this.sParams.innerHTML = "";
			var first = true;
			for(var param in parameters){
				var paramType = parameters[param].type;
				var paramSummary = parameters[param].summary;
				var paramName = param;
				this.parameters.style.display = "block";		
				this.pLink.innerHTML = paramName;
				this.pOpt.style.display = "none";
				if(parameters[param].opt){
					this.pOpt.style.display = "inline";				
				}
				this.pType.parentNode.style.display = "none";
				if(parameters[param][0]){
					this.pType.parentNode.style.display = "inline";
					this.pType.innerHTML = paramType;
				}
				this.pDesc.parentNode.style.display = "none";
				if(paramSummary){
					this.pDesc.parentNode.style.display = "inline";
					this.pDesc.innerHTML = paramSummary;
				}
				appends.push(this.pParent.appendChild(this.pSave.cloneNode(true)));

				if(!first) {
					this.sParams.appendChild(document.createTextNode(", "));
				}
				first = false;
				if(paramType){
					dojo.debug(this.sPTypeSave);
					this.sPTypeSave.innerHTML = paramType;
					this.sParams.appendChild(this.sPTypeSave.cloneNode(true));
					this.sParams.appendChild(document.createTextNode(" "));
				}
				dojo.debug(this.sPNameSave);
				this.sPNameSave.innerHTML = paramName;
				this.sParams.appendChild(this.sPNameSave.cloneNode(true))
			}

			if(message.returns){
				this.sType.innerHTML = message.returns;
			}else{
				this.sType.innerHTML = "void";
			}

			this.sName.innerHTML = message.name;

			this.domNode.appendChild(this.navSave);
			this.domNode.appendChild(this.detailSave.cloneNode(true));

			for(var i = 0, append; append = appends[i]; i++){
				dojo.html.removeNode(append);
			}
		},

		onPkgResult: function(/*Object*/ results){
			if(this.pkgEditor){
				this.pkgEditor.close(true);
				dojo.debug(this.pkgDescription);
			}
			var methods = results.methods;
			var requires = results.requires;
			var description = results.description;
			this._pkgPath = results.path;
			var requireLinks = [];
			var appends = this._appends;
			while(appends.length){
				dojo.html.removeNode(appends.shift());
			}

			dojo.html.removeChildren(this.domNode);
			
			this.pkg.innerHTML = results.pkg;
			
			var hasRequires = false;
			for(var env in requires){
				hasRequires = true;

				this.rH3.style.display = "none";
				if(env != "common"){
					this.rH3.style.display = "";
					this.rH3.innerHTML = env;
				}

				for(var i = 0, require; require = requires[env][i]; i++){
					requireLinks.push({
						name: require
					});
					this.rLink.innerHTML = require;
					this.rLink.href = "#" + require;
					var rRow2 = this.rRow2.parentNode.insertBefore(this.rRow2.cloneNode(true), this.rRow2);
					rRow2.style.display = "";
					appends.push(rRow2);
				}
				var rRow = this.rRow.parentNode.insertBefore(this.rRow.cloneNode(true), this.rRow);
				rRow.style.display = "";
				appends.push(rRow);
			}
			
			if(hasRequires){
				appends.push(this.packageSave.appendChild(this.requires.cloneNode(true)));
			}

			if(results.size){
				for(var i = 0, method; method = methods[i]; i++){
					this.mLink.innerHTML = method.name;
					this.mLink.href = "#" + method.name;
					this.mDesc.parentNode.style.display = "none";
					if(method.summary){
						this.mDesc.parentNode.style.display = "inline";				
						this.mDesc.innerHTML = method.summary;
					}
					var mRow = this.mRow.parentNode.insertBefore(this.mRow.cloneNode(true), this.mRow);
					mRow.style.display = "";
					appends.push(mRow);
				}
				appends.push(this.packageSave.appendChild(this.methods.cloneNode(true)));
			}

			this.domNode.appendChild(this.packageSave);
			
			/*
			dojo.debug(description);
			function fillContent(){
				this.pkgDescription.replaceEditorContent(description);
				this.pkgDescription._updateHeight();
			}
			if(this.pkgDescription.isLoaded){
				fillContent();
			}else{
				dojo.event.connect(this.pkgDescription, "onLoad", dojo.lang.hitch(this, fillContent));
			}
			*/
			this.pkgDescription.innerHTML = description;
			
			function makeSelect(fOrP, x){
				return function(e) {
					dojo.event.topic.publish("/docs/" + fOrP + "/select", x);
				}
			}

			var as = this.domNode.getElementsByTagName("a");
			for(var i = 0, a; a = as[i]; i++){
				if(a.className == "docMLink"){
					dojo.event.connect(a, "onclick", makeSelect("function", methods[i]));
				}else if(a.className == "docRLink"){
					dojo.event.connect(a, "onclick", makeSelect("package", requireLinks[i]));
				}
			}
		},

		onDocResults: function(fns){
			dojo.debug("onDocResults(): called");

			if(fns.length == 1){
				dojo.event.topic.publish("/docs/function/select", fns[0]);
				return;
			}

			dojo.html.removeChildren(this.domNode);

			this.count.innerHTML = fns.length;
			var appends = [];
			for(var i = 0, fn; fn = fns[i]; i++){
				this.fnLink.innerHTML = fn.name;
				this.fnLink.href = "#" + fn.name;
				if(fn.id){
					this.fnLink.href = this.fnLink.href + "," + fn.id;	
				}
				this.summary.parentNode.style.display = "none";
				if(fn.summary){
					this.summary.parentNode.style.display = "inline";				
					this.summary.innerHTML = fn.summary;
				}
				appends.push(this.rowParent.appendChild(this.rowSave.cloneNode(true)));
			}

			function makeSelect(x){
				return function(e) {
					dojo.event.topic.publish("/docs/function/select", x);
				}
			}

			this.domNode.appendChild(this.resultSave.cloneNode(true));
			var as = this.domNode.getElementsByTagName("a");
			for(var i = 0, a; a = as[i]; i++){
				dojo.event.connect(a, "onclick", makeSelect(fns[i]));
			}

			for(var i = 0, append; append = appends[i]; i++){
				this.rowParent.removeChild(append);
			}
		}
	}
);

__CPAN_FILE__ src/widget/Editor2Toolbar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Toolbar");

dojo.require("dojo.lang.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.display");
dojo.require("dojo.widget.RichText");
dojo.require("dojo.widget.PopupContainer");
dojo.require("dojo.widget.ColorPalette");

// Object: Manager available editor2 toolbar items
dojo.widget.Editor2ToolbarItemManager = {
	_registeredItemHandlers: [],
	registerHandler: function(/*Object*/obj, /*String*/func){
		// summary: register a toolbar item handler
		// obj: object which has the function to call
		// func: the function in the object
		if(arguments.length == 2){
			this._registeredItemHandlers.push(function(){return obj[func].apply(obj, arguments);});
		}else{
			/* obj: Function
			    func: null
			    pId: f */
//			for(i in this._registeredItemHandlers){
//				if(func === this._registeredItemHandlers[i]){
//					dojo.debug("Editor2ToolbarItemManager handler "+func+" is already registered, ignored");
//					return;
//				}
//			}
			this._registeredItemHandlers.push(obj);
		}
	},
	removeHandler: function(func){
		// summary: remove a registered handler
		for(var i in this._registeredItemHandlers){
			if(func === this._registeredItemHandlers[i]){
				delete this._registeredItemHandlers[i];
				return;
			}
		}
		dojo.debug("Editor2ToolbarItemManager handler "+func+" is not registered, can not remove.");
	},
	destroy: function(){
		for(var i in this._registeredItemHandlers){
			delete this._registeredItemHandlers[i];
		}
	},
	getToolbarItem: function(/*String*/name){
		// summary: return a toobar item with the given name
		var item;
		name = name.toLowerCase();
		for(var i in this._registeredItemHandlers){
			item = this._registeredItemHandlers[i](name);
			if(item){
				break;
			}
		}

		if(!item){
			switch(name){
				//button for builtin functions
				case 'bold':
				case 'copy':
				case 'cut':
				case 'delete':
				case 'indent':
				case 'inserthorizontalrule':
				case 'insertorderedlist':
				case 'insertunorderedlist':
				case 'italic':
				case 'justifycenter':
				case 'justifyfull':
				case 'justifyleft':
				case 'justifyright':
				case 'outdent':
				case 'paste':
				case 'redo':
				case 'removeformat':
				case 'selectall':
				case 'strikethrough':
				case 'subscript':
				case 'superscript':
				case 'underline':
				case 'undo':
				case 'unlink':
				case 'createlink':
				case 'insertimage':
				//extra simple buttons
				case 'htmltoggle':
					item = new dojo.widget.Editor2ToolbarButton(name);
					break;
				case 'forecolor':
				case 'hilitecolor':
					item = new dojo.widget.Editor2ToolbarColorPaletteButton(name);
					break;
				case 'plainformatblock':
					item = new dojo.widget.Editor2ToolbarFormatBlockPlainSelect("formatblock");
					break;
				case 'formatblock':
					item = new dojo.widget.Editor2ToolbarFormatBlockSelect("formatblock");
					break;
				case 'fontsize':
					item = new dojo.widget.Editor2ToolbarFontSizeSelect("fontsize");
					break;
				case 'fontname':
					item = new dojo.widget.Editor2ToolbarFontNameSelect("fontname");
					break;
				case 'inserttable':
				case 'insertcell':
				case 'insertcol':
				case 'insertrow':
				case 'deletecells':
				case 'deletecols':
				case 'deleterows':
				case 'mergecells':
				case 'splitcell':
					dojo.debug(name + " is implemented in dojo.widget.Editor2Plugin.TableOperation, please require it first.");
					break;
				//TODO:
				case 'inserthtml':
				case 'blockdirltr':
				case 'blockdirrtl':
				case 'dirltr':
				case 'dirrtl':
				case 'inlinedirltr':
				case 'inlinedirrtl':
					dojo.debug("Not yet implemented toolbar item: "+name);
					break;
				default:
					dojo.debug("dojo.widget.Editor2ToolbarItemManager.getToolbarItem: Unknown toolbar item: "+name);
			}
		}
		return item;
	}
};

dojo.addOnUnload(dojo.widget.Editor2ToolbarItemManager, "destroy");
// summary:
//		dojo.widget.Editor2ToolbarButton is the base class for all toolbar item in Editor2Toolbar
dojo.declare("dojo.widget.Editor2ToolbarButton", null,{
	initializer: function(name){
		// summary: constructor
		this._name = name;
		this._command = dojo.widget.Editor2Manager.getCommand(name);
	},
	create: function(/*DomNode*/node, /*dojo.widget.Editor2Toolbar*/toolbar, /*Boolean*/nohover){
		// summary: create the item
		// node: the dom node which is the root of this toolbar item
		// toolbar: the Editor2Toolbar widget this toolbar item belonging to
		// nohover: whether this item in charge of highlight this item
		this._domNode = node;
		//make this unselectable: different browsers
		//use different properties for this, so use
		//js do it automatically
		this.disableSelection(this._domNode);
		this._parentToolbar = toolbar;
		dojo.event.connect(this._domNode, 'onclick', this, 'onClick');
		if(!nohover){
			dojo.event.connect(this._domNode, 'onmouseover', this, 'onMouseOver');
			dojo.event.connect(this._domNode, 'onmouseout', this, 'onMouseOut');
		}
	},
	disableSelection: function(/*DomNode*/rootnode){
		// summary: disable selection on the passed node and all its children
		dojo.html.disableSelection(rootnode);
		var nodes = rootnode.all || rootnode.getElementsByTagName("*");
		for(var x=0; x<nodes.length; x++){
			dojo.html.disableSelection(nodes[x]);
		}
	},
	onMouseOver: function(){
		if(this._command.getState() != dojo.widget.Editor2Manager.commandState.Disabled){
			this.highlightToolbarItem();
		}
	},
	onMouseOut: function(){
		this.unhighlightToolbarItem();
	},
	destroy: function(){
		// summary: destructor
		this._domNode = null;
		delete this._command;
		this._parentToolbar = null;
	},
	onClick: function(e){
		if(this._domNode && !this._domNode.disabled && this._command){
			e.preventDefault();
			e.stopPropagation();
			this._command.execute();
		}
	},
	refreshState: function(){
		// summary: update the state of the toolbar item
		if(this._domNode && this._command){
			var em = dojo.widget.Editor2Manager;
			var state = this._command.getState();
			if(state != this._lastState){
				switch(state){
					case em.commandState.Latched:
						this.latchToolbarItem();
						break;
					case em.commandState.Enabled:
						this.enableToolbarItem();
						break;
					case em.commandState.Disabled:
					default:
						this.disableToolbarItem();
				}
				this._lastState = state;
			}
			return state;
		}
	},

	latchToolbarItem: function(){
		this._domNode.disabled = false;
		this.removeToolbarItemStyle(this._domNode);
		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarLatchedItemStyle);
	},

	enableToolbarItem: function(){
		this._domNode.disabled = false;
		this.removeToolbarItemStyle(this._domNode);
		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarEnabledItemStyle);
	},

	disableToolbarItem: function(){
		this._domNode.disabled = true;
		this.removeToolbarItemStyle(this._domNode);
		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarDisabledItemStyle);
	},

	highlightToolbarItem: function(){
		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarHighlightedItemStyle);
	},

	unhighlightToolbarItem: function(){
		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarHighlightedItemStyle);
	},

	removeToolbarItemStyle: function(){
		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarEnabledItemStyle);
		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarLatchedItemStyle);
		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarDisabledItemStyle);
		this.unhighlightToolbarItem();
	}
});

// summary: dojo.widget.Editor2ToolbarDropDownButton extends the basic button with a dropdown list
dojo.declare("dojo.widget.Editor2ToolbarDropDownButton", dojo.widget.Editor2ToolbarButton,{
	onClick: function(){
		if(this._domNode){
			if(!this._dropdown){
				this._dropdown = dojo.widget.createWidget("PopupContainer", {});
				this._domNode.appendChild(this._dropdown.domNode);
			}
			if(this._dropdown.isShowingNow){
				this._dropdown.close();
			}else{
				this.onDropDownShown();
				this._dropdown.open(this._domNode, null, this._domNode);
			}
		}
	},
	destroy: function(){
		this.onDropDownDestroy();
		if(this._dropdown){
			this._dropdown.destroy();
		}
		dojo.widget.Editor2ToolbarDropDownButton.superclass.destroy.call(this);
	},
	onDropDownShown: function(){},
	onDropDownDestroy: function(){}
});

// summary: dojo.widget.Editor2ToolbarColorPaletteButton provides a dropdown color palette picker
dojo.declare("dojo.widget.Editor2ToolbarColorPaletteButton", dojo.widget.Editor2ToolbarDropDownButton,{
	onDropDownShown: function(){
		if(!this._colorpalette){
			this._colorpalette = dojo.widget.createWidget("ColorPalette", {});
			this._dropdown.addChild(this._colorpalette);

			this.disableSelection(this._dropdown.domNode);
			this.disableSelection(this._colorpalette.domNode);
			//do we need a destory to delete this._colorpalette manually?
			//I assume as it is added to this._dropdown via addChild, it
			//should be deleted when this._dropdown is destroyed

			dojo.event.connect(this._colorpalette, "onColorSelect", this, 'setColor');
			dojo.event.connect(this._dropdown, "open", this, 'latchToolbarItem');
			dojo.event.connect(this._dropdown, "close", this, 'enableToolbarItem');
		}
	},
	setColor: function(color){
		this._dropdown.close();
		this._command.execute(color);
	}
});

// summary: dojo.widget.Editor2ToolbarFormatBlockPlainSelect provides a simple select for setting block format
dojo.declare("dojo.widget.Editor2ToolbarFormatBlockPlainSelect", dojo.widget.Editor2ToolbarButton,{
	create: function(node, toolbar){
		//TODO: check node is a select
		this._domNode = node;
		this.disableSelection(this._domNode);
		this._parentToolbar = toolbar;
		dojo.event.connect(this._domNode, 'onchange', this, 'onChange');
	},

	destroy: function(){
		this._domNode = null;
		this._command = null;
		this._parentToolbar = null;
	},

	onChange: function(){
		if(this._domNode){
			var sv = this._domNode.value.toLowerCase();
			this._command.execute(sv);
		}
	},

	refreshState: function(){
		if(this._domNode && this._command){
			dojo.widget.Editor2ToolbarFormatBlockPlainSelect.superclass.refreshState.call(this);
			var format = this._command.getValue();
			if(!format){ format = ""; }
			dojo.lang.forEach(this._domNode.options, function(item){
				if(item.value.toLowerCase() == format.toLowerCase()){
					item.selected = true;
				}
			});
		}
	}
});

// summary: dojo.widget.Editor2ToolbarComboItem provides an external loaded dropdown list
dojo.declare("dojo.widget.Editor2ToolbarComboItem", dojo.widget.Editor2ToolbarDropDownButton,{
	href: null,
	create: function(node, toolbar){
		dojo.widget.Editor2ToolbarComboItem.superclass.create.call(this, node, toolbar);
		//do not use lazy initilization, as we need the local names in refreshState()
		if(!this._contentPane){
			dojo.require("dojo.widget.ContentPane");
			this._contentPane = dojo.widget.createWidget("ContentPane", {preload: 'true'});
			this._contentPane.addOnLoad(this, "setup");
			this._contentPane.setUrl(this.href);
		}
	},

	onMouseOver: function(e){
		dojo.html.addClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectStyle);
	},
	onMouseOut:function(e){
		dojo.html.removeClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectStyle);
	},

	onDropDownShown: function(){
		if(!this._dropdown.__addedContentPage){
			this._dropdown.addChild(this._contentPane);
			this._dropdown.__addedContentPage = true;
		}
	},

	setup: function(){
		// summary: overload this to connect event
	},

	onChange: function(e){
		var name = e.currentTarget.getAttribute("dropDownItemName");
		this._command.execute(name);
		this._dropdown.close();
	},

	onMouseOverItem: function(e){
		dojo.html.addClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectItemStyle);
	},

	onMouseOutItem: function(e){
		dojo.html.removeClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectItemStyle);
	},

	refreshState: function(){
		// summary: overload this to update GUI item
	}
});

// summary: dojo.widget.Editor2ToolbarFormatBlockSelect is an improved format block setting item
dojo.declare("dojo.widget.Editor2ToolbarFormatBlockSelect", dojo.widget.Editor2ToolbarComboItem,{
	href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FormatBlock.html"),

	setup: function(){
		dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.setup.call(this);

		var nodes = this._contentPane.domNode.all || this._contentPane.domNode.getElementsByTagName("*");
		this._blockNames = {};
		this._blockDisplayNames = {};
		for(var x=0; x<nodes.length; x++){
			var node = nodes[x];
			dojo.html.disableSelection(node);
			var name=node.getAttribute("dropDownItemName")
			if(name){
				this._blockNames[name] = node;
				var childrennodes = node.getElementsByTagName(name);
				this._blockDisplayNames[name] = childrennodes[childrennodes.length-1].innerHTML;
			}
		}
		for(var name in this._blockNames){
			dojo.event.connect(this._blockNames[name], "onclick", this, "onChange");
			dojo.event.connect(this._blockNames[name], "onmouseover", this, "onMouseOverItem");
			dojo.event.connect(this._blockNames[name], "onmouseout", this, "onMouseOutItem");
		}
	},

	onDropDownDestroy: function(){
		if(this._blockNames){
			for(var name in this._blockNames){
				delete this._blockNames[name];
				delete this._blockDisplayNames[name];
			}
		}
	},

	refreshState: function(){
		if(this._command){
			//dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.refreshState.call(this);
			var format = this._command.getValue();
			if(format == this._lastSelectedFormat && this._blockDisplayNames){
				return;
			}
			this._lastSelectedFormat = format;
			var label = this._domNode.getElementsByTagName("label")[0];
			var isSet = false;
			if(this._blockDisplayNames){
				for(var name in this._blockDisplayNames){
					if(name == format){
						label.innerHTML = 	this._blockDisplayNames[name];
						isSet = true;
						break;
					}
				}
				if(!isSet){
					label.innerHTML = "&nbsp;";
				}
			}
		}
	}
});

// summary: dojo.widget.Editor2ToolbarFontSizeSelect provides a dropdown list for setting fontsize
dojo.declare("dojo.widget.Editor2ToolbarFontSizeSelect", dojo.widget.Editor2ToolbarComboItem,{
	href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FontSize.html"),

	setup: function(){
		dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.setup.call(this);

		var nodes = this._contentPane.domNode.all || this._contentPane.domNode.getElementsByTagName("*");
		this._fontsizes = {};
		this._fontSizeDisplayNames = {};
		for(var x=0; x<nodes.length; x++){
			var node = nodes[x];
			dojo.html.disableSelection(node);
			var name=node.getAttribute("dropDownItemName")
			if(name){
				this._fontsizes[name] = node;
				this._fontSizeDisplayNames[name] = node.getElementsByTagName('font')[0].innerHTML;
			}
		}
		for(var name in this._fontsizes){
			dojo.event.connect(this._fontsizes[name], "onclick", this, "onChange");
			dojo.event.connect(this._fontsizes[name], "onmouseover", this, "onMouseOverItem");
			dojo.event.connect(this._fontsizes[name], "onmouseout", this, "onMouseOutItem");
		}
	},

	onDropDownDestroy: function(){
		if(this._fontsizes){
			for(var name in this._fontsizes){
				delete this._fontsizes[name];
				delete this._fontSizeDisplayNames[name];
			}
		}
	},

	refreshState: function(){
		if(this._command){
			//dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.refreshState.call(this);
			var size = this._command.getValue();
			if(size == this._lastSelectedSize && this._fontSizeDisplayNames){
				return;
			}
			this._lastSelectedSize = size;
			var label = this._domNode.getElementsByTagName("label")[0];
			var isSet = false;
			if(this._fontSizeDisplayNames){
				for(var name in this._fontSizeDisplayNames){
					if(name == size){
						label.innerHTML = 	this._fontSizeDisplayNames[name];
						isSet = true;
						break;
					}
				}
				if(!isSet){
					label.innerHTML = "&nbsp;";
				}
			}
		}
	}
});

// summary: dojo.widget.Editor2ToolbarFontNameSelect provides a dropdown list for setting fontname
dojo.declare("dojo.widget.Editor2ToolbarFontNameSelect", dojo.widget.Editor2ToolbarFontSizeSelect,{
	href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FontName.html")
});

// summary:
//		dojo.widget.Editor2Toolbar is the main widget for the toolbar associated with an Editor2
dojo.widget.defineWidget(
	"dojo.widget.Editor2Toolbar",
	dojo.widget.HtmlWidget,
	{
		templatePath: dojo.uri.dojoUri("src/widget/templates/EditorToolbar.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/EditorToolbar.css"),

		// DOM Nodes
//		saveButton: null,

		// String: class name for latched toolbar button items
		ToolbarLatchedItemStyle: "ToolbarButtonLatched",
		// String: class name for enabled toolbar button items
		ToolbarEnabledItemStyle: "ToolbarButtonEnabled",
		// String: class name for disabled toolbar button items
		ToolbarDisabledItemStyle: "ToolbarButtonDisabled",
		// String: class name for highlighted toolbar button items
		ToolbarHighlightedItemStyle: "ToolbarButtonHighlighted",
		// String: class name for highlighted toolbar select items
		ToolbarHighlightedSelectStyle: "ToolbarSelectHighlighted",
		// String: class name for highlighted toolbar select dropdown items
		ToolbarHighlightedSelectItemStyle: "ToolbarSelectHighlightedItem",

//		itemNodeType: 'span', //all the items (with attribute dojoETItemName set) defined in the toolbar should be a of this type

		postCreate: function(){
			var nodes = dojo.html.getElementsByClass("dojoEditorToolbarItem", this.domNode/*, this.itemNodeType*/);

			this.items = {};
			for(var x=0; x<nodes.length; x++){
				var node = nodes[x];
				var itemname = node.getAttribute("dojoETItemName");
				if(itemname){
					var item = dojo.widget.Editor2ToolbarItemManager.getToolbarItem(itemname);
					if(item){
						item.create(node, this);
						this.items[itemname.toLowerCase()] = item;
					}else{
						//hide unsupported toolbar items
						node.style.display = "none";
					}
				}
			}
		},

		update: function(){
			// summary: update all the toolbar items
			for(var cmd in this.items){
				this.items[cmd].refreshState();
			}
		},

		destroy: function(){
			for(var it in this.items){
				this.items[it].destroy();
				delete this.items[it];
			}
			dojo.widget.Editor2Toolbar.superclass.destroy.call(this);
		}//,

		// stub for observers
//		exec: function(what, arg){ /* dojo.debug(what, new Date()); */ }
	},
	"html",
	function(){
		dojo.event.connect(this, "fillInTemplate", dojo.lang.hitch(this, function(){
			if(dojo.render.html.ie){
				this.domNode.style.zoom = 1.0;
			}
		}));
	}
);

__CPAN_FILE__ src/widget/Slider.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Slider");

// load dependencies
dojo.require("dojo.event.*");
dojo.require("dojo.dnd.*");
// dojo.dnd.* doesn't include this package, because it's not in __package__.js
dojo.require("dojo.dnd.HtmlDragMove");
dojo.require("dojo.widget.*");
dojo.require("dojo.html.layout");


// summary
//	Slider Widget.
//	
//	The slider widget comes in three forms:
//	 1. Base Slider widget which supports movement in x and y dimensions
//	 2. Vertical Slider (SliderVertical) widget which supports movement
//	    only in the y dimension.
//	 3. Horizontal Slider (SliderHorizontal) widget which supports movement
//	    only in the x dimension.
//
//	The key objects in the widget are:
//	 - a container div which displays a bar in the background (Slider object)
//	 - a handle inside the container div, which represents the value
//	   (sliderHandle DOM node)
//	 - the object which moves the handle (_handleMove is of type 
//	   SliderDragMoveSource)
//
//	The values for the slider are calculated by grouping pixels together, 
//	based on the number of values to be represented by the slider.
//	The number of pixels in a group is called the _valueSize
//	 e.g. if slider is 150 pixels long, and is representing the values
//	      0,1,...10 then pixels are grouped into lots of 15 (_valueSize), where:
//	        value 0 maps to pixels  0 -  7
//	              1                 8 - 22
//	              2                23 - 37 etc.
//	The accuracy of the slider is limited to the number of pixels
//	(i.e tiles > pixels will result in the slider not being able to
//	 represent some values).
dojo.widget.defineWidget (
	"dojo.widget.Slider",
	dojo.widget.HtmlWidget,
	{
		// Number
		//	minimum value to be represented by slider in the horizontal direction
		minimumX: 0,
		// Number
		//	minimum value to be represented by slider in the vertical direction
		minimumY: 0,
		// Number
		//	maximum value to be represented by slider in the horizontal direction
		maximumX: 10,
		// Number
		//	maximum value to be represented by slider in the vertical direction
		maximumY: 10,
		// Number
		//	number of values to be represented by slider in the horizontal direction
		//	=0 means no snapping
		snapValuesX: 0,
		// Number
		//	number of values to be represented by slider in the vertical direction
		//	=0 means no snapping
		snapValuesY: 0,
		// should the handle snap to the grid or remain where it was dragged to?
		// FIXME: snapToGrid=false is logically in conflict with setting snapValuesX and snapValuesY
		_snapToGrid: true,
		// Boolean
		//	enables (disables) sliding in the horizontal direction
		isEnableX: true,
		// Boolean
		//	enables (disables) sliding in the vertical direction
		isEnableY: true,
		// value size (pixels) in the x dimension
		_valueSizeX: 0.0,
		// value size (pixels) in the y dimension
		_valueSizeY: 0.0,
		// left most edge of constraining container (pixels) in the X dimension
		_minX: 0,
		// top most edge of constraining container (pixels) in the Y dimension
		_minY: 0,
		// constrained slider size (pixels) in the x dimension
		_constraintWidth: 0,
		// constrained slider size (pixels) in the y dimension
		_constraintHeight: 0,
		// progress image right clip value (pixels) in the X dimension
		_clipLeft: 0,
		// progress image left clip value (pixels) in the X dimension
		_clipRight: 0,
		// progress image top clip value (pixels) in the Y dimension
		_clipTop: 0,
		// progress image bottom clip value (pixels) in the Y dimension
		_clipBottom: 0,
		// half the size of the slider handle (pixels) in the X dimension
		_clipXdelta: 0,
		// half the size of the slider handle (pixels) in the Y dimension
		_clipYdelta: 0,
		// Number
		//	initial value in the x dimension
		initialValueX: 0,
		// Number
		//	initial value in the y dimension
		initialValueY: 0,
		// Boolean
		//	values decrease in the X dimension
		flipX: false,
		// Boolean
		//	values decrease in the Y dimension
		flipY: false,
		// Boolean
		//	enables (disables) the user to click on the slider to set the position
		clickSelect: true,
		// Boolean
		//	disables (enables) the value to change while you are dragging, or just after drag finishes
		activeDrag: false,

		templateCssPath: dojo.uri.dojoUri ("src/widget/templates/Slider.css"),
		templatePath: dojo.uri.dojoUri ("src/widget/templates/Slider.html"),

		// This is set to true when a drag is started, so that it is not confused
		// with a click
		_isDragInProgress: false,

		// default user style attributes
		// String
		//	down arrow graphic URL
		bottomButtonSrc: dojo.uri.dojoUri("src/widget/templates/images/slider_down_arrow.png"),
		// String
		//	up arrow graphic URL
		topButtonSrc: dojo.uri.dojoUri("src/widget/templates/images/slider_up_arrow.png"),
		// String
		//	left arrow graphic URL
		leftButtonSrc: dojo.uri.dojoUri("src/widget/templates/images/slider_left_arrow.png"),
		// String
		//	right arrow graphic URL
		rightButtonSrc: dojo.uri.dojoUri("src/widget/templates/images/slider_right_arrow.png"),
		// String
		//	slider background graphic URL
		backgroundSrc: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
		// String
		//	slider background graphic URL to overlay the normal background to show progress
		progressBackgroundSrc: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
		// String
		//	sizing style attributes for the background image
		backgroundSize: "width:200px;height:200px;",
		// String
		//	style attributes (other than sizing) for the background image
		backgroundStyle: "",
		// String
		//	style attributes for the left and right arrow images
		buttonStyleX: "",
		// String
		//	style attributes for the up and down arrow images
		buttonStyleY: "",
		// String
		//	style attributes for the moveable slider image
		handleStyle: "",
		// String
		//	moveable slider graphic URL
		handleSrc: dojo.uri.dojoUri("src/widget/templates/images/slider-button.png"),
		// Boolean
		//	show (don't show) the arrow buttons
		showButtons: true,
		_eventCount: 0,
		_typamaticTimer: null,
		_typamaticFunction: null,
		// Number
		//	number of milliseconds before a held key or button becomes typematic 
		defaultTimeout: 500,
		// Number
		//	fraction of time used to change the typematic timer between events
		//	1.0 means that each typematic event fires at defaultTimeout intervals
		//	< 1.0 means that each typematic event fires at an increasing faster rate
		timeoutChangeRate: 0.90,
		_currentTimeout: this.defaultTimeout,

		// does the keyboard related stuff
		_handleKeyEvents: function(/*Event*/ evt){
			if(!evt.key){ return; }

			if(!evt.ctrlKey && !evt.altKey){
				switch(evt.key){
					case evt.KEY_LEFT_ARROW:
						dojo.event.browser.stopEvent(evt);
						this._leftButtonPressed(evt);
						return;
					case evt.KEY_RIGHT_ARROW:
						dojo.event.browser.stopEvent(evt);
						this._rightButtonPressed(evt);
						return;
					case evt.KEY_DOWN_ARROW:
						dojo.event.browser.stopEvent(evt);
						this._bottomButtonPressed(evt);
						return;
					case evt.KEY_UP_ARROW:
						dojo.event.browser.stopEvent(evt);
						this._topButtonPressed(evt);
						return;
				}
			}
			this._eventCount++;

		},

		_pressButton: function(/*DomNode*/ buttonNode){
			buttonNode.className = buttonNode.className.replace("Outset","Inset");
		},

		_releaseButton: function(/*DomNode*/ buttonNode){
			buttonNode.className = buttonNode.className.replace("Inset","Outset");
		},

		_buttonPressed: function(/*Event*/ evt, /*DomNode*/ buttonNode){
			this._setFocus();
			if(typeof evt == "object"){
				if(this._typamaticTimer != null){
					if(this._typamaticNode == buttonNode){
						return;
					}
					clearTimeout(this._typamaticTimer);
				}
				this._buttonReleased(null);
				this._eventCount++;
				this._typamaticTimer = null;
				this._currentTimeout = this.defaultTimeout;
				dojo.event.browser.stopEvent(evt);
			}else if (evt != this._eventCount){
				this._buttonReleased(null);
				return false;
			}
			if (buttonNode == this.leftButtonNode && this.isEnableX){
				this._snapX(dojo.html.getPixelValue (this.sliderHandleNode,"left") - this._valueSizeX);
			}
			else if (buttonNode == this.rightButtonNode && this.isEnableX){
				this._snapX(dojo.html.getPixelValue (this.sliderHandleNode,"left") + this._valueSizeX);
			}
			else if (buttonNode == this.topButtonNode && this.isEnableY){
				this._snapY(dojo.html.getPixelValue (this.sliderHandleNode,"top") - this._valueSizeY);
			}
			else if (buttonNode == this.bottomButtonNode && this.isEnableY){
				this._snapY(dojo.html.getPixelValue (this.sliderHandleNode,"top") + this._valueSizeY);
			}
			else {
				return false;
			}
			this._pressButton(buttonNode);
			this.notifyListeners();
			this._typamaticNode = buttonNode;
			this._typamaticTimer = dojo.lang.setTimeout(this, "_buttonPressed", this._currentTimeout, this._eventCount, buttonNode);
			this._currentTimeout = Math.round(this._currentTimeout * this.timeoutChangeRate);
			return false;
		},

		_bottomButtonPressed: function(/*Event*/ evt){
			return this._buttonPressed(evt,this.bottomButtonNode);
		},

		// IE sends these events when rapid clicking, mimic an extra single click
		_bottomButtonDoubleClicked: function(/*Event*/ evt){
			var rc = this._bottomButtonPressed(evt);
			dojo.lang.setTimeout( this, "_buttonReleased", 50, null);
			return rc;
		},

		_topButtonPressed: function(/*Event*/ evt){
			return this._buttonPressed(evt,this.topButtonNode);
		},

		// IE sends these events when rapid clicking, mimic an extra single click
		_topButtonDoubleClicked: function(/*Event*/ evt){
			var rc = this._topButtonPressed(evt);
			dojo.lang.setTimeout( this, "_buttonReleased", 50, null);
			return rc;
		},

		_leftButtonPressed: function(/*Event*/ evt){
			return this._buttonPressed(evt,this.leftButtonNode);
		},

		// IE sends these events when rapid clicking, mimic an extra single click
		_leftButtonDoubleClicked: function(/*Event*/ evt){
			var rc = this._leftButtonPressed(evt);
			dojo.lang.setTimeout( this, "_buttonReleased", 50, null);
			return rc;
		},

		_rightButtonPressed: function(/*Event*/ evt){
			return this._buttonPressed(evt,this.rightButtonNode);
		},

		// IE sends these events when rapid clicking, mimic an extra single click
		_rightButtonDoubleClicked: function(/*Event*/ evt){
			var rc = this._rightButtonPressed(evt);
			dojo.lang.setTimeout( this, "_buttonReleased", 50, null);
			return rc;
		},

		_buttonReleased: function(/*Event*/ evt){
			if(typeof evt == "object" && evt != null && typeof evt.keyCode != "undefined" && evt.keyCode != null){
				var keyCode = evt.keyCode;

				switch(keyCode){
					case evt.KEY_LEFT_ARROW:
					case evt.KEY_RIGHT_ARROW:
					case evt.KEY_DOWN_ARROW:
					case evt.KEY_UP_ARROW:
						dojo.event.browser.stopEvent(evt);
						break;
				}
			}
			this._releaseButton(this.topButtonNode);
			this._releaseButton(this.bottomButtonNode);
			this._releaseButton(this.leftButtonNode);
			this._releaseButton(this.rightButtonNode);
			this._eventCount++;
			if(this._typamaticTimer != null){
				clearTimeout(this._typamaticTimer);
			}
			this._typamaticTimer = null;
			this._currentTimeout = this.defaultTimeout;
		},

		_mouseWheeled: function(/*Event*/ evt){
			var scrollAmount = 0;
			if(typeof evt.wheelDelta == 'number'){ // IE
				scrollAmount = evt.wheelDelta;
			}else if (typeof evt.detail == 'number'){ // Mozilla+Firefox
				scrollAmount = -evt.detail;
			}
			if (this.isEnableY){
				if(scrollAmount > 0){
					this._topButtonPressed(evt);
					this._buttonReleased(evt);
				}else if (scrollAmount < 0){
					this._bottomButtonPressed(evt);
					this._buttonReleased(evt);
				}
			} else if (this.isEnableX){
				if(scrollAmount > 0){
					this._rightButtonPressed(evt);
					this._buttonReleased(evt);
				}else if (scrollAmount < 0){
					this._leftButtonPressed(evt);
					this._buttonReleased(evt);
				}
			}
		},

		_discardEvent: function(/*Event*/ evt){
			dojo.event.browser.stopEvent(evt);
		},

		_setFocus: function(){
			if (this.focusNode.focus){
				this.focusNode.focus();
			}
		},

		// This function is called when the template is loaded
		fillInTemplate: function (/*Object*/ args, /*Object*/ frag) 
		{
			var source = this.getFragNodeRef(frag);
			dojo.html.copyStyle(this.domNode, source);
			// the user's style for the widget might include border and padding
			// unfortunately, border isn't supported for inline elements
			// so I get to fake everyone out by setting the border and padding
			// of the outer table cells
			var padding = this.domNode.style.padding;
			if (dojo.lang.isString(padding) && padding != "" && padding != "0px" && padding != "0px 0px 0px 0px"){
				this.topBorderNode.style.padding = 
					this.bottomBorderNode.style.padding = padding;
				this.topBorderNode.style.paddingBottom = "0px";
				this.bottomBorderNode.style.paddingTop = "0px";
				this.rightBorderNode.style.paddingRight = this.domNode.style.paddingRight;
				this.leftBorderNode.style.paddingLeft= this.domNode.style.paddingLeft;
				this.domNode.style.padding = "0px 0px 0px 0px";
			}
			var borderWidth = this.domNode.style.borderWidth;
			if (dojo.lang.isString(borderWidth) && borderWidth != "" && borderWidth != "0px" && borderWidth != "0px 0px 0px 0px"){
				this.topBorderNode.style.borderStyle = 
					this.rightBorderNode.style.borderStyle = 
					this.bottomBorderNode.style.borderStyle = 
					this.leftBorderNode.style.borderStyle = 
						this.domNode.style.borderStyle;
				this.topBorderNode.style.borderColor = 
					this.rightBorderNode.style.borderColor = 
					this.bottomBorderNode.style.borderColor = 
					this.leftBorderNode.style.borderColor = 
						this.domNode.style.borderColor;
				this.topBorderNode.style.borderWidth = 
					this.bottomBorderNode.style.borderWidth = borderWidth;
				this.topBorderNode.style.borderBottomWidth = "0px";
				this.bottomBorderNode.style.borderTopWidth = "0px";
				this.rightBorderNode.style.borderRightWidth = this.domNode.style.borderRightWidth;
				this.leftBorderNode.style.borderLeftWidth = this.domNode.style.borderLeftWidth;
				this.domNode.style.borderWidth = "0px 0px 0px 0px";
			}

			// dojo.debug ("fillInTemplate - className = " + this.domNode.className);

			// setup drag-n-drop for the sliderHandle
			this._handleMove = new dojo.widget._SliderDragMoveSource (this.sliderHandleNode);
			this._handleMove.setParent (this);

			if (this.clickSelect){
				dojo.event.connect (this.constrainingContainerNode, "onmousedown", this, "_onClick");
			} 

			if (this.isEnableX){
				this.setValueX (!isNaN(this.initialValueX) ? this.initialValueX : (!isNaN(this.minimumX) ? this.minimumX : 0));
			}
			if (!this.isEnableX || !this.showButtons){
				this.rightButtonNode.style.width = "1px"; // allow the border to show
				this.rightButtonNode.style.visibility = "hidden";
				this.leftButtonNode.style.width = "1px"; // allow the border to show
				this.leftButtonNode.style.visibility = "hidden";
			}
			if (this.isEnableY){
				this.setValueY (!isNaN(this.initialValueY) ? this.initialValueY : (!isNaN(this.minimumY) ? this.minimumY : 0));
			}
			if (!this.isEnableY || !this.showButtons){
				this.bottomButtonNode.style.width = "1px"; // allow the border to show
				this.bottomButtonNode.style.visibility = "hidden";
				this.topButtonNode.style.width = "1px"; // allow the border to show
				this.topButtonNode.style.visibility = "hidden";
			}
			if(this.focusNode.addEventListener){
				// dojo.event.connect() doesn't seem to work with DOMMouseScroll
				this.focusNode.addEventListener('DOMMouseScroll', dojo.lang.hitch(this, "_mouseWheeled"), false); // Mozilla + Firefox + Netscape
			}
		},

		// move the X value to the closest allowable value
		_snapX: function(/*Number*/ x){
			if (x < 0){ x = 0; }
			else if (x > this._constraintWidth){ x = this._constraintWidth; }
			else {
				var selectedValue = Math.round (x / this._valueSizeX);
				x = Math.round (selectedValue * this._valueSizeX);
			}
			this.sliderHandleNode.style.left = x + "px";
			if (this.flipX){
				this._clipLeft = x + this._clipXdelta;
			} else {
				this._clipRight = x + this._clipXdelta;
			}
			this.progressBackgroundNode.style.clip = "rect("+this._clipTop+"px,"+this._clipRight+"px,"+this._clipBottom+"px,"+this._clipLeft+"px)";
		},

		// compute _valueSizeX & _constraintWidth & default snapValuesX
		_calc_valueSizeX: function (){
			var constrainingCtrBox = dojo.html.getContentBox(this.constrainingContainerNode);
			var sliderHandleBox = dojo.html.getContentBox(this.sliderHandleNode);
			if (isNaN(constrainingCtrBox.width) || isNaN(sliderHandleBox.width) || constrainingCtrBox.width <= 0 || sliderHandleBox.width <= 0){ 
				return false; 
			}

			this._constraintWidth = constrainingCtrBox.width 
				+ dojo.html.getPadding(this.constrainingContainerNode).width
				- sliderHandleBox.width;

			if (this.flipX){
				this._clipLeft = this._clipRight = constrainingCtrBox.width;
			} else {
				this._clipLeft = this._clipRight = 0;
			}
			this._clipXdelta = sliderHandleBox.width >> 1;
			if (!this.isEnableY){
				this._clipTop = 0;
				this._clipBottom = constrainingCtrBox.height;
			}

			if (this._constraintWidth <= 0){ return false; }
			if (this.snapValuesX == 0){
				this.snapValuesX = this._constraintWidth + 1;
			}

			this._valueSizeX = this._constraintWidth / (this.snapValuesX - 1);
			return true;
		},

		// summary
		//	move the handle horizontally to the specified value
		setValueX: function (/*Number*/ value){
			if (0.0 == this._valueSizeX){
				if (this._calc_valueSizeX () == false){
					dojo.lang.setTimeout(this, "setValueX", 100, value);
					return;
				}
			}
			if (isNaN(value)){
				value = 0;
			}
			if (value > this.maximumX){
				value = this.maximumX;
			}
			else if (value < this.minimumX){
				value = this.minimumX;
			}
			var pixelPercent = (value-this.minimumX) / (this.maximumX-this.minimumX);
			if (this.flipX){
				pixelPercent = 1.0 - pixelPercent;
			}
			this._snapX (pixelPercent * this._constraintWidth);
			this.notifyListeners();
		},


		// summary
		//	return the X value that the matches the position of the handle
		getValueX: function (){
			var pixelPercent = dojo.html.getPixelValue (this.sliderHandleNode,"left") / this._constraintWidth;
			if (this.flipX){
				pixelPercent = 1.0 - pixelPercent;
			}
			return Math.round (pixelPercent * (this.snapValuesX-1)) * ((this.maximumX-this.minimumX) / (this.snapValuesX-1)) + this.minimumX;
		},

		// move the Y value to the closest allowable value
		_snapY: function (/*Number*/ y){
			if (y < 0){ y = 0; }
			else if (y > this._constraintHeight){ y = this._constraintHeight; }
			else {
				var selectedValue = Math.round (y / this._valueSizeY);
				y = Math.round (selectedValue * this._valueSizeY);
			}
			this.sliderHandleNode.style.top = y + "px";
			if (this.flipY){
				this._clipTop = y + this._clipYdelta;
			} else {
				this._clipBottom = y + this._clipYdelta;
			}
			this.progressBackgroundNode.style.clip = "rect("+this._clipTop+"px,"+this._clipRight+"px,"+this._clipBottom+"px,"+this._clipLeft+"px)";
		},
		// compute _valueSizeY & _constraintHeight & default snapValuesY
		_calc_valueSizeY: function (){
			var constrainingCtrBox = dojo.html.getContentBox(this.constrainingContainerNode);
			var sliderHandleBox = dojo.html.getContentBox(this.sliderHandleNode);
			if (isNaN(constrainingCtrBox.height) || isNaN(sliderHandleBox.height) || constrainingCtrBox.height <= 0 || sliderHandleBox.height <= 0){ 
				return false; 
			}

			this._constraintHeight = constrainingCtrBox.height
				+ dojo.html.getPadding(this.constrainingContainerNode).height
				- sliderHandleBox.height;

			if (this.flipY){
				this._clipTop = this._clipBottom = constrainingCtrBox.height;
			} else {
				this._clipTop = this._clipBottom = 0;
			}
			this._clipYdelta = sliderHandleBox.height >> 1;
			if (!this.isEnableX){
				this._clipLeft = 0;
				this._clipRight = constrainingCtrBox.width;
			}

			if (this._constraintHeight <= 0){ return false; }
			if (this.snapValuesY == 0){
				this.snapValuesY = this._constraintHeight + 1;
			}

			this._valueSizeY = this._constraintHeight / (this.snapValuesY - 1);
			return true;
		},

		// summary
		//	move the handle vertically to the specified value
		setValueY: function (/*Number*/ value){
			if (0.0 == this._valueSizeY){
				if (this._calc_valueSizeY () == false){
					dojo.lang.setTimeout(this, "setValueY", 100, value);
					return;
				}
			}
			if (isNaN(value)){
				value = 0;
			}
			if (value > this.maximumY){
				value = this.maximumY;
			}
			else if (value < this.minimumY){
				value = this.minimumY;
			}
			var pixelPercent = (value-this.minimumY) / (this.maximumY-this.minimumY);
			if (this.flipY){
				pixelPercent = 1.0 - pixelPercent;
			}
			this._snapY (pixelPercent * this._constraintHeight);
			this.notifyListeners();
		},

		// summary
		//	return the Y value that the matches the position of the handle
		getValueY: function (){
			var pixelPercent = dojo.html.getPixelValue (this.sliderHandleNode,"top") / this._constraintHeight;
			if (this.flipY){
				pixelPercent = 1.0 - pixelPercent;
			}
			return Math.round (pixelPercent * (this.snapValuesY-1)) * ((this.maximumY-this.minimumY) / (this.snapValuesY-1)) + this.minimumY;
		},

		// set the position of the handle
		_onClick: function(/*Event*/ evt){
			if (this._isDragInProgress){
				return;
			}

			var parent = dojo.html.getAbsolutePosition(this.constrainingContainerNode, true, dojo.html.boxSizing.MARGIN_BOX);
			var content = dojo.html.getContentBox(this._handleMove.domNode);			
			if (this.isEnableX){
				var x = evt.pageX - parent.x - (content.width >> 1);
				this._snapX(x);
			}
			if (this.isEnableY){
				var y = evt.pageY - parent.y - (content.height >> 1);
				this._snapY(y);
			}
			this.notifyListeners();
		},

		// summary
		//	method to invoke user's onValueChanged method
		notifyListeners: function(){
			this.onValueChanged(this.getValueX(), this.getValueY());
		},

		// summary
		//	empty method to be overridden by user
		onValueChanged: function(/*Number*/ x, /*Number*/ y){
		}
	}
);



// summary
//	the horizontal slider widget subclass
dojo.widget.defineWidget (
	"dojo.widget.SliderHorizontal",
	dojo.widget.Slider,
	{
		widgetType: "SliderHorizontal",

		isEnableX: true,
		isEnableY: false,
		// Number
		//	sets initialValueX
		initialValue: "",
		// Number
		//	sets snapValuesX
		snapValues: "",
		// Number
		//	sets minimumX
		minimum: "",
		// Number
		//	sets maximumX
		maximum: "",
		// String
		//	sets buttonStyleX
		buttonStyle: "",
		backgroundSize: "height:10px;width:200px;",
		backgroundSrc: dojo.uri.dojoUri("src/widget/templates/images/slider-bg.gif"),
		// Boolean
		//	sets flipX
		flip: false,

		postMixInProperties: function(){
			dojo.widget.SliderHorizontal.superclass.postMixInProperties.apply(this, arguments);
			if (!isNaN(parseFloat(this.initialValue))){
				this.initialValueX = parseFloat(this.initialValue);
			}
			if (!isNaN(parseFloat(this.minimum))){
				this.minimumX = parseFloat(this.minimum);
			}
			if (!isNaN(parseFloat(this.maximum))){
				this.maximumX = parseFloat(this.maximum);
			}
			if (!isNaN(parseInt(this.snapValues))){
				this.snapValuesX = parseInt(this.snapValues);
			}
			if (dojo.lang.isString(this.buttonStyle) && this.buttonStyle != ""){
				this.buttonStyleX = this.buttonStyle;
			}
			if (dojo.lang.isBoolean(this.flip)){
				this.flipX = this.flip;
			}
		},

		notifyListeners: function(){
			this.onValueChanged(this.getValueX());
		},

		// summary
		//	wrapper for getValueX()
		getValue: function (){
			return this.getValueX ();
		},

		// summary
		//	wrapper for setValueX()
		setValue: function (/*Number*/ value){
			this.setValueX (value);
		},

		onValueChanged: function(/*Number*/ value){
		}
	}
);


/* ------------------------------------------------------------------------- */


// summary
//	the vertical slider widget subclass
dojo.widget.defineWidget (
	"dojo.widget.SliderVertical",
	dojo.widget.Slider,
	{
		widgetType: "SliderVertical",

		isEnableX: false,
		isEnableY: true,
		// Number
		//	sets initialValueY
		initialValue: "",
		// Number
		//	sets snapValuesY
		snapValues: "",
		// Number
		//	sets minimumY
		minimum: "",
		// Number
		//	sets maximumY
		maximum: "",
		// String
		//	sets buttonStyleY
		buttonStyle: "",
		backgroundSize: "width:10px;height:200px;",
		backgroundSrc: dojo.uri.dojoUri("src/widget/templates/images/slider-bg-vert.gif"),
		// Boolean
		//	sets flipY
		flip: false,

		postMixInProperties: function(){
			dojo.widget.SliderVertical.superclass.postMixInProperties.apply(this, arguments);
			if (!isNaN(parseFloat(this.initialValue))){
				this.initialValueY = parseFloat(this.initialValue);
			}
			if (!isNaN(parseFloat(this.minimum))){
				this.minimumY = parseFloat(this.minimum);
			}
			if (!isNaN(parseFloat(this.maximum))){
				this.maximumY = parseFloat(this.maximum);
			}
			if (!isNaN(parseInt(this.snapValues))){
				this.snapValuesY = parseInt(this.snapValues);
			}
			if (dojo.lang.isString(this.buttonStyle) && this.buttonStyle != ""){
				this.buttonStyleY = this.buttonStyle;
			}
			if (dojo.lang.isBoolean(this.flip)){
				this.flipY = this.flip;
			}
		},

		notifyListeners: function(){
			this.onValueChanged(this.getValueY());
		},

		// summary
		//	wrapper for getValueY()
		getValue: function (){
			return this.getValueY ();
		},

		// summary
		//	wrapper for setValueY()
		setValue: function (/*Number*/ value){
			this.setValueY (value);
		},

		onValueChanged: function(/*Number*/ value){
		}
	}
);


/* ------------------------------------------------------------------------- */


/**
 * This class extends the HtmlDragMoveSource class to provide
 * features for the slider handle.
 */
dojo.declare (
	"dojo.widget._SliderDragMoveSource",
	dojo.dnd.HtmlDragMoveSource,
{
	slider: null,

	/** Setup the handle for drag
	 *  Extends dojo.dnd.HtmlDragMoveSource by creating a SliderDragMoveSource */
	onDragStart: function(/*Event*/ evt){
		this.slider._isDragInProgress = true;
		var pos = dojo.html.getAbsolutePosition(this.slider.constrainingContainerNode, true, dojo.html.boxSizing.MARGIN_BOX);
		if (this.slider.isEnableX){
			this.slider._minX = pos.x;
		}
		if (this.slider.isEnableY){
			this.slider._minY = pos.y;
		}

		var dragObj = this.createDragMoveObject ();

		this.slider.notifyListeners();
		return dragObj;
	},

	onDragEnd: function(/*Event*/ evt){
		this.slider._isDragInProgress = false;
		this.slider.notifyListeners();
	},

	createDragMoveObject: function (){
		//dojo.debug ("SliderDragMoveSource#createDragMoveObject - " + this.slider);
		var dragObj = new dojo.widget._SliderDragMoveObject (this.dragObject, this.type);
		dragObj.slider = this.slider;

		// this code copied from dojo.dnd.HtmlDragSource#onDragStart
		if (this.dragClass){ 
			dragObj.dragClass = this.dragClass; 
		}

		return dragObj;
	},


	setParent: function (/*Widget*/ slider){
		this.slider = slider;
	}
});


/* ------------------------------------------------------------------------- */


/**
 * This class extends the HtmlDragMoveObject class to provide
 * features for the slider handle.
 */
dojo.declare (
	"dojo.widget._SliderDragMoveObject",
	dojo.dnd.HtmlDragMoveObject,
{
	// reference to dojo.widget.Slider
	slider: null,

	/** Moves the node to follow the mouse.
	 *  Extends functon HtmlDragObject by adding functionality to snap handle
	 *  to a discrete value */
	onDragMove: function(/*Event*/ evt){
		this.updateDragOffset ();

		if (this.slider.isEnableX){
			var x = this.dragOffset.x + evt.pageX - this.slider._minX;
			this.slider._snapX(x);
		}

		if (this.slider.isEnableY){
			var y = this.dragOffset.y + evt.pageY - this.slider._minY;
			this.slider._snapY(y);
		}
		if(this.slider.activeDrag){
			this.slider.notifyListeners();
		}
	}
});

__CPAN_FILE__ src/widget/AnimatedPng.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.AnimatedPng");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

// summary
//	PNGs have great tranparency, but lack animation.
//	This widget lets you point an img tag at an animated gif for graceful degrading,
//	while letting you specify a png containing a grid of cells to animate between.
//
// usage
//	<img dojoType="AnimatedPng"
//		src="images/animatedpng_static.gif"		(for degradation; in case javascript is disabled)
//		aniSrc="images/animatedpng_frames.gif"
//		width="20"
//		height="20"
//		interval="50"
//	/>
//
//	var params = {src: "images/animatedpng_static.gif", aniSrc: "images/animatedpng_frames.gif", width: 20, height: 20, interval: 50};
//	var widget = dojo.widget.createWidget("AnimatedPng", params, document.getElementById("pngContainer"));
//
dojo.widget.defineWidget(
	"dojo.widget.AnimatedPng",
	dojo.widget.HtmlWidget,
	{
		isContainer: false,

		// Integer
		//	width (of each frame) in pixels
		width: 0,
		
		// Integer
		//	height (of each frame) in pixels
		height: 0,
		
		// String
		//	pathname to png file containing frames to be animated (ie, displayed sequentially)
		aniSrc: '',
		
		// Integer
		//	time to display each frame
		interval: 100,

		_blankSrc: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),

		templateString: '<img class="dojoAnimatedPng" />',

		postCreate: function(){
			this.cellWidth = this.width;
			this.cellHeight = this.height;

			var img = new Image();
			var self = this;

			img.onload = function(){ self._initAni(img.width, img.height); };
			img.src = this.aniSrc;
		},

		_initAni: function(w, h){
			this.domNode.src = this._blankSrc;
			this.domNode.width = this.cellWidth;
			this.domNode.height = this.cellHeight;
			this.domNode.style.backgroundImage = 'url('+this.aniSrc+')';
			this.domNode.style.backgroundRepeat = 'no-repeat';

			this.aniCols = Math.floor(w/this.cellWidth);
			this.aniRows = Math.floor(h/this.cellHeight);
			this.aniCells = this.aniCols * this.aniRows;
			this.aniFrame = 0;

			window.setInterval(dojo.lang.hitch(this, '_tick'), this.interval);
		},

		_tick: function(){
			this.aniFrame++;
			if (this.aniFrame == this.aniCells) this.aniFrame = 0;

			var col = this.aniFrame % this.aniCols;
			var row = Math.floor(this.aniFrame / this.aniCols);

			var bx = -1 * col * this.cellWidth;
			var by = -1 * row * this.cellHeight;

			this.domNode.style.backgroundPosition = bx+'px '+by+'px';
		}
	}
);

__CPAN_FILE__ src/widget/TreeDocIconExtension.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeDocIconExtension");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeExtension");

// selector extension to emphase node

dojo.widget.defineWidget(
	"dojo.widget.TreeDocIconExtension",
	[dojo.widget.TreeExtension],
{
	/**
	 * can't unlisten
	 */
	
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TreeDocIcon.css"),

	
	listenTreeEvents: ["afterChangeTree","afterSetFolder","afterUnsetFolder"],
	
	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget },
	
	getnodeDocType: function(node) {
		var nodeDocType = node.getnodeDocType();
		if (!nodeDocType) { // set default type
			nodeDocType = node.isFolder ? "Folder" : "Document";
		}
		return nodeDocType;
	},
	
	setnodeDocTypeClass: function(node) {
		
		var reg = new RegExp("(^|\\s)"+node.tree.classPrefix+"Icon\\w+",'g');			
				
		var clazz = dojo.html.getClass(node.iconNode).replace(reg,'') + ' ' + node.tree.classPrefix+'Icon'+this.getnodeDocType(node);
		dojo.html.setClass(node.iconNode, clazz);		
	},
		
		
	onAfterSetFolder: function(message) {
		//dojo.debug("FOLDER");
		if (message.source.iconNode) {
			// on node-initialize time when folder is set there is no iconNode
			// this case will be processed in treeChange anyway			
			this.setnodeDocTypeClass(message.source);
		}
	},
	
	
	onAfterUnsetFolder: function(message) {
		this.setnodeDocTypeClass(message.source);
	},
		
	
	listenNode: function(node) {
		/**
		 * add node with document type icon to node template and Tree.iconNodeTemplate
		 * it will be set to TreeNode.iconNode on node creation
		 * we do not assign document type yet, its node specific
		 */
		//dojo.debug("listenNode in "+node);
			
		node.contentIconNode = document.createElement("div");
		var clazz = node.tree.classPrefix+"IconContent";
		if (dojo.render.html.ie) {
			clazz = clazz+' '+ node.tree.classPrefix+"IEIconContent";
		}
		dojo.html.setClass(node.contentIconNode, clazz);
		
		node.contentNode.parentNode.replaceChild(node.contentIconNode, node.expandNode);
									  
	  	node.iconNode = document.createElement("div");
		dojo.html.setClass(node.iconNode, node.tree.classPrefix+"Icon"+' '+node.tree.classPrefix+'Icon'+this.getnodeDocType(node));
		
		node.contentIconNode.appendChild(node.expandNode);
		node.contentIconNode.appendChild(node.iconNode);
		
		dojo.dom.removeNode(node.contentNode);
		node.contentIconNode.appendChild(node.contentNode);
		
	
		
		//dojo.html.insertAfter(node.iconNode, node.expandNode);
		
		//dojo.debug("listenNode out "+node);
		
	},
			
	
	onAfterChangeTree: function(message) {
		var _this = this;
		
		//dojo.debug(message.node)
		
		if (!message.oldTree || !this.listenedTrees[message.oldTree.widgetId]) {			
			// moving from old tree to our tree
			this.processDescendants(message.node,
				this.listenNodeFilter,
				this.listenNode
			);
		}
		
	}
	

});

__CPAN_FILE__ src/widget/TreeRPCController.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeRPCController");

dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TreeLoadingController");


dojo.widget.defineWidget("dojo.widget.TreeRPCController", dojo.widget.TreeLoadingController, {
	/**
	 * Make request to server about moving children.
	 *
	 * Request returns "true" if move succeeded,
	 * object with error field if failed
	 *
	 * I can't leave DragObject floating until async request returns, need to return false/true
	 * so making it sync way...
	 *
	 * Also, "loading" icon is not shown until function finishes execution, so no indication for remote request.
	*/
	doMove: function(child, newParent, index){

		//if (newParent.isTreeNode) newParent.markLoading();

		var params = {
			// where from
			child: this.getInfo(child),
			childTree: this.getInfo(child.tree),
			// where to
			newParent: this.getInfo(newParent),
			newParentTree: this.getInfo(newParent.tree),
			newIndex: index
		};

		var success;

		this.runRPC({		
			url: this.getRPCUrl('move'),
			/* I hitch to get this.loadOkHandler */
			load: function(response){
				success = this.doMoveProcessResponse(response, child, newParent, index) ;
			},
			sync: true,
			lock: [child, newParent],
			params: params
		});


		return success;
	},

	doMoveProcessResponse: function(response, child, newParent, index){

		if(!dojo.lang.isUndefined(response.error)){
			this.RPCErrorHandler("server", response.error);
			return false;
		}

		var args = [child, newParent, index];
		return dojo.widget.TreeLoadingController.prototype.doMove.apply(this, args);

	},


	doRemoveNode: function(node, callObj, callFunc){

		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		}

		this.runRPC({
				url: this.getRPCUrl('removeNode'),
				/* I hitch to get this.loadOkHandler */
				load: function(response){
					this.doRemoveNodeProcessResponse(response, node, callObj, callFunc) 
				},
				params: params,
				lock: [node]
		});

	},


	doRemoveNodeProcessResponse: function(response, node, callObj, callFunc){
		if(!dojo.lang.isUndefined(response.error)){
			this.RPCErrorHandler("server", response.error);
			return false;
		}

		if(!response){ return false; }

		if(response == true){
			/* change parent succeeded */
			var args = [ node, callObj, callFunc ];
			dojo.widget.TreeLoadingController.prototype.doRemoveNode.apply(this, args);

			return;
		}else if(dojo.lang.isObject(response)){
			dojo.raise(response.error);
		}else{
			dojo.raise("Invalid response "+response)
		}


	},



	// -----------------------------------------------------------------------------
	//                             Create node stuff
	// -----------------------------------------------------------------------------


	doCreateChild: function(parent, index, output, callObj, callFunc){

			var params = {
				tree: this.getInfo(parent.tree),
				parent: this.getInfo(parent),
				index: index,
				data: output
			}

			this.runRPC({
				url: this.getRPCUrl('createChild'),
				load: function(response) {
					// suggested data is dead, fresh data from server is used
					this.doCreateChildProcessResponse( response, parent, index, callObj, callFunc) 
				},
				params: params,
				lock: [parent]
			});

	},

	doCreateChildProcessResponse: function(response, parent, index, callObj, callFunc){

		if(!dojo.lang.isUndefined(response.error)){
			this.RPCErrorHandler("server",response.error);
			return false;
		}

		if(!dojo.lang.isObject(response)){
			dojo.raise("Invalid result "+response)
		}

		var args = [parent, index, response, callObj, callFunc];
		
		dojo.widget.TreeLoadingController.prototype.doCreateChild.apply(this, args);
	}
});

__CPAN_FILE__ src/widget/TreeRpcControllerV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeRpcControllerV3");

dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TreeLoadingControllerV3");

dojo.widget.defineWidget(
	"dojo.widget.TreeRpcControllerV3",
	dojo.widget.TreeLoadingControllerV3,
{
	// TODO: do something with addChild / setChild, so that RpcController become able
	// to hook on this and report to server

	extraRpcOnEdit: false,
				
	/**
	 * Make request to server about moving children.
	 *
	 * Request returns "true" if move succeeded,
	 * object with error field if failed
	 *
	 * I can't leave DragObject floating until async request returns, need to return false/true
	 * so making it sync way...
	 *
	 * Also, "loading" icon is not shown until function finishes execution, so no indication for remote request.
	*/
	doMove: function(child, newParent, index, sync){

		//if (newParent.isTreeNode) newParent.markLoading();

		
		var params = {
			// where from
			child: this.getInfo(child),
			childTree: this.getInfo(child.tree),
			// where to
			newParent: this.getInfo(newParent),
			newParentTree: this.getInfo(newParent.tree),
			newIndex: index
		};


		var deferred = this.runRpc({		
			url: this.getRpcUrl('move'),
			sync: sync,			
			params: params
		});

		var _this = this;
		var args = arguments;	
		
		//deferred.addCallback(function(res) { dojo.debug("doMove fired "+res); return res});
		
		deferred.addCallback(function() {			
			dojo.widget.TreeBasicControllerV3.prototype.doMove.apply(_this,args);
		});

		
		return deferred;
	},

	// -------------- detach
	
	prepareDetach: function(node, sync) {
		var deferred = this.startProcessing(node);		
		return deferred;
	},
	
	finalizeDetach: function(node) {
		this.finishProcessing(node);
	},

	doDetach: function(node, sync){

		
		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		}

		var deferred = this.runRpc({
			url: this.getRpcUrl('detach'),
			sync: sync,
			params: params			
		});
		
		
		var _this = this;
		var args = arguments;
		
		deferred.addCallback(function() {			
			dojo.widget.TreeBasicControllerV3.prototype.doDetach.apply(_this,args);
		});
		
						
		return deferred;

	},

	// -------------------------- Inline edit node ---------------------	

	/**
	 * send edit start request if needed
	 * useful for server-side locking 
	 */
	requestEditConfirmation: function(node, action, sync) {
		if (!this.extraRpcOnEdit) {			
			return dojo.Deferred.prototype.makeCalled();
		}
	
		//dojo.debug("requestEditConfirmation "+node+" "+action);
		
		var _this = this;
	
		var deferred = this.startProcessing(node);
			
		//dojo.debug("startProcessing "+node);
		
		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		}
		
		deferred.addCallback(function() {
			//dojo.debug("add action on requestEditConfirmation "+action);
			return _this.runRpc({
				url: _this.getRpcUrl(action),
				sync: sync,
				params: params			
			});
		});
		
		
		deferred.addBoth(function(r) {
			//dojo.debug("finish rpc with "+r);
			_this.finishProcessing(node);
			return r;
		});
	
		return deferred;
	},
	
	editLabelSave: function(node, newContent, sync) {
		var deferred = this.startProcessing(node);
						
		var _this = this;
		
		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree),
			newContent: newContent
		}
		
	
		deferred.addCallback(function() {
			return _this.runRpc({
				url: _this.getRpcUrl('editLabelSave'),
				sync: sync,
				params: params			
			});
		});
		
		
		deferred.addBoth(function(r) {
			_this.finishProcessing(node);
			return r;
		});
	
		return deferred;
	},
	
	editLabelStart: function(node, sync) {		
		if (!this.canEditLabel(node)) {
			return false;
		}
		
		var _this = this;
		
		if (!this.editor.isClosed()) {
			//dojo.debug("editLabelStart editor open");
			var deferred = this.editLabelFinish(this.editor.saveOnBlur, sync);
			deferred.addCallback(function() {
				return _this.editLabelStart(node, sync);
			});
			return deferred;
		}
						
		//dojo.debug("editLabelStart closed, request");
		var deferred = this.requestEditConfirmation(node, 'editLabelStart', sync);
		
		deferred.addCallback(function() {
			//dojo.debug("start edit");
			_this.doEditLabelStart(node);
		});
	
		
		return deferred;
	
	},

	editLabelFinish: function(save, sync) {
		var _this = this;
		
		var node = this.editor.node;
		
		var deferred = dojo.Deferred.prototype.makeCalled();
		
		if (!save && !node.isPhantom) {
			deferred = this.requestEditConfirmation(this.editor.node,'editLabelFinishCancel', sync);
		}
		
		if (save) {
			if (node.isPhantom) {
				deferred = this.sendCreateChildRequest(
					node.parent,
					node.getParentIndex(),
					{title:this.editor.getContents()},
					sync
				);
			} else {				
				// this deferred has new information from server
				deferred = this.editLabelSave(node, this.editor.getContents(), sync);
			}
		}
		
		deferred.addCallback(function(server_data) {			
			_this.doEditLabelFinish(save, server_data);
		});
		
		deferred.addErrback(function(r) {
			//dojo.debug("Error occured");
			//dojo.debugShallow(r);
			_this.doEditLabelFinish(false);
			return false;
		});
		
		return deferred;
	},
	
			
	
	/**
	 * TODO: merge server-side info
	 */
	createAndEdit: function(parent, index, sync) {
		var data = {title:parent.tree.defaultChildTitle};
		
		if (!this.canCreateChild(parent, index, data)) {
			return false;
		}
		
		/* close editor first */
		if (!this.editor.isClosed()) {
			//dojo.debug("editLabelStart editor open");
			var deferred = this.editLabelFinish(this.editor.saveOnBlur, sync);
			deferred.addCallback(function() {
				return _this.createAndEdit(parent, index, sync);
			});
			return deferred;
		}
			
		var _this = this;
		
		/* load parent and create child*/
		var deferred = this.prepareCreateChild(parent, index, data, sync);
		
		
		deferred.addCallback(function() {
			var child = _this.makeDefaultNode(parent, index);			
			child.isPhantom = true;
			return child;
		});
		
		
		deferred.addBoth(function(r) {
			_this.finalizeCreateChild(parent, index, data, sync);
			return r;
		});
		
		/* expand parent */
		deferred.addCallback(function(child) {
			var d = _this.exposeCreateChild(parent, index, data, sync);
			d.addCallback(function() { return child });
			return d;
		});
		
		
		deferred.addCallback(function(child) {
			//dojo.debug("start edit");
			_this.doEditLabelStart(child);
			return child;
		});
		
		
		
		return deferred;
	
	},

	prepareDestroyChild: function(node, sync) {
		//dojo.debug(node);
		var deferred = this.startProcessing(node);		
		return deferred;
	},
	
	finalizeDestroyChild: function(node) {
		this.finishProcessing(node);
	},
		

	doDestroyChild: function(node, sync){

		
		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		}

		var deferred = this.runRpc({
			url: this.getRpcUrl('destroyChild'),
			sync: sync,
			params: params			
		});
		
		
		var _this = this;
		var args = arguments;
		
		deferred.addCallback(function() {			
			dojo.widget.TreeBasicControllerV3.prototype.doDestroyChild.apply(_this,args);
		});
		
						
		return deferred;

	},

	// -----------------------------------------------------------------------------
	//                             Create node stuff
	// -----------------------------------------------------------------------------
	sendCreateChildRequest: function(parent, index, data, sync) {
		var params = {
			tree: this.getInfo(parent.tree),
			parent: this.getInfo(parent),
			index: index,
			data: data
		}

		var deferred = this.runRpc({
			url: this.getRpcUrl('createChild'),
			sync: sync,
			params: params
		});
		
		return deferred;
	},
		

	doCreateChild: function(parent, index, data, sync){		
		
		if (dojo.lang.isUndefined(data.title)) {
			data.title = parent.tree.defaultChildTitle;
		}

		var deferred = this.sendCreateChildRequest(parent,index,data,sync);
		
		var _this = this;
		var args = arguments;
		
		
		deferred.addCallback(function(server_data) {
			dojo.lang.mixin(server_data, data); // add my data as less priority
			//dojo.debug("Create ");
			//dojo.debug(server_data);
			return dojo.widget.TreeBasicControllerV3.prototype.doCreateChild.call(_this,parent,index,server_data);
		});
		
						
		return deferred;
	},
	
	// TODO: merge server data into cloned node, like in createChild	
	doClone: function(child, newParent, index, deep, sync) {
		
		var params = {
			child: this.getInfo(child),
			newParent: this.getInfo(newParent),
			index: index,
			deep: deep ? true : false, // undefined -> false
			tree: this.getInfo(child.tree)
		}
		
		
		var deferred = this.runRpc({
			url: this.getRpcUrl('clone'),
			sync: sync,
			params: params
		});
		
		var _this = this;
		var args = arguments;
		
		deferred.addCallback(function() {			
			dojo.widget.TreeBasicControllerV3.prototype.doClone.apply(_this,args);
		});
		
						
		return deferred;	
	}

	
});

__CPAN_FILE__ src/widget/TaskBar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TaskBar");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.FloatingPane");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.event.*");
dojo.require("dojo.html.selection");

// summary
//	Widget used internally by the TaskBar;
//	shows an icon associated w/a floating pane
dojo.widget.defineWidget(
	"dojo.widget.TaskBarItem",
	dojo.widget.HtmlWidget,
{
	// String
	//	path of icon for associated floating pane
	iconSrc: '',
	
	// String
	//	name of associated floating pane
	caption: 'Untitled',

	// String
	//	widget id of associated floating pane
	widgetId: "",

	templatePath: dojo.uri.dojoUri("src/widget/templates/TaskBarItemTemplate.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TaskBar.css"),

	fillInTemplate: function() {
		if (this.iconSrc) {
			var img = document.createElement("img");
			img.src = this.iconSrc;
			this.domNode.appendChild(img);
		}
		this.domNode.appendChild(document.createTextNode(this.caption));
		dojo.html.disableSelection(this.domNode);
	},

	postCreate: function() {
		this.window=dojo.widget.getWidgetById(this.windowId);
		this.window.explodeSrc = this.domNode;
		dojo.event.connect(this.window, "destroy", this, "destroy")
	},

	onClick: function() {
		this.window.toggleDisplay();
	}
});

// summary:
//	Displays an icon for each associated floating pane, like Windows task bar
dojo.widget.defineWidget(
	"dojo.widget.TaskBar",
	dojo.widget.FloatingPane,
	function(){
		this._addChildStack = [];
	},
{
	// TODO: this class extends floating pane merely to get the shadow;
	//	it should extend HtmlWidget and then just call the shadow code directly
	resizable: false,
	titleBarDisplay: "none",

	addChild: function(/*Widget*/ child) {
		// summary: add taskbar item for specified FloatingPane
		// TODO: this should not be called addChild(), as that has another meaning.
		if(!this.containerNode){ 
			this._addChildStack.push(child);
		}else if(this._addChildStack.length > 0){
			var oarr = this._addChildStack;
			this._addChildStack = [];
			dojo.lang.forEach(oarr, this.addChild, this);
		}
		var tbi = dojo.widget.createWidget("TaskBarItem",
			{	windowId: child.widgetId, 
				caption: child.title, 
				iconSrc: child.iconSrc
			});
		dojo.widget.TaskBar.superclass.addChild.call(this,tbi);
	}
});

__CPAN_FILE__ src/widget/TabContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TabContainer");

dojo.require("dojo.lang.func");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.PageContainer");
dojo.require("dojo.event.*");
dojo.require("dojo.html.selection");
dojo.require("dojo.widget.html.layout");

// summary
//	A TabContainer is a container that has multiple panes, but shows only
//	one pane at a time.  There are a set of tabs corresponding to each pane,
//	where each tab has the title (aka label) of the pane, and optionally a close button.
//
//	Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
//	(where <widgetId> is the id of the TabContainer itself.
dojo.widget.defineWidget("dojo.widget.TabContainer", dojo.widget.PageContainer, {

	// String
	//   Defines where tab labels go relative to tab content.
	//   "top", "bottom", "left-h", "right-h"
	labelPosition: "top",
	
	// String
	//   If closebutton=="tab", then every tab gets a close button.
	//   DEPRECATED:  Should just say closable=true on each
	//   pane you want to be closable.
	closeButton: "none",

	templateString: null,	// override setting in PageContainer
	templatePath: dojo.uri.dojoUri("src/widget/templates/TabContainer.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TabContainer.css"),

	// String
	//	initially selected tab (widgetId)
	//	DEPRECATED: use selectedChild instead.
	selectedTab: "",

	postMixInProperties: function() {
		if(this.selectedTab){
			dojo.deprecated("selectedTab deprecated, use selectedChild instead, will be removed in", "0.5");
			this.selectedChild=this.selectedTab;
		}
		if(this.closeButton!="none"){
			dojo.deprecated("closeButton deprecated, use closable='true' on each child instead, will be removed in", "0.5");
		}
		dojo.widget.TabContainer.superclass.postMixInProperties.apply(this, arguments);
	},

	fillInTemplate: function() {
		// create the tab list that will have a tab (a.k.a. tab button) for each tab panel
		this.tablist = dojo.widget.createWidget("TabController",
			{
				id: this.widgetId + "_tablist",
				labelPosition: this.labelPosition,
				doLayout: this.doLayout,
				containerId: this.widgetId
			}, this.tablistNode);
		dojo.widget.TabContainer.superclass.fillInTemplate.apply(this, arguments);
	},

	postCreate: function(args, frag) {	
		dojo.widget.TabContainer.superclass.postCreate.apply(this, arguments);

		// size the container pane to take up the space not used by the tabs themselves
		this.onResized();
	},

	_setupChild: function(tab){
		if(this.closeButton=="tab" || this.closeButton=="pane"){
			// TODO: remove in 0.5
			tab.closable=true;
		}
		dojo.html.addClass(tab.domNode, "dojoTabPane");
		dojo.widget.TabContainer.superclass._setupChild.apply(this, arguments);
	},

	onResized: function(){
		// Summary: Configure the content pane to take up all the space except for where the tabs are
		if(!this.doLayout){ return; }

		// position the labels and the container node
		var labelAlign=this.labelPosition.replace(/-h/,"");
		var children = [
			{domNode: this.tablist.domNode, layoutAlign: labelAlign},
			{domNode: this.containerNode, layoutAlign: "client"}
		];
		dojo.widget.html.layout(this.domNode, children);

		if(this.selectedChildWidget){
			var containerSize = dojo.html.getContentBox(this.containerNode);
			this.selectedChildWidget.resizeTo(containerSize.width, containerSize.height);
		}
	},

	selectTab: function(tab, callingWidget){
		dojo.deprecated("use selectChild() rather than selectTab(), selectTab() will be removed in", "0.5");
		this.selectChild(tab, callingWidget);
	},

	onKey: function(e){
		// summary
		//	Keystroke handling for keystrokes on the tab panel itself (that were bubbled up to me)
		//	Ctrl-up: focus is returned from the pane to the tab button
		//	Alt-del: close tab
		if(e.keyCode == e.KEY_UP_ARROW && e.ctrlKey){
			// set focus to current tab
			var button = this.correspondingTabButton || this.selectedTabWidget.tabButton;
			button.focus();
			dojo.event.browser.stopEvent(e);
		}else if(e.keyCode == e.KEY_DELETE && e.altKey){
			if (this.selectedChildWidget.closable){
				this.closeChild(this.selectedChildWidget);
				dojo.event.browser.stopEvent(e);
			}
		}
	},

	destroy: function(){
		this.tablist.destroy();
		dojo.widget.TabContainer.superclass.destroy.apply(this, arguments);
	}
});

// summary
// 	Set of tabs (the things with labels and a close button, that you click to show a tab panel).
//	Lets the user select the currently shown pane in a TabContainer or PageContainer.
//	TabController also monitors the TabContainer, and whenever a pane is
//	added or deleted updates itself accordingly.
dojo.widget.defineWidget(
    "dojo.widget.TabController",
    dojo.widget.PageController,
	{
		templateString: "<div wairole='tablist' dojoAttachEvent='onKey'></div>",

		// String
		//   Defines where tab labels go relative to tab content.
		//   "top", "bottom", "left-h", "right-h"
		labelPosition: "top",

		doLayout: true,

		// String
		//	Class name to apply to the top dom node
		"class": "",

		// String
		//	the name of the tab widget to create to correspond to each page
		buttonWidget: "TabButton",

		postMixInProperties: function() {
			if(!this["class"]){
				this["class"] = "dojoTabLabels-" + this.labelPosition + (this.doLayout ? "" : " dojoTabNoLayout");
			}
			dojo.widget.TabController.superclass.postMixInProperties.apply(this, arguments);
		}
	}
);

// summary
//	A tab (the thing you click to select a pane).
//	Contains the title (aka label) of the pane, and optionally a close-button to destroy the pane.
//	This is an internal widget and should not be instantiated directly.
dojo.widget.defineWidget("dojo.widget.TabButton", dojo.widget.PageButton,
{
	templateString: "<div class='dojoTab' dojoAttachEvent='onClick'>"
						+"<div dojoAttachPoint='innerDiv'>"
							+"<span dojoAttachPoint='titleNode' tabIndex='-1' waiRole='tab'>${this.label}</span>"
							+"<span dojoAttachPoint='closeButtonNode' class='close closeImage' style='${this.closeButtonStyle}'"
							+"    dojoAttachEvent='onMouseOver:onCloseButtonMouseOver; onMouseOut:onCloseButtonMouseOut; onClick:onCloseButtonClick'></span>"
						+"</div>"
					+"</div>",

	postMixInProperties: function(){
		this.closeButtonStyle = this.closeButton ? "" : "display: none";
		dojo.widget.TabButton.superclass.postMixInProperties.apply(this, arguments);
	},

	fillInTemplate: function(){
		dojo.html.disableSelection(this.titleNode);
		dojo.widget.TabButton.superclass.fillInTemplate.apply(this, arguments);
	}
});


// summary
//	Tab for display in high-contrast mode (where background images don't show up).
//	This is an internal widget and shouldn't be instantiated directly.
dojo.widget.defineWidget(
	"dojo.widget.a11y.TabButton",
	dojo.widget.TabButton,
	{
		imgPath: dojo.uri.dojoUri("src/widget/templates/images/tab_close.gif"),
		
		templateString: "<div class='dojoTab' dojoAttachEvent='onClick;onKey'>"
							+"<div dojoAttachPoint='innerDiv'>"
								+"<span dojoAttachPoint='titleNode' tabIndex='-1' waiRole='tab'>${this.label}</span>"
								+"<img class='close' src='${this.imgPath}' alt='[x]' style='${this.closeButtonStyle}'"
								+"    dojoAttachEvent='onClick:onCloseButtonClick'>"
							+"</div>"
						+"</div>"
	}
);



__CPAN_FILE__ src/widget/TitlePane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TitlePane");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.html.style");
dojo.require("dojo.lfx.*");

dojo.widget.defineWidget(
	"dojo.widget.TitlePane",
	dojo.widget.ContentPane,
{
	labelNode: "",
	labelNodeClass: "",
	containerNodeClass: "",
	label: "",
	
	open: true,
	templatePath: dojo.uri.dojoUri("src/widget/templates/TitlePane.html"),

	postCreate: function() {
		if (this.label) {
			this.labelNode.appendChild(document.createTextNode(this.label));
		}

		if (this.labelNodeClass) {
			dojo.html.addClass(this.labelNode, this.labelNodeClass);
		}	

		if (this.containerNodeClass) {
			dojo.html.addClass(this.containerNode, this.containerNodeClass);
		}	

		if (!this.open) {
			dojo.html.hide(this.containerNode);
		}
		dojo.widget.TitlePane.superclass.postCreate.apply(this, arguments);
	},

	onLabelClick: function() {
		if (this.open) {
			dojo.lfx.wipeOut(this.containerNode, 250).play();
			this.open=false;
		} else {
			dojo.lfx.wipeIn(this.containerNode, 250).play();
			this.open=true;
		}
	},

	setLabel: function(label) {
		this.labelNode.innerHTML=label;
	}
});

__CPAN_FILE__ src/widget/CurrencyTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.CurrencyTextbox");

dojo.require("dojo.widget.IntegerTextbox");
dojo.require("dojo.validate.common");

/*
  ****** CurrencyTextbox ******

  A subclass that extends IntegerTextbox.
  Over-rides isValid/isInRange to test if input denotes a monetary value .
  Has 5 new properties that can be specified as attributes in the markup.

  @attr fractional      The decimal places (e.g. for cents).  Can be true or false, optional if omitted.
  @attr symbol     A currency symbol such as Yen "???", Pound "???", or the Euro "???". Default is "$".
  @attr separator  Default is "," instead of no separator as in IntegerTextbox.
  @attr min  Minimum signed value.  Default is -Infinity
  @attr max  Maximum signed value.  Default is +Infinity
*/
dojo.widget.defineWidget(
	"dojo.widget.CurrencyTextbox",
	dojo.widget.IntegerTextbox,
	{
		mixInProperties: function(localProperties, frag){
			// First initialize properties in super-class.
			dojo.widget.CurrencyTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.fractional){
				this.flags.fractional = (localProperties.fractional == "true");
			}else if(localProperties.cents){
				dojo.deprecated("dojo.widget.IntegerTextbox", "use fractional attr instead of cents", "0.5");
				this.flags.fractional = (localProperties.cents == "true");
			}
			if(localProperties.symbol){
				this.flags.symbol = localProperties.symbol;
			}
			if(localProperties.min){ 
				this.flags.min = parseFloat(localProperties.min);
			}
			if(localProperties.max){ 
				this.flags.max = parseFloat(localProperties.max);
			}
		},

		// Over-ride for currency validation
		isValid: function(){
			return dojo.validate.isCurrency(this.textbox.value, this.flags);
		},
		isInRange: function(){
			return dojo.validate.isInRange(this.textbox.value, this.flags);
		}
	}
);

__CPAN_FILE__ src/widget/Clock.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Clock");

dojo.require("dojo.widget.*");
dojo.require("dojo.gfx.*");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.timing.Timer");

dojo.widget.defineWidget(
	"dojo.widget.Clock",
	dojo.widget.HtmlWidget,
	function(){
		var self=this;
		this.timeZoneOffset=0;	//	this is fun.
		this.label="";		//	optional label.
		
		this.date=new Date();
		
		this.handColor="#788598";
		this.handStroke="#6f7b8c";
	//	this.secondHandColor="#c90405";
		this.secondHandColor=[201, 4, 5, 0.8];
		this.topLabelColor="#efefef";
		this.labelColor="#fff";

		//	timer
		this.timer = new dojo.lang.timing.Timer(1000);

		//	shapes
		this.center={ x:75, y:75 };
		this.hands={
			hour:null,
			minute:null,
			second:null
		};
		this.shadows={
			hour:{ shadow:null, shift:{ dx:2, dy:2} },
			minute:{ shadow:null, shift:{ dx:2, dy:3} },
			second:{ shadow:null, shift:{ dx:4, dy:4} }
		};
		this.image = dojo.uri.dojoUri("src/widget/templates/images/clock.png");
		this.surface=null;
		this.labelNode=null;
		this.topLabelNode=null;

		this.draw=function(){
			self.date=new Date();
			var h=(self.date.getHours()+self.timeZoneOffset) % 12;
			var m=self.date.getMinutes();
			var s=self.date.getSeconds();

			self.placeHour(h, m, s);
			self.placeMinute(m, s);
			self.placeSecond(s);

			self.topLabelNode.innerHTML=((self.date.getHours()+self.timeZoneOffset)>11)?"PM":"AM";
		};

		this.timer.onTick=self.draw;
	},
	{
		set:function(/* Date */dt){
			this.date=dt;
			if(!this.timer.isRunning){
				this.draw();
			}
		},
		start:function(){ this.timer.start(); },
		stop:function(){ this.timer.stop(); },

		_initPoly:function(parent, points){
			var path = parent.createPath();
			var first = true;
			dojo.lang.forEach(points, function(c){
				if(first){
					path.moveTo(c.x, c.y);
					first=false;
				} else {
					path.lineTo(c.x, c.y);
				}
			});
			return path;
		},
		_placeHand:function(shape, angle, shift){
			var move = { dx:this.center.x + (shift?shift.dx:0), dy:this.center.y+(shift?shift.dy:0) };
			return shape.setTransform([move, dojo.gfx.matrix.rotateg(-angle)]);
		},
		placeHour:function(h, m, s){
			var angle=30 *(h + m/60 + s/3600);
			this._placeHand(this.hands.hour, angle);
			this._placeHand(this.shadows.hour.shadow, angle, this.shadows.hour.shift);
		},
		placeMinute:function(m, s){
			var angle=6 * (m + s/60);
			this._placeHand(this.hands.minute, angle);
			this._placeHand(this.shadows.minute.shadow, angle, this.shadows.minute.shift);
		},
		placeSecond:function(s){
			var angle=6 * s;
			this._placeHand(this.hands.second, angle);
			this._placeHand(this.shadows.second.shadow, angle, this.shadows.second.shift);
		},
		
		init:function(){
			//	start by setting up the domNode
			if(this.domNode.style.position != "absolute"){
				this.domNode.style.position = "relative";
			}

			//	clean out any children
			while(this.domNode.childNodes.length>0){
				this.domNode.removeChild(this.domNode.childNodes[0]);
			}
			
			//	set ourselves up.
			this.domNode.style.width="150px";
			this.domNode.style.height="150px";

			this.surface=dojo.gfx.createSurface(this.domNode, 150, 150);
			this.surface.createRect({width: 150, height: 150});
			this.surface.createImage({width: 150, height: 150, src: this.image+""});
			
			var hP=[ {x: -3, y: -4}, {x: 3, y: -4}, {x: 1, y: -27}, { x:-1, y:-27}, {x: -3, y: -4} ];
			var mP=[ {x: -3, y: -4}, {x: 3, y: -4}, {x: 1, y: -38}, {x:-1, y:-38}, {x: -3, y: -4} ];
			var sP=[ {x: -2, y: -2}, {x: 2, y: -2}, {x: 1, y: -45}, {x: -1, y: -45}, {x: -2, y: -2} ];
			
			this.shadows.hour.shadow = this._initPoly(this.surface, hP)
				.setFill([0, 0, 0, 0.1]);
			this.hands.hour = this._initPoly(this.surface, hP)
				.setStroke({color: this.handStroke, width:1 })
				.setFill({ 
					type:"linear", 
					x1:0, y1:0, x2:0, y2:-27, 
					colors:[{offset:0, color:"#fff"}, {offset:0.33, color:this.handColor}]
				});
			this.shadows.minute.shadow = this._initPoly(this.surface, mP)
				.setFill([0, 0, 0, 0.1]);
			this.hands.minute = this._initPoly(this.surface, mP)
				.setStroke({color: this.handStroke, width:1 })
				.setFill({ 
					type:"linear", 
					x1:0, y1:0, x2:0, y2:-38, 
					colors:[{offset:0, color:"#fff"}, {offset:0.33, color:this.handColor}]
				});

			this.surface.createCircle({r: 6})
				.setStroke({color: this.handStroke, width:2 })
				.setFill("#fff")
				.setTransform({dx: 75, dy: 75});

			this.shadows.second.shadow = this._initPoly(this.surface, sP)
				.setFill([0, 0, 0, 0.1]);
			this.hands.second = this._initPoly(this.surface, sP)
				.setFill(this.secondHandColor);

			//	clock centers, doesn't move.
			this.surface.createCircle({r: 4})
				.setFill(this.secondHandColor)
				.setTransform({dx: 75, dy: 75});

			//	labels
			this.topLabelNode=document.createElement("div");
			with(this.topLabelNode.style){
				position="absolute";
				top="3px";
				left="0px";
				color=this.topLabelColor;
				textAlign="center";
				width="150px";
				fontFamily="sans-serif";
				fontSize="11px";
				textTransform="uppercase";
				fontWeight="bold";
			}
			this.topLabelNode.innerHTML=((this.date.getHours()+this.timeZoneOffset)>11)?"PM":"AM";
			this.domNode.appendChild(this.topLabelNode);

			this.labelNode=document.createElement("div");
			with(this.labelNode.style){
				position="absolute";
				top="134px";
				left="0px";
				color=this.labelColor;
				textAlign="center";
				width="150px";
				fontFamily="sans-serif";
				fontSize="10px";
				textTransform="uppercase";
				fontWeight="bold";
			}
			this.labelNode.innerHTML=this.label||"&nbsp;";
			this.domNode.appendChild(this.labelNode);
			
			this.draw();
		},
		postCreate:function(){
			this.init();
			this.start();
		}
	}
);

__CPAN_FILE__ src/widget/TreeBasicControllerV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeBasicControllerV3");

dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TreeCommon");
dojo.require("dojo.widget.TreeNodeV3");
dojo.require("dojo.widget.TreeV3");

dojo.widget.defineWidget(
	"dojo.widget.TreeBasicControllerV3",
	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
	function(){
		this.listenedTrees = {};
	},
{
	// TODO: do something with addChild / setChild, so that RpcController become able
	// to hook on this and report to server
	
	// TODO: make sure keyboard control stuff works when node is moved between trees
	// node should be unfocus()'ed when it its ancestor is moved and tree,lastFocus - cleared

	/**
	 * TreeCommon.listenTree will attach listeners to these events
	 *
	 * The logic behind the naming:
	 * 1. (after|before)
	 * 2. if an event refers to tree, then add "Tree"
	 * 3. add action
	 */
	listenTreeEvents: ["afterSetFolder", "afterTreeCreate", "beforeTreeDestroy"],
	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget},	
		
		
	editor: null,

	
	initialize: function(args) {
		if (args.editor) {
			this.editor = dojo.widget.byId(args.editor);
			this.editor.controller = this;
		}
		
	},
		
	
	getInfo: function(elem) {
		return elem.getInfo();
	},

	onBeforeTreeDestroy: function(message) {
                this.unlistenTree(message.source);
	},

	onAfterSetFolder: function(message) {
		
		//dojo.profile.start("onTreeChange");
        
		if (message.source.expandLevel > 0) {
			this.expandToLevel(message.source, message.source.expandLevel);				
		}
		if (message.source.loadLevel > 0) {
			this.loadToLevel(message.source, message.source.loadLevel);				
		}
			
		
		//dojo.profile.end("onTreeChange");
	},
	

	// down arrow
	_focusNextVisible: function(nodeWidget) {
		
		// if this is an expanded folder, get the first child
		if (nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.children.length > 0) {
			returnWidget = nodeWidget.children[0];			
		} else {
			// find a parent node with a sibling
			while (nodeWidget.isTreeNode && nodeWidget.isLastChild()) {
				nodeWidget = nodeWidget.parent;
			}
			
			if (nodeWidget.isTreeNode) {
				var returnWidget = nodeWidget.parent.children[nodeWidget.getParentIndex()+1];				
			}
			
		}
				
		if (returnWidget && returnWidget.isTreeNode) {
			this._focusLabel(returnWidget);
			return returnWidget;
		}
		
	},
	
	// up arrow
	_focusPreviousVisible: function(nodeWidget) {
		var returnWidget = nodeWidget;
		
		// if younger siblings		
		if (!nodeWidget.isFirstChild()) {
			var previousSibling = nodeWidget.parent.children[nodeWidget.getParentIndex()-1]

			nodeWidget = previousSibling;
			// if the previous nodeWidget is expanded, dive in deep
			while (nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.children.length > 0) {
				returnWidget = nodeWidget;
				// move to the last child
				nodeWidget = nodeWidget.children[nodeWidget.children.length-1];
			}
		} else {
			// if this is the first child, return the parent
			nodeWidget = nodeWidget.parent;
		}
		
		if (nodeWidget && nodeWidget.isTreeNode) {
			returnWidget = nodeWidget;
		}
		
		if (returnWidget && returnWidget.isTreeNode) {
			this._focusLabel(returnWidget);
			return returnWidget;
		}
		
	},
	
	// right arrow
	_focusZoomIn: function(nodeWidget) {
		var returnWidget = nodeWidget;
		
		// if not expanded, expand, else move to 1st child
		if (nodeWidget.isFolder && !nodeWidget.isExpanded) {
			this.expand(nodeWidget);
		}else if (nodeWidget.children.length > 0) {
			nodeWidget = nodeWidget.children[0];
		}
		
		if (nodeWidget && nodeWidget.isTreeNode) {
			returnWidget = nodeWidget;
		}
		
		if (returnWidget && returnWidget.isTreeNode) {
			this._focusLabel(returnWidget);
			return returnWidget;
		}
		
	},
	
	// left arrow
	_focusZoomOut: function(node) {
		
		var returnWidget = node;
		
		// if not expanded, expand, else move to 1st child
		if (node.isFolder && node.isExpanded) {
			this.collapse(node);
		} else {
			node = node.parent;
		}
		if (node && node.isTreeNode) {
			returnWidget = node;
		}
		
		if (returnWidget && returnWidget.isTreeNode) {
			this._focusLabel(returnWidget);
			return returnWidget;
		}
		
	},
	
	onFocusNode: function(e) {
		var node = this.domElement2TreeNode(e.target);
		
		if (node) {
			node.viewFocus();			
			dojo.event.browser.stopEvent(e);
		}
	},
	
	onBlurNode: function(e) {
		var node = this.domElement2TreeNode(e.target);
		
		if (!node) {
			return;
		}
		
		var labelNode = node.labelNode;
		
		labelNode.setAttribute("tabIndex", "-1");
		node.viewUnfocus();		
		dojo.event.browser.stopEvent(e);
		
		// this could have been set to -1 by the shift+TAB processing
		node.tree.domNode.setAttribute("tabIndex", "0");
		
	},
	
	
	_focusLabel: function(node) {
		//dojo.debug((new Error()).stack)		
		var lastFocused = node.tree.lastFocused;
		var labelNode;
		
		if (lastFocused && lastFocused.labelNode) {
			labelNode = lastFocused.labelNode;
			// help Opera out with blur events
			dojo.event.disconnect(labelNode, "onblur", this, "onBlurNode");
			labelNode.setAttribute("tabIndex", "-1");
			dojo.html.removeClass(labelNode, "TreeLabelFocused");
		}
		
		// set tabIndex so that the tab key can find this node
		labelNode = node.labelNode;
		labelNode.setAttribute("tabIndex", "0");
		node.tree.lastFocused = node;
		
		// add an outline - this helps opera a lot
		dojo.html.addClass(labelNode, "TreeLabelFocused");
		dojo.event.connectOnce(labelNode, "onblur", this, "onBlurNode");
		// prevent the domNode from seeing the focus event
		dojo.event.connectOnce(labelNode, "onfocus", this, "onFocusNode");
		// set focus so that the label wil be voiced using screen readers
		labelNode.focus();
			
	},
	
	onKey: function(e) {
		if (!e.key || e.ctrkKey || e.altKey) { return; }
		// pretend the key was directed toward the current focused node (helps opera out)
		
		var nodeWidget = this.domElement2TreeNode(e.target);
		if (!nodeWidget) {
			return;
		}
		
		var treeWidget = nodeWidget.tree;
		
		if (treeWidget.lastFocused && treeWidget.lastFocused.labelNode) {
			nodeWidget = treeWidget.lastFocused;
		}
		
		switch(e.key) {
			case e.KEY_TAB:
				if (e.shiftKey) {
					// we're moving backwards so don't tab to the domNode
					// it'll be added back in onBlurNode
					treeWidget.domNode.setAttribute("tabIndex", "-1");
				}
				break;
			case e.KEY_RIGHT_ARROW:
				this._focusZoomIn(nodeWidget);
				dojo.event.browser.stopEvent(e);
				break;
			case e.KEY_LEFT_ARROW:
				this._focusZoomOut(nodeWidget);
				dojo.event.browser.stopEvent(e);
				break;
			case e.KEY_UP_ARROW:
				this._focusPreviousVisible(nodeWidget);
				dojo.event.browser.stopEvent(e);
				break;
			case e.KEY_DOWN_ARROW:
				this._focusNextVisible(nodeWidget);
				dojo.event.browser.stopEvent(e);
				break;
		}
	},
	
	
	onFocusTree: function(e) {
		if (!e.currentTarget) { return; }
		try {
			var treeWidget = this.getWidgetByNode(e.currentTarget);
			if (!treeWidget || !treeWidget.isTree) { return; }
			// on first focus, choose the root node
			var nodeWidget = this.getWidgetByNode(treeWidget.domNode.firstChild);
			if (nodeWidget && nodeWidget.isTreeNode) {
				if (treeWidget.lastFocused && treeWidget.lastFocused.isTreeNode) { // onClick could have chosen a non-root node
					nodeWidget = treeWidget.lastFocused;
				}
				this._focusLabel(nodeWidget);
			}
		}
		catch(e) {}
	},

	// perform actions-initializers for tree
	onAfterTreeCreate: function(message) {
		var tree = message.source;
		dojo.event.browser.addListener(tree.domNode, "onKey", dojo.lang.hitch(this, this.onKey));
		dojo.event.browser.addListener(tree.domNode, "onmousedown", dojo.lang.hitch(this, this.onTreeMouseDown));
		dojo.event.browser.addListener(tree.domNode, "onclick", dojo.lang.hitch(this, this.onTreeClick));
		dojo.event.browser.addListener(tree.domNode, "onfocus", dojo.lang.hitch(this, this.onFocusTree));
		tree.domNode.setAttribute("tabIndex", "0");
		
		if (tree.expandLevel) {								
			this.expandToLevel(tree, tree.expandLevel)
		}
		if (tree.loadLevel) {
			this.loadToLevel(tree, tree.loadLevel);
		}
	},

    onTreeMouseDown: function(e) {
    },

	onTreeClick: function(e){
		//dojo.profile.start("onTreeClick");
		
		var domElement = e.target;
		//dojo.debug('click')
		// find node
        var node = this.domElement2TreeNode(domElement);		
		if (!node || !node.isTreeNode) {
			return;
		}
		
		
		var checkExpandClick = function(el) {
			return el === node.expandNode;
		}
		
		if (this.checkPathCondition(domElement, checkExpandClick)) {
			this.processExpandClick(node);			
		}
		
		this._focusLabel(node);
		
		//dojo.profile.end("onTreeClick");
		
	},
	
	processExpandClick: function(node){
		
		//dojo.profile.start("processExpandClick");
		
		if (node.isExpanded){
			this.collapse(node);
		} else {
			this.expand(node);
		}
		
		//dojo.profile.end("processExpandClick");
	},
		
	
	
	/**
	 * time between expand calls for batch operations
	 * @see expandToLevel
	 */
	batchExpandTimeout: 20,
	
	
	expandAll: function(nodeOrTree) {		
		return this.expandToLevel(nodeOrTree, Number.POSITIVE_INFINITY);
		
	},
	
	
	collapseAll: function(nodeOrTree) {
		var _this = this;
		
		var filter = function(elem) {
			return (elem instanceof dojo.widget.Widget) && elem.isFolder && elem.isExpanded;
		}
		
		if (nodeOrTree.isTreeNode) {		
			this.processDescendants(nodeOrTree, filter, this.collapse);
		} else if (nodeOrTree.isTree) {
			dojo.lang.forEach(nodeOrTree.children,function(c) { _this.processDescendants(c, filter, _this.collapse) });
		}
	},
	
	/**
	 * expand tree to specific node
	 */
	expandToNode: function(node) {
		n = node.parent
		s = []
		while (!n.isExpanded) {
			s.push(n)
			n = n.parent
		}
				
		dojo.lang.forEach(s, function(n) { n.expand() })
	},
		
	/**
	 * walk a node in time, forward order, with pauses between expansions
	 */
	expandToLevel: function(nodeOrTree, level) {
		dojo.require("dojo.widget.TreeTimeoutIterator");
		
		var _this = this;
		var filterFunc = function(elem) {
			var res = elem.isFolder || elem.children && elem.children.length;
			//dojo.debug("Filter "+elem+ " result:"+res);
			return res;
		};
		var callFunc = function(node, iterator) {			
			 _this.expand(node, true);
			 iterator.forward();
		}
			
		var iterator = new dojo.widget.TreeTimeoutIterator(nodeOrTree, callFunc, this);
		iterator.setFilter(filterFunc);
		
		
		iterator.timeout = this.batchExpandTimeout;
		
		//dojo.debug("here "+nodeOrTree+" level "+level);
		
		iterator.setMaxLevel(nodeOrTree.isTreeNode ? level-1 : level);
		
		
		return iterator.start(nodeOrTree.isTreeNode);
	},
	

	getWidgetByNode: function(node) {
		var widgetId;
		var newNode = node;
		while (! (widgetId = newNode.widgetId) ) {
			newNode = newNode.parentNode;
			if (newNode == null) { break; }
		}
		if (widgetId) { return dojo.widget.byId(widgetId); }
		else if (node == null) { return null; }
		else{ return dojo.widget.manager.byNode(node); }
	},



	/**
	 * callout activated even if node is expanded already
	 */
	expand: function(node) {
		
		//dojo.profile.start("expand");
		
		//dojo.debug("Expand "+node.isFolder);
		
		if (node.isFolder) {			
			node.expand(); // skip trees or non-folders
		}		
		
		//dojo.profile.end("expand");
				
	},

	/**
	 * safe to call on tree and non-folder
	 */
	collapse: function(node) {
		if (node.isFolder) {
			node.collapse();
		}
	},
	
	
	// -------------------------- TODO: Inline edit node ---------------------
	canEditLabel: function(node) {
		if (node.actionIsDisabledNow(node.actions.EDIT)) return false;

		return true;
	},
	
		
	editLabelStart: function(node) {		
		if (!this.canEditLabel(node)) {
			return false;
		}
		
		if (!this.editor.isClosed()) {
			//dojo.debug("editLabelStart editor open");
			this.editLabelFinish(this.editor.saveOnBlur);			
		}
				
		this.doEditLabelStart(node);
		
	
	},
	
	
	editLabelFinish: function(save) {
		this.doEditLabelFinish(save);		
	},
	
	
	doEditLabelStart: function(node) {
		if (!this.editor) {
			dojo.raise(this.widgetType+": no editor specified");
		}
		
		//dojo.debug("editLabelStart editor open "+node);
		
		this.editor.open(node);		
	},
	
	doEditLabelFinish: function(save, server_data) {
		//dojo.debug("Finish "+save);
		//dojo.debug((new Error()).stack)
		if (!this.editor) {
			dojo.raise(this.widgetType+": no editor specified");
		}

		var node = this.editor.node;	
		var editorTitle = this.editor.getContents();
		
		this.editor.close(save);

		if (save) {
			var data = {title:editorTitle};
			
			if (server_data) { // may be undefined
				dojo.lang.mixin(data, server_data);
			}
			
			
			if (node.isPhantom) {			
				// I can't just set node phantom's title, because widgetId/objectId/widgetName...
				// may be provided by server
				var parent = node.parent;
				var index = node.getParentIndex();				
				node.destroy();
				// new node was added!
				dojo.widget.TreeBasicControllerV3.prototype.doCreateChild.call(this, parent, index, data);
			} else {
				var title = server_data && server_data.title ? server_data.title : editorTitle;
				// use special method to make sure everything updated and event sent
				node.setTitle(title); 
			}
		} else {
			//dojo.debug("Kill phantom on cancel");
			if (node.isPhantom) {
				node.destroy();
			}
		}
	},
	
	
		
	makeDefaultNode: function(parent, index) {
		var data = {title:parent.tree.defaultChildTitle};
		return dojo.widget.TreeBasicControllerV3.prototype.doCreateChild.call(this,parent,index,data);
	},
	
	/**
	 * check that something is possible
	 * run maker to do it
	 * run exposer to expose result to visitor immediatelly
	 *   exposer does not affect result
	 */
	runStages: function(check, prepare, make, finalize, expose, args) {
		
		if (check && !check.apply(this, args)) {
			return false;
		}
		
		if (prepare && !prepare.apply(this, args)) {
			return false;
		}
		
		var result = make.apply(this, args);
		
		
		if (finalize) {
			finalize.apply(this,args);			
		}
			
		if (!result) {
			return result;
		}
		
			
		if (expose) {
			expose.apply(this, args);
		}
		
		return result;
	}
});


// create and edit
dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
		
	createAndEdit: function(parent, index) {
		var data = {title:parent.tree.defaultChildTitle};
		
		if (!this.canCreateChild(parent, index, data)) {
			return false;
		}
		
		var child = this.doCreateChild(parent, index, data);
		if (!child) return false;
		this.exposeCreateChild(parent, index, data);
		
		child.isPhantom = true;
		
		if (!this.editor.isClosed()) {
			//dojo.debug("editLabelStart editor open");
			this.editLabelFinish(this.editor.saveOnBlur);			
		}
		
		
				
		this.doEditLabelStart(child);		
	
	}
	
});


// =============================== clone ============================
dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
	
	canClone: function(child, newParent, index, deep){
		return true;
	},
	
	
	clone: function(child, newParent, index, deep) {
		return this.runStages(
			this.canClone, this.prepareClone, this.doClone, this.finalizeClone, this.exposeClone, arguments
		);			
	},

	exposeClone: function(child, newParent) {
		if (newParent.isTreeNode) {
			this.expand(newParent);
		}
	},

	doClone: function(child, newParent, index, deep) {
		//dojo.debug("Clone "+child);
		var cloned = child.clone(deep);
		newParent.addChild(cloned, index);
				
		return cloned;
	}
	

});

// =============================== detach ============================

dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
	canDetach: function(child) {
		if (child.actionIsDisabledNow(child.actions.DETACH)) {
			return false;
		}

		return true;
	},


	detach: function(node) {
		return this.runStages(
			this.canDetach, this.prepareDetach, this.doDetach, this.finalizeDetach, this.exposeDetach, arguments
		);			
	},


	doDetach: function(node, callObj, callFunc) {
		node.detach();
	}
	
});


// =============================== destroy ============================
dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {

	canDestroyChild: function(child) {
		
		if (child.parent && !this.canDetach(child)) {
			return false;
		}
		return true;
	},


	destroyChild: function(node) {
		return this.runStages(
			this.canDestroyChild, this.prepareDestroyChild, this.doDestroyChild, this.finalizeDestroyChild, this.exposeDestroyChild, arguments
		);			
	},


	doDestroyChild: function(node) {
		node.destroy();
	}
	
});



// =============================== move ============================

dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {

	/**
	 * check for non-treenodes
	 */
	canMoveNotANode: function(child, parent) {
		if (child.treeCanMove) {
			return child.treeCanMove(parent);
		}
		
		return true;
	},

	/**
	 * Checks whether it is ok to change parent of child to newParent
	 * May incur type checks etc
	 *
	 * It should check only hierarchical possibility w/o index, etc
	 * because in onDragOver event for Between Dnd mode we can't calculate index at once on onDragOVer.
	 * index changes as client moves mouse up-down over the node
	 */
	canMove: function(child, newParent){
		if (!child.isTreeNode) {
			return this.canMoveNotANode(child, newParent);
		}
						
		if (child.actionIsDisabledNow(child.actions.MOVE)) {
			return false;
		}

		// if we move under same parent then no matter if ADDCHILD disabled for him
		// but if we move to NEW parent then check if action is disabled for him
		// also covers case for newParent being a non-folder in strict mode etc
		if (child.parent !== newParent && newParent.actionIsDisabledNow(newParent.actions.ADDCHILD)) {
			return false;
		}

		// Can't move parent under child. check whether new parent is child of "child".
		var node = newParent;
		while(node.isTreeNode) {
			//dojo.debugShallow(node.title)
			if (node === child) {
				// parent of newParent is child
				return false;
			}
			node = node.parent;
		}

		return true;
	},


	move: function(child, newParent, index/*,...*/) {
		return this.runStages(this.canMove, this.prepareMove, this.doMove, this.finalizeMove, this.exposeMove, arguments);			
	},

	doMove: function(child, newParent, index) {
		//dojo.debug("MOVE "+child);
		child.tree.move(child, newParent, index);

		return true;
	},
	
	exposeMove: function(child, newParent) {		
		if (newParent.isTreeNode) {
			this.expand(newParent);
		}
	}
		

});

dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {

	// -----------------------------------------------------------------------------
	//                             Create node stuff
	// -----------------------------------------------------------------------------


	canCreateChild: function(parent, index, data) {
		if (parent.actionIsDisabledNow(parent.actions.ADDCHILD)) {
			return false;
		}

		return true;
	},


	/* send data to server and add child from server */
	/* data may contain an almost ready child, or anything else, suggested to server */
	/*in Rpc controllers server responds with child data to be inserted */
	createChild: function(parent, index, data) {
		return this.runStages(this.canCreateChild, this.prepareCreateChild, this.doCreateChild, this.finalizeCreateChild, this.exposeCreateChild, arguments);		
	},


	doCreateChild: function(parent, index, data) {
		//dojo.debug("doCreateChild parent "+parent+" index "+index+" data "+data);
		
		var newChild = parent.tree.createNode(data); 
		//var newChild = dojo.widget.createWidget(widgetType, data);

		parent.addChild(newChild, index);

		return newChild;
	},
	
	exposeCreateChild: function(parent) {
		return this.expand(parent);
	}


});

__CPAN_FILE__ src/widget/TreeDisableWrapExtension.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide( "dojo.widget.TreeDisableWrapExtension" );

dojo.require( "dojo.widget.HtmlWidget" );
dojo.require( "dojo.widget.TreeExtension" );

// selector extension to emphase node
dojo.widget.defineWidget(
	"dojo.widget.TreeDisableWrapExtension",
	dojo.widget.TreeExtension,
{
	/**
	 * can't unlisten
	 */
	templateCssPath: dojo.uri.dojoUri( "src/widget/templates/TreeDisableWrap.css" ),
		
	listenTree: function(tree) {
		
		var wrappingDiv = document.createElement( "div" );
		var clazz = tree.classPrefix+"DisableWrap";
		if (dojo.render.html.ie) {
			clazz = clazz+' '+ tree.classPrefix+"IEDisableWrap";
		}
		dojo.html.setClass(wrappingDiv, clazz);
		
		var table = document.createElement( "table" );
		wrappingDiv.appendChild( table );
		
		var tbody = document.createElement( "tbody" );
		table.appendChild( tbody );
		
		var tr = document.createElement( "tr" );
		tbody.appendChild( tr );
		
		var td = document.createElement( "td" );
		tr.appendChild( td );
		
		if( tree.domNode.parentNode ) {
			tree.domNode.parentNode.replaceChild( wrappingDiv, tree.domNode );
		}
		
		td.appendChild( tree.domNode );
		tree.domNode = wrappingDiv;
	}
});

__CPAN_FILE__ src/widget/Toggler.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Toggler");
dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");

// clicking on this node shows/hides another widget

dojo.widget.defineWidget(
	"dojo.widget.Toggler",
	dojo.widget.HtmlWidget,
{
	// Associated widget 
	targetId: '',
	
	fillInTemplate: function() {
		dojo.event.connect(this.domNode, "onclick", this, "onClick");
	},
	
	onClick: function() {
		var pane = dojo.widget.byId(this.targetId);
		if(!pane){ return; }
		pane.explodeSrc = this.domNode;
		pane.toggleShowing();
	}
});

__CPAN_FILE__ src/widget/TreeLoadingController.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeLoadingController");

dojo.require("dojo.widget.TreeBasicController");
dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");


dojo.widget.defineWidget("dojo.widget.TreeLoadingController", dojo.widget.TreeBasicController, {
	RPCUrl: "",

	RPCActionParam: "action", // used for GET for RPCUrl


	/**
	 * Common RPC error handler (dies)
	*/
	RPCErrorHandler: function(type, obj, evt) {
		alert( "RPC Error: " + (obj.message||"no message"));
	},

	preventCache: true,

	getRPCUrl: function(action) {

		// RPCUrl=local meant SOLELY for DEMO and LOCAL TESTS.
		// May lead to widgetId collisions
		if (this.RPCUrl == "local") {
			var dir = document.location.href.substr(0, document.location.href.lastIndexOf('/'));
			var localUrl = dir+"/"+action;
			//dojo.debug(localUrl);
			return localUrl;
		}

		if (!this.RPCUrl) {
			dojo.raise("Empty RPCUrl: can't load");
		}

		return this.RPCUrl + ( this.RPCUrl.indexOf("?") > -1 ? "&" : "?") + this.RPCActionParam+"="+action;
	},


	/**
	 * Add all loaded nodes from array obj as node children and expand it
	*/
	loadProcessResponse: function(node, result, callObj, callFunc) {

		if (!dojo.lang.isUndefined(result.error)) {
			this.RPCErrorHandler("server", result.error);
			return false;
		}

		//dojo.debugShallow(result);

		var newChildren = result;

		if (!dojo.lang.isArray(newChildren)) {
			dojo.raise('loadProcessResponse: Not array loaded: '+newChildren);
		}

		for(var i=0; i<newChildren.length; i++) {
			// looks like dojo.widget.manager needs no special "add" command
			newChildren[i] = dojo.widget.createWidget(node.widgetType, newChildren[i]);
			node.addChild(newChildren[i]);
		}


		//node.addAllChildren(newChildren);

		node.state = node.loadStates.LOADED;

		//dojo.debug(callFunc);

		if (dojo.lang.isFunction(callFunc)) {
			callFunc.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node, newChildren]);
		}
		//this.expand(node);
	},

	getInfo: function(obj) {
		return obj.getInfo();
	},

	runRPC: function(kw) {
		var _this = this;

		var handle = function(type, data, evt) {
			// unlock BEFORE any processing is done
			// so errorHandler may apply locking
			if (kw.lock) {
				dojo.lang.forEach(kw.lock,
					function(t) { t.unlock() }
				);
			}

			if(type == "load"){
				kw.load.call(this, data);
			}else{
				this.RPCErrorHandler(type, data, evt);
			}

		}

		if (kw.lock) {
			dojo.lang.forEach(kw.lock,
				function(t) { t.lock() }
			);
		}


		dojo.io.bind({
			url: kw.url,
			/* I hitch to get this.loadOkHandler */
			handle: dojo.lang.hitch(this, handle),
			mimetype: "text/json",
			preventCache: _this.preventCache,
			sync: kw.sync,
			content: { data: dojo.json.serialize(kw.params) }
		});
	},



	/**
	 * Load children of the node from server
	 * Synchroneous loading doesn't break control flow
	 * I need sync mode for DnD
	*/
	loadRemote: function(node, sync, callObj, callFunc){
		var _this = this;

		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		};

		//dojo.debug(callFunc)

		this.runRPC({
			url: this.getRPCUrl('getChildren'),
			load: function(result) {
				_this.loadProcessResponse(node, result, callObj, callFunc) ;
			},
			sync: sync,
			lock: [node],
			params: params
		});

	},


	expand: function(node, sync, callObj, callFunc) {

		if (node.state == node.loadStates.UNCHECKED && node.isFolder) {

			this.loadRemote(node, sync,
				this,
				function(node, newChildren) {
					this.expand(node, sync, callObj, callFunc);
				}
			);

			return;
		}

		dojo.widget.TreeBasicController.prototype.expand.apply(this, arguments);

	},



	doMove: function(child, newParent, index) {
		/* load nodes into newParent in sync mode, if needed, first */
		if (newParent.isTreeNode && newParent.state == newParent.loadStates.UNCHECKED) {
			this.loadRemote(newParent, true);
		}

		return dojo.widget.TreeBasicController.prototype.doMove.apply(this, arguments);
	},


	doCreateChild: function(parent, index, data, callObj, callFunc) {

		/* load nodes into newParent in sync mode, if needed, first */
		if (parent.state == parent.loadStates.UNCHECKED) {
			this.loadRemote(parent, true);
		}

		return dojo.widget.TreeBasicController.prototype.doCreateChild.apply(this, arguments);
	}



});

__CPAN_FILE__ src/widget/RegexpTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.RegexpTextbox");

dojo.require("dojo.widget.ValidationTextbox");

/*
  ****** RegexpTextbox ******

  A subclass of ValidationTextbox.
  Over-rides isValid to test input based on a regular expression.
  Has a new property that can be specified as attributes in the markup. 

  @attr regexp     The regular expression string to use
  @attr flags      Flags to pass to the regular expression (e.g. 'i', 'g', etc)
*/
dojo.widget.defineWidget(
	"dojo.widget.RegexpTextbox",
	dojo.widget.ValidationTextbox,
	{
	    mixInProperties: function(localProperties, frag){
	        // First initialize properties in super-class.
	        dojo.widget.RegexpTextbox.superclass.mixInProperties.apply(this, arguments);

	        // Get properties from markup attibutes, and assign to flags object.
	        if(localProperties.regexp){
	            this.flags.regexp = localProperties.regexp;
	        }
	        if(localProperties.flags){
	            this.flags.flags = localProperties.flags;
	        }
	    },

	    // Over-ride for integer validation
	    isValid: function(){
	        var regexp = new RegExp(this.flags.regexp, this.flags.flags);
	        return regexp.test(this.textbox.value);
	    }
	}
);

__CPAN_FILE__ src/widget/Tree.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
 * Tree model does all the drawing, visual node management etc.
 * Throws events about clicks on it, so someone may catch them and process
 * Tree knows nothing about DnD stuff, covered in TreeDragAndDrop and (if enabled) attached by controller
*/

/**
 * TODO: use domNode.cloneNode instead of createElement for grid
 * Should be faster (lyxsus)
 */
dojo.provide("dojo.widget.Tree");

dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeNode");
dojo.require("dojo.html.common");
dojo.require("dojo.html.selection");


dojo.widget.defineWidget("dojo.widget.Tree", dojo.widget.HtmlWidget, function() {
	this.eventNames = {};

	this.tree = this;
	this.DNDAcceptTypes = [];
	this.actionsDisabled = [];

},
{
	widgetType: "Tree",

	eventNamesDefault: {
		// new child does not get domNode filled in (only template draft)
		// until addChild->createDOMNode is called(program way) OR createDOMNode (html-way)
		// hook events to operate on new DOMNode, create dropTargets etc
		createDOMNode: "createDOMNode",
		// tree created.. Perform tree-wide actions if needed
		treeCreate: "treeCreate",
		treeDestroy: "treeDestroy",
		// expand icon clicked
		treeClick: "treeClick",
		// node icon clicked
		iconClick: "iconClick",
		// node title clicked
		titleClick: "titleClick",

		moveFrom: "moveFrom",
		moveTo: "moveTo",
		addChild: "addChild",
		removeNode: "removeNode",
		expand: "expand",
		collapse: "collapse"
	},

	isContainer: true,

	DNDMode: "off",

	lockLevel: 0, // lock ++ unlock --, so nested locking works fine

	strictFolders: true,

	DNDModes: {
		BETWEEN: 1,
		ONTO: 2
	},

	DNDAcceptTypes: "",

	templateCssPath: dojo.uri.dojoUri("src/widget/templates/images/Tree/Tree.css"),

	templateString: '<div class="dojoTree"></div>',

	isExpanded: true, // consider this "root node" to be always expanded

	isTree: true,

	objectId: "",

	// autoCreate if not "off"
	// used to get the autocreated controller ONLY.
	// generally, tree DOES NOT KNOW about its CONTROLLER, it just doesn't care
	// controller gets messages via dojo.event
	controller: "",

	// autoCreate if not "off"
	// used to get the autocreated selector ONLY.
	// generally, tree DOES NOT KNOW its SELECTOR
	// binding is made with dojo.event
	selector: "",

	// used ONLY at initialization time
	menu: "", // autobind menu if menu's widgetId is set here

	expandLevel: "", // expand to level automatically

	//
	// these icons control the grid and expando buttons for the whole tree
	//

	blankIconSrc: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_blank.gif"),

	gridIconSrcT: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_t.gif"), // for non-last child grid
	gridIconSrcL: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_l.gif"), // for last child grid
	gridIconSrcV: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_v.gif"), // vertical line
	gridIconSrcP: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_p.gif"), // for under parent item child icons
	gridIconSrcC: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_c.gif"), // for under child item child icons
	gridIconSrcX: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_x.gif"), // grid for sole root item
	gridIconSrcY: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_y.gif"), // grid for last rrot item
	gridIconSrcZ: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_grid_z.gif"), // for under root parent item child icon

	expandIconSrcPlus: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_expand_plus.gif"),
	expandIconSrcMinus: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_expand_minus.gif"),
	expandIconSrcLoading: dojo.uri.dojoUri("src/widget/templates/images/Tree/treenode_loading.gif"),


	iconWidth: 18,
	iconHeight: 18,


	//
	// tree options
	//

	showGrid: true,
	showRootGrid: true,

	actionIsDisabled: function(action) {
		var _this = this;
		return dojo.lang.inArray(_this.actionsDisabled, action)
	},


	actions: {
    	ADDCHILD: "ADDCHILD"
	},


	getInfo: function() {
		var info = {
			widgetId: this.widgetId,
			objectId: this.objectId
		}

		return info;
	},

	initializeController: function() {
		if (this.controller != "off") {
			if (this.controller) {
				this.controller = dojo.widget.byId(this.controller);
			}
			else {
				// create default controller here
				dojo.require("dojo.widget.TreeBasicController");
				this.controller = dojo.widget.createWidget("TreeBasicController",
					{ DNDController: (this.DNDMode ? "create" : ""), dieWithTree: true }
				 );

			}
			this.controller.listenTree(this); // controller listens to my events

		} else {
			this.controller = null;
		}
	},

	initializeSelector: function() {

		if (this.selector != "off") {
			if (this.selector) {
				this.selector = dojo.widget.byId(this.selector);
			}
			else {
				// create default controller here
				dojo.require("dojo.widget.TreeSelector");
				this.selector = dojo.widget.createWidget("TreeSelector", {dieWithTree: true});
			}

			this.selector.listenTree(this);

		} else {
			this.selector = null;
		}
	},

	initialize: function(args, frag){

		var _this = this;

		for(name in this.eventNamesDefault) {
			if (dojo.lang.isUndefined(this.eventNames[name])) {
				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
			}
		}

		for(var i=0; i<this.actionsDisabled.length; i++) {
			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
		}

		if (this.DNDMode == "off") {
			this.DNDMode = 0;
		} else if (this.DNDMode == "between") {
			this.DNDMode = this.DNDModes.ONTO | this.DNDModes.BETWEEN;
		} else if (this.DNDMode == "onto") {
			this.DNDMode = this.DNDModes.ONTO;
		}

		this.expandLevel = parseInt(this.expandLevel);

		this.initializeSelector();
		this.initializeController();

		if (this.menu) {
			this.menu = dojo.widget.byId(this.menu);
			this.menu.listenTree(this);
		}


		this.containerNode = this.domNode;

	},


	postCreate: function() {
		this.createDOMNode();
	},


	createDOMNode: function() {

		dojo.html.disableSelection(this.domNode);

		for(var i=0; i<this.children.length; i++){
			this.children[i].parent = this; // root nodes have tree as parent

			var node = this.children[i].createDOMNode(this, 0);


			this.domNode.appendChild(node);
		}


		if (!this.showRootGrid){
			for(var i=0; i<this.children.length; i++){
				this.children[i].expand();
			}
		}

		dojo.event.topic.publish(this.eventNames.treeCreate, { source: this } );

	},


	destroy: function() {
		dojo.event.topic.publish(this.tree.eventNames.treeDestroy, { source: this } );

		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
	},


	addChild: function(child, index) {

//		dojo.debug("doAddChild "+index+" called for "+child);

		var message = {
			child: child,
			index: index,
			parent: this,
			// remember if dom was already initialized
			// initialized => no createDOMNode => no createDOMNode event
			domNodeInitialized: child.domNodeInitialized
		}

		this.doAddChild.apply(this, arguments);

		dojo.event.topic.publish(this.tree.eventNames.addChild, message);
	},


	// not called for initial tree building. See createDOMNode instead.
	// builds child html node if needed
	// index is "last node" by default
	/**
	 * FIXME: Is it possible that removeNode from the tree will cause leaks cause of attached events ?
	 * if yes, then only attach events in addChild and detach in remove.. Seems all ok yet.
	*/
	doAddChild: function(child, index){

		if (dojo.lang.isUndefined(index)) {
			index = this.children.length;
		}

		if (!child.isTreeNode){
			dojo.raise("You can only add TreeNode widgets to a "+this.widgetType+" widget!");
			return;
		}

		// usually it is impossible to change "isFolder" state, but if anyone wants to add a child to leaf,
		// it is possible program-way.
		if (this.isTreeNode){
			if (!this.isFolder) { // just became a folder.
				//dojo.debug("becoming folder "+this);
				this.setFolder();
			}
		}

		// adjust tree
		var _this = this;
		dojo.lang.forEach(child.getDescendants(), function(elem) { elem.tree = _this.tree; });

		// fix parent
		child.parent = this;


		// no dynamic loading for those who become parents
		if (this.isTreeNode) {
			this.state = this.loadStates.LOADED;
		}

		// add new child into DOM after it was added into children
		if (index < this.children.length) { // children[] already has child
			//dojo.debug("Inserting before "+this.children[index].title);
			dojo.html.insertBefore(child.domNode, this.children[index].domNode);
		} else {
			this.containerNode.appendChild(child.domNode);
			if (this.isExpanded && this.isTreeNode) {
				/* When I add children to hidden containerNode => show container w/ them */
				this.showChildren();
			}
		}


		this.children.splice(index, 0, child);

		//dojo.debugShallow(this.children);


		// if node exists - adjust its depth, otherwise build it
		if (child.domNodeInitialized) {
			var d = this.isTreeNode ? this.depth : -1;
			child.adjustDepth( d - child.depth + 1 );


			// update icons to link generated dom with Tree => updateParentGrid
			// if I moved child from LastNode inside the tree => need to link it up'n'down =>
			// updateExpandGridColumn
			// if I change depth => need to update all grid..
			child.updateIconTree();
		} else {
			//dojo.debug("Create domnode ");
			child.depth = this.isTreeNode ? this.depth+1 : 0;
			child.createDOMNode(child.tree, child.depth);
		}



		// Use-case:
		// When previous sibling was created => it was last, no children after it
		// so it did not create link down => let's add it for all descendants
		// Use-case:
		// a child was moved down under the last node so last node should be updated
		var prevSibling = child.getPreviousSibling();
		if (child.isLastChild() && prevSibling) {
			prevSibling.updateExpandGridColumn();
		}


		//dojo.debug("Added child "+child);



	},




	makeBlankImg: function() {
		var img = document.createElement('img');

		img.style.width = this.iconWidth + 'px';
		img.style.height = this.iconHeight + 'px';
		img.src = this.blankIconSrc;
		img.style.verticalAlign = 'middle';

		return img;
	},


	updateIconTree: function(){

		//dojo.debug("Update icons for "+this)
		if (!this.isTree) {
			this.updateIcons();
		}

		for(var i=0; i<this.children.length; i++){
			this.children[i].updateIconTree();
		}

	},

	toString: function() {
		return "["+this.widgetType+" ID:"+this.widgetId+"]"
	},




	/**
	 * Move child to newParent as last child
	 * redraw tree and update icons.
	 *
	 * Called by target, saves source in event.
	 * events are published for BOTH trees AFTER update.
	*/
	move: function(child, newParent, index) {

		//dojo.debug(child+" "+newParent+" at "+index);

		var oldParent = child.parent;
		var oldTree = child.tree;

		this.doMove.apply(this, arguments);

		var newParent = child.parent;
		var newTree = child.tree;

		var message = {
				oldParent: oldParent, oldTree: oldTree,
				newParent: newParent, newTree: newTree,
				child: child
		};

		/* publish events here about structural changes for both source and target trees */
		dojo.event.topic.publish(oldTree.eventNames.moveFrom, message);
		dojo.event.topic.publish(newTree.eventNames.moveTo, message);

	},


	/* do actual parent change here. Write remove child first */
	doMove: function(child, newParent, index) {
		//var parent = child.parent;
		child.parent.doRemoveNode(child);

		newParent.doAddChild(child, index);
	},



// ================================ removeNode ===================================

	removeNode: function(child) {
		if (!child.parent) return;

		var oldTree = child.tree;
		var oldParent = child.parent;

		var removedChild = this.doRemoveNode.apply(this, arguments);


		dojo.event.topic.publish(this.tree.eventNames.removeNode,
			{ child: removedChild, tree: oldTree, parent: oldParent }
		);

		return removedChild;
	},


	doRemoveNode: function(child) {
		if (!child.parent) return;

		var parent = child.parent;

		var children = parent.children;


		var index = child.getParentIndex();
		if (index < 0) {
			dojo.raise("Couldn't find node "+child+" for removal");
		}


		children.splice(index,1);
		dojo.html.removeNode(child.domNode);

		if (parent.children.length == 0 && !parent.isTree) {
			parent.containerNode.style.display = "none";
		}

		// if WAS last node (children.length decreased already) and has prevSibling
		if (index == children.length && index>0) {
			children[index-1].updateExpandGridColumn();
		}
		// if it WAS first node in WHOLE TREE -
		// update link up of its former lower neighbour(if exists still)
		if (parent instanceof dojo.widget.Tree && index == 0 && children.length>0) {
			children[0].updateExpandGrid();
		}

		//parent.updateIconTree();


		child.parent = child.tree = null;

		return child;
	},

	markLoading: function() {
		// no way to mark tree loading
	},

	unMarkLoading: function() {
		// no way to show that tree finished loading
	},


	lock: function() {
		!this.lockLevel && this.markLoading();
		this.lockLevel++;
	},
	unlock: function() {
		if (!this.lockLevel) {
			dojo.raise("unlock: not locked");
		}
		this.lockLevel--;
		!this.lockLevel && this.unMarkLoading();
	},

	isLocked: function() {
		var node = this;
		while (true) {
			if (node.lockLevel) {
				return true;
			}
			if (node instanceof dojo.widget.Tree) {
				break;
			}
			node = node.parent;
		}

		return false;
	},

	flushLock: function() {
		this.lockLevel = 0;
		this.unMarkLoading();
	}
});



__CPAN_FILE__ src/widget/Chart.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Chart");

dojo.require("dojo.widget.*");
dojo.require("dojo.gfx.color");
dojo.require("dojo.gfx.color.hsl");

// Base class for svg and vml implementations of Chart
dojo.declare(
	"dojo.widget.Chart",
	null,
	function(){
		this.series = [];
	},
{
	isContainer: false,

	assignColors: function(){
		//	summary
		//	Assigns/generates a color for a data series.
		var hue=30;
		var sat=120;
		var lum=120;
		var steps = Math.round(330/this.series.length);

		for(var i=0; i<this.series.length; i++){
			var c=dojo.gfx.color.hsl2rgb(hue,sat,lum);
			if(!this.series[i].color){
				this.series[i].color = dojo.gfx.color.rgb2hex(c[0],c[1],c[2]);
			}
			hue += steps;
		}
	},
	parseData: function(table){
		var thead=table.getElementsByTagName("thead")[0];
		var tbody=table.getElementsByTagName("tbody")[0];
		if(!(thead&&tbody)) dojo.raise("dojo.widget.Chart: supplied table must define a head and a body.");

		//	set up the series.
		var columns=thead.getElementsByTagName("tr")[0].getElementsByTagName("th");	//	should be <tr><..>
		
		//	assume column 0 == X
		for (var i=1; i<columns.length; i++){
			var key="column"+i;
			var label=columns[i].innerHTML;
			var plotType=columns[i].getAttribute("plotType")||"line";
			var color=columns[i].getAttribute("color");
			var ds=new dojo.widget.Chart.DataSeries(key,label,plotType,color);
			this.series.push(ds);
		}

		//	ok, get the values.
		var rows=tbody.rows;
		var xMin=Number.MAX_VALUE,xMax=Number.MIN_VALUE;
		var yMin=Number.MAX_VALUE,yMax=Number.MIN_VALUE;
		var ignore = [
			"accesskey","align","bgcolor","class",
			"colspan","height","id","nowrap",
			"rowspan","style","tabindex","title",
			"valign","width"
		];

		for(var i=0; i<rows.length; i++){
			var row=rows[i];
			var cells=row.cells;
			var x=Number.MIN_VALUE;
			for (var j=0; j<cells.length; j++){
				if (j==0){
					x=parseFloat(cells[j].innerHTML);
					xMin=Math.min(xMin, x);
					xMax=Math.max(xMax, x);
				} else {
					var ds=this.series[j-1];
					var y=parseFloat(cells[j].innerHTML);
					yMin=Math.min(yMin,y);
					yMax=Math.max(yMax,y);
					var o={x:x, value:y};
					var attrs=cells[j].attributes;
					for(var k=0; k<attrs.length; k++){
						var attr=attrs.item(k);
						var bIgnore=false;
						for (var l=0; l<ignore.length; l++){
							if (attr.nodeName.toLowerCase()==ignore[l]){
								bIgnore=true;
								break;
							}
						}
						if(!bIgnore) o[attr.nodeName]=attr.nodeValue;
					}
					ds.add(o);
				}
			}
		}
		return { x:{ min:xMin, max:xMax}, y:{ min:yMin, max:yMax} };
	}
});

/*
 *	Every chart has a set of data series; this is the series.  Note that each
 *	member of value is an object and in the minimum has 2 properties: .x and
 *	.value.
 */
dojo.declare(
	"dojo.widget.Chart.DataSeries",
	null,
	function(key, label, plotType, color){
		this.id = "DataSeries"+dojo.widget.Chart.DataSeries.count++;
		this.key = key;
		this.label = label||this.id;
		this.plotType = plotType||"line";	//	let line be the default.
		this.color = color;
		this.values = [];
	},
{
	add: function(v){
		if(v.x==null||v.value==null){
			dojo.raise("dojo.widget.Chart.DataSeries.add: v must have both an 'x' and 'value' property.");
		}
		this.values.push(v);
	},

	clear: function(){
		this.values=[];
	},

	createRange: function(len){
		var idx = this.values.length-1;
		var length = (len||this.values.length);
		return { "index": idx, "length": length, "start":Math.max(idx-length,0) };
	},

	//	trend values
	getMean: function(len){
		var range = this.createRange(len);
		if(range.index<0){ return 0; }
		var t = 0;
		var c = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){ t += n; c++; }
		}
		t /= Math.max(c,1);
		return t;
	},

	getMovingAverage: function(len){
		var range = this.createRange(len);
		if(range.index<0){ return 0; }
		var t = 0;
		var c = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){ t += n; c++; }
		}
		t /= Math.max(c,1);
		return t;
	},

	getVariance: function(len){
		var range = this.createRange(len);
		if(range.index < 0){ return 0; }
		var t = 0; // FIXME: for tom: wtf are t, c, and s?
		var s = 0;
		var c = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){
				t += n;
				s += Math.pow(n,2);
				c++;
			}
		}
		return (s/c)-Math.pow(t/c,2);
	},

	getStandardDeviation: function(len){
		return Math.sqrt(this.getVariance(len));
	},

	getMax: function(len){
		var range = this.createRange(len);
		if(range.index < 0){ return 0; }
		var t = 0;
		for (var i=range.index; i>=range.start; i--){
			var n=parseFloat(this.values[i].value);
			if (!isNaN(n)){
				t=Math.max(n,t);
			}
		}
		return t;
	},

	getMin: function(len){
		var range=this.createRange(len);
		if(range.index < 0){ return 0; }
		var t = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){
				t=Math.min(n,t);
			}
		}
		return t;
	},

	getMedian: function(len){
		var range = this.createRange(len);

		if(range.index<0){ return 0; }

		var a = [];
		for (var i=range.index; i>=range.start; i--){
			var n=parseFloat(this.values[i].value);
			if (!isNaN(n)){
				var b=false;
				for(var j=0; j<a.length&&!b; j++){
					if (n==a[j]) b=true; 
				}
				if(!b){ a.push(n); }
			}
		}
		a.sort();
		if(a.length>0){ return a[Math.ceil(a.length/2)]; }
		return 0;
	},

	getMode: function(len){
		var range=this.createRange(len);
		if(range.index<0){ return 0; }
		var o = {};
		var ret = 0
		var m = 0;
		for(var i=range.index; i>=range.start; i--){
			var n=parseFloat(this.values[i].value);
			if(!isNaN(n)){
				if (!o[this.values[i].value]) o[this.values[i].value] = 1;
				else o[this.values[i].value]++;
			}
		}
		for(var p in o){
			if(m<o[p]){ m=o[p]; ret=p; }
		}
		return parseFloat(ret);
	}
});

dojo["requireIf"](dojo.render.svg.capable, "dojo.widget.svg.Chart");
dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.widget.vml.Chart");

__CPAN_FILE__ src/widget/Textbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Textbox");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.Manager");
dojo.require("dojo.widget.Parse");
dojo.require("dojo.xml.Parse");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.common");

dojo.require("dojo.i18n.common");
dojo.requireLocalization("dojo.widget", "validate");

/*
  ****** Textbox ******

  This widget is a generic textbox field.
  Serves as a base class to derive more specialized functionality in subclasses.
  Has the following properties that can be specified as attributes in the markup.

  @attr id         The textbox id attribute.
  @attr className  The textbox class attribute.
  @attr name       The textbox name attribute.
  @attr value      The textbox value attribute.
  @attr trim       Removes leading and trailing whitespace if true.  Default is false.
  @attr uppercase  Converts all characters to uppercase if true.  Default is false.
  @attr lowercase  Converts all characters to lowercase if true.  Default is false.
  @attr ucFirst    Converts the first character of each word to uppercase if true.
  @attr lowercase  Removes all characters that are not digits if true.  Default is false.
*/
dojo.widget.defineWidget(
	"dojo.widget.Textbox",
	dojo.widget.HtmlWidget,
	{
		// default values for new subclass properties
		className: "",
		name: "",
		value: "",
		type: "",
		trim: false,
		uppercase: false,
		lowercase: false,
		ucFirst: false,
		digit: false,
		htmlfloat: "none",

		templatePath: dojo.uri.dojoUri("src/widget/templates/Textbox.html"),
	
		// our DOM nodes
		textbox: null,
	
		// Apply various filters to textbox value
		filter: function() { 
			if (this.trim) {
				this.textbox.value = this.textbox.value.replace(/(^\s*|\s*$)/g, "");
			} 
			if (this.uppercase) {
				this.textbox.value = this.textbox.value.toUpperCase();
			} 
			if (this.lowercase) {
				this.textbox.value = this.textbox.value.toLowerCase();
			} 
			if (this.ucFirst) {
				this.textbox.value = this.textbox.value.replace(/\b\w+\b/g, 
					function(word) { return word.substring(0,1).toUpperCase() + word.substring(1).toLowerCase(); });
			} 
			if (this.digit) {
				this.textbox.value = this.textbox.value.replace(/\D/g, "");
			} 
		},
	
		// event handlers, you can over-ride these in your own subclasses
		onfocus: function() {},
		onblur: function() { this.filter(); },
	
		// All functions below are called by create from dojo.widget.Widget
		mixInProperties: function(localProperties, frag) {
			dojo.widget.Textbox.superclass.mixInProperties.apply(this, arguments);
			if ( localProperties["class"] ) { 
				this.className = localProperties["class"];
			}
		}
	}
);

__CPAN_FILE__ src/widget/TreeExtension.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeExtension");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeCommon");

dojo.widget.defineWidget(
	"dojo.widget.TreeExtension",
	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
	function() {
		this.listenedTrees = {};
	},
	{}
);

__CPAN_FILE__ src/widget/GoogleMap.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.GoogleMap");
dojo.require("dojo.event.*");
dojo.require("dojo.math");
dojo.require("dojo.widget.*");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.widget.HtmlWidget");

(function(){
	var gkey = djConfig["gMapKey"]||djConfig["googleMapKey"];

	//	the Google API key mechanism sucks.  We're hardcoding here for love and affection but I don't like it.
	var uri=new dojo.uri.Uri(window.location.href);
	if(uri.host=="www.dojotoolkit.org"){
		gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hRqjp7ri2mNiOEYqetD3xnFHpt5rBSjszDd1sdufPyQKUTyCf_YxoIxvw";
	}
	else if(uri.host=="blog.dojotoolkit.org"){
		gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hSkep6Av1xaMhVn3yCLkorJeXeLARQ6fammI_P3qSGleTJhoI5_1JmP_Q";
	}
	else if(uri.host=="archive.dojotoolkit.org"){
		gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hTaQpDt0dyGLIHbXMPTzg1kWeAfwRTwZNyrUfbfxYE9yIvRivEjcXoDTg";
	}
	else if(uri.host=="dojotoolkit.org"){
		gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hSaOaO_TgJ5c3mtQFnk5JO2zD5dZBRZk-ieqVs7BORREYNzAERmcJoEjQ";
	}

	if(!dojo.hostenv.post_load_){
		if(!gkey || gkey==""){
			dojo.raise("dojo.widget.GoogleMap: The Google Map widget requires a proper API key in order to be used.");
		}
		var tag = "<scr"+"ipt src='http://maps.google.com/maps?file=api&amp;v=2&amp;key="+gkey+"'></scri"+"pt>";
		if(!dj_global["GMap2"]){
			document.write(tag);
		}
	}else{
		dojo.debug("Cannot initialize Google Map system after the page has been loaded! Please either manually include the script block provided by Google in your page or require() the GoogleMap widget before onload has fired.");
	}
})();

dojo.widget.defineWidget(
	"dojo.widget.GoogleMap",
	dojo.widget.HtmlWidget,
	function(){
		//	summary
		//	initializer/constructor for the simple GoogleMap widget.
		this.map=null;
		this.geocoder=null;
		this.data=[];
		this.datasrc="";
		this.controls=["largemap","scale","maptype"];
	},
{
	templatePath:null,
	templateCssPath:null,
	isContainer: false,

	_defaultPoint:{lat:39.10662, lng: -94.578209},

	setControls:function(){
		//	summary
		//	Set any controls on the map in question.
		var methodmap={
			largemap:GLargeMapControl,
			smallmap:GSmallMapControl,
			smallzoom:GSmallZoomControl,
			scale:GScaleControl,
			maptype:GMapTypeControl,
			overview:GOverviewMapControl
		};
		for(var i=0; i<this.controls.length; i++){
			this.map.addControl(new (methodmap[this.controls[i].toLowerCase()])());
		}
	},
	
	findCenter:function(/* GLatLngBounds */bounds){
		//	summary
		//	Returns the center point given the Bounds object.
		if(this.data.length==1){
			return (new GLatLng(this.data[0].lat, this.data[0].lng));	//	GLatLng
		}
		var clat=(bounds.getNorthEast().lat()+bounds.getSouthWest().lat())/2;
		var clng=(bounds.getNorthEast().lng()+bounds.getSouthWest().lng())/2;
		return (new GLatLng(clat,clng));	//	GLatLng
	},

	createPinpoint:function(/* GLatLng */pt, /* string? */overlay){
		//	summary
		//	Creates a marker at the given point, with an optional overlay HTML string.
		var m=new GMarker(pt);
		if(overlay){
			GEvent.addListener(m,"click",function(){
				m.openInfoWindowHtml("<div>"+overlay+"</div>");
			});
		}
		return m;	//	GMarker
	},
	plot:function(/* object */obj){
		//	summary
		//	Plots a point at given lat/lng coordinate
		var p=new GLatLng(obj.lat,obj.lng);
		var d=obj.description||null;
		var m=this.createPinpoint(p,d);
		this.map.addOverlay(m);
	},
	plotAddress:function(/* string */address){
		//	summary
		//	Calls the Google Geocoder to get a lat/lng coordinate at string address
		var self=this;
		this.geocoder.getLocations(address, function(response){
			if(!response || response.Status.code != 200){
				alert("The address \"" + address + "\" was not found.");
				return;
			}
			var obj={
				lat:response.Placemark[0].Point.coordinates[1],
				lng:response.Placemark[0].Point.coordinates[0],
				description:response.Placemark[0].address
			};
			self.data.push(obj);
			self.render();
		});
	},

	parse:function(/* HTMLTable */table){
		//	summary
		//	Parses the passed table for data to plot on this map.
		this.data=[];

		//	get the column indices
		var h=table.getElementsByTagName("thead")[0];
		if(!h){
			return;
		}

		var a=[];
		var cols=h.getElementsByTagName("td");
		if(cols.length==0){
			cols=h.getElementsByTagName("th");
		}
		for(var i=0; i<cols.length; i++){
			var c=cols[i].innerHTML.toLowerCase();
			if(c=="long") c="lng";
			a.push(c);
		}
		
		//	parse the data
		var b=table.getElementsByTagName("tbody")[0];
		if(!b){
			return;
		}
		for(var i=0; i<b.childNodes.length; i++){
			if(!(b.childNodes[i].nodeName&&b.childNodes[i].nodeName.toLowerCase()=="tr")){
				continue;
			}
			var cells=b.childNodes[i].getElementsByTagName("td");
			var o={};
			for(var j=0; j<a.length; j++){
				var col=a[j];
				if(col=="lat"||col=="lng"){
					o[col]=parseFloat(cells[j].innerHTML);					
				}else{
					o[col]=cells[j].innerHTML;
				}
			}
			this.data.push(o);
		}
	},
	render:function(){
		//	summary
		//	Plots all acutal points in the current data array.
		if(this.data.length==0){
			this.map.setCenter(new GLatLng(this._defaultPoint.lat, this._defaultPoint.lng), 4);
			return;
		}

		//	remove all overlays
		this.map.clearOverlays();

		var bounds=new GLatLngBounds();
		var d=this.data;
		for(var i=0; i<d.length; i++){
			bounds.extend(new GLatLng(d[i].lat,d[i].lng));
		}
		var zoom=Math.min((this.map.getBoundsZoomLevel(bounds)-1),14);
		this.map.setCenter(this.findCenter(bounds), zoom);

		for(var i=0; i<this.data.length; i++){
			this.plot(this.data[i]);
		}
	},

	initialize:function(/* object */args, /* object */frag){
		//	summary
		//	initializes the widget
		if(this.datasrc){
			this.parse(dojo.byId(this.datasrc));
		}
		else if(this.domNode.getElementsByTagName("table")[0]){
			this.parse(this.domNode.getElementsByTagName("table")[0]);
		}
	},
	postCreate:function(){
		//	summary
		//	Sets up and renders the widget.

		//	clean the domNode before creating the map.
		while(this.domNode.childNodes.length>0){
			this.domNode.removeChild(this.domNode.childNodes[0]);
		}
		if(this.domNode.style.position!="absolute"){
			this.domNode.style.position="relative";
		}
		this.map=new GMap2(this.domNode);
		try{
			this.geocoder=new GClientGeocoder();
		}catch(ex){}
		this.render();
		this.setControls();
	}
});

__CPAN_FILE__ src/widget/MonthlyCalendar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.MonthlyCalendar");
dojo.require("dojo.date.common");
dojo.require("dojo.date.format");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.DatePicker");
dojo.require("dojo.event.*");
dojo.require("dojo.html.*");
dojo.require("dojo.experimental");

dojo.experimental("dojo.widget.MonthlyCalendar");

dojo.widget.defineWidget(
	"dojo.widget.MonthlyCalendar",
	dojo.widget.DatePicker,
	{
		dayWidth: 'wide',

		templatePath: dojo.uri.dojoUri("src/widget/templates/MonthlyCalendar.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/MonthlyCalendar.css"),

		initializer: function(){
			this.iCalendars = [];
		},

		/*
		cache: function(){
		},
		*/

		addCalendar: function(/* dojo.iCalendar */ cal) {
			dojo.debug("Adding Calendar");
			this.iCalendars.push(cal);
			dojo.debug("Starting init");
			this.initUI();
			dojo.debug("done init");
		},

		createDayContents: function(node,mydate) {
			dojo.html.removeChildren(node);
			node.appendChild(document.createTextNode(mydate.getDate()));	
				for(var x=0; x<this.iCalendars.length; x++) {
					var evts = this.iCalendars[x].getEvents(mydate);
					if ((dojo.lang.isArray(evts)) && (evts.length>0)) {
					for(var y=0;y<evts.length;y++) {
						var el = document.createElement("div");
						dojo.html.addClass(el, "dojoMonthlyCalendarEvent");          
						el.appendChild(document.createTextNode(evts[y].summary.value));
						el.width = dojo.html.getContentBox(node).width;
						node.appendChild(el);
					}
				}
			}
		},

		initUI: function() {
			var dayLabels = dojo.date.getNames('days', this.dayWidth, 'standAlone', this.lang);
			var dayLabelNodes = this.dayLabelsRow.getElementsByTagName("td");
			for(var i=0; i<7; i++) {
				dayLabelNodes.item(i).innerHTML = dayLabels[i];
			}

			this.selectedIsUsed = false;
			this.currentIsUsed = false;
			var currentClassName = "";
			var previousDate = new Date();
			var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
			var currentCalendarNode;
			// set hours of date such that there is no chance of rounding error due to 
			// time change in local time zones
			previousDate.setHours(8);
			var nextDate = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date, 8);
			var lastDay = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date + 42, 8);
			
			if (this.iCalendars.length > 0) {
				for (var x=0; x<this.iCalendars.length;x++) {
					this.iCalendars[x].preComputeRecurringEvents(lastDay);
				}
			}

			if(this.firstSaturday.date < 7) {
				// this means there are days to show from the previous month
				var dayInWeek = 6;
				for (var i=this.firstSaturday.date; i>0; i--) {
					currentCalendarNode = calendarNodes.item(dayInWeek);
					this.createDayContents(currentCalendarNode, nextDate);
					
					dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
					dayInWeek--;
					previousDate = nextDate;
					nextDate = this.incrementDate(nextDate, false);
				}
				for(var i=dayInWeek; i>-1; i--) {
					currentCalendarNode = calendarNodes.item(i);

					this.createDayContents(currentCalendarNode, nextDate);

					dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "previous"));
					previousDate = nextDate;
					nextDate = this.incrementDate(nextDate, false);				
				}
			} else {
				nextDate.setDate(1);
				for(var i=0; i<7; i++) {
					currentCalendarNode = calendarNodes.item(i);
					this.createDayContents(currentCalendarNode, nextDate);
					dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
					previousDate = nextDate;
					nextDate = this.incrementDate(nextDate, true);				
				}
			}
			previousDate.setDate(this.firstSaturday.date);
			previousDate.setMonth(this.firstSaturday.month);
			previousDate.setFullYear(this.firstSaturday.year);
			nextDate = this.incrementDate(previousDate, true);
			var count = 7;
			currentCalendarNode = calendarNodes.item(count);
			while((nextDate.getMonth() == previousDate.getMonth()) && (count<42)) {
				this.createDayContents(currentCalendarNode, nextDate);
				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
				currentCalendarNode = calendarNodes.item(++count);
				previousDate = nextDate;
				nextDate = this.incrementDate(nextDate, true);
			}
			
			while(count < 42) {
				this.createDayContents(currentCalendarNode, nextDate);
				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "next"));
				currentCalendarNode = calendarNodes.item(++count);
				previousDate = nextDate;
				nextDate = this.incrementDate(nextDate, true);
			}
			this.setMonthLabel(this.firstSaturday.month);
			this.setYearLabels(this.firstSaturday.year);
		}	
	}
);

dojo.widget.MonthlyCalendar.util= new function() {

	this.toRfcDate = function(jsDate) {
		if(!jsDate) {
			jsDate = this.today;
		}
		var year = jsDate.getFullYear();
		var month = jsDate.getMonth() + 1;
		if (month < 10) {
			month = "0" + month.toString();
		}
		var date = jsDate.getDate();
		if (date < 10) {
			date = "0" + date.toString();
		}
		// because this is a date picker and not a time picker, we treat time 
		// as zero
		return year + "-" + month + "-" + date + "T00:00:00+00:00";
	}
	
	this.fromRfcDate = function(rfcDate) {
		var tempDate = rfcDate.split("-");
		if(tempDate.length < 3) {
			return new Date();
		}
		// fullYear, month, date
		return new Date(parseInt(tempDate[0]), (parseInt(tempDate[1], 10) - 1), parseInt(tempDate[2].substr(0,2), 10));
	}

//Note: redundant with dojo.widget.DatePicker.util	
	this.initFirstSaturday = function(month, year) {
		if(!month) {
			month = this.date.getMonth();
		}
		if(!year) {
			year = this.date.getFullYear();
		}
		var firstOfMonth = new Date(year, month, 1);
		return {year: year, month: month, date: 7 - firstOfMonth.getDay()};
	}
}

__CPAN_FILE__ src/widget/TreeWithNode.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.require("dojo.lang.declare");
dojo.provide("dojo.widget.TreeWithNode");

dojo.declare(
	"dojo.widget.TreeWithNode",
	null,
	function(){ },
{
	/*
	 * dynamic loading-related stuff. 
	 * When an empty folder node appears, it is "UNCHECKED" first,
	 * then after Rpc call it becomes LOADING and, finally LOADED
	 *
	 * tree may be dynamically loaded also
	 */
	loadStates: {
		UNCHECKED: "UNCHECKED",
    	LOADING: "LOADING",
    	LOADED: "LOADED"
	},
	
	state: "UNCHECKED",  // after creation will change to loadStates: "loaded/loading/unchecked"

    //RpcUrl: "", // user can override rpc url for specific nodes

	objectId: "", // the widget represents an object


	// I need this to parse children
	isContainer: true,
	
	lockLevel: 0, // lock ++ unlock --, so nested locking works fine
	
	lock: function() {
		this.lockLevel++;
	},
	unlock: function() {
		if (!this.lockLevel) {
			//dojo.debug((new Error()).stack);
			dojo.raise(this.widgetType+" unlock: not locked");
		}
		this.lockLevel--;
	},
	
	
	expandLevel: 0, // expand to level automatically
	loadLevel: 0, // load to level automatically
		
	hasLock: function() {
		return this.lockLevel>0;
	},

	isLocked: function() {
		var node = this;
		while (true) {
			if (node.lockLevel) {
				return true;
			}
			if (!node.parent || node.isTree) {
				break;
			}
			
			node = node.parent;
			
		}

		return false;
	},

	
	flushLock: function() {
		this.lockLevel = 0;
		//this.unMarkLoading();
	},
	
	
	actionIsDisabled: function(action) {
		var disabled = false;

		if (dojo.lang.inArray(this.actionsDisabled, action)) {
			disabled = true;
		}


		//dojo.debug("Check "+this+" "+disabled)
		
		
		if (this.isTreeNode) {
			if (!this.tree.allowAddChildToLeaf && action == this.actions.ADDCHILD && !this.isFolder) {
				disabled = true;
			}
		}
		return disabled;
	},
		
	actionIsDisabledNow: function(action) {
		return this.actionIsDisabled(action) || this.isLocked();
	},
	
	
	/**
	 * childrenArray is array of Widgets or array of Objects
	 * widgets may be both attached and detached
	 *
	 * Use Cases
	 * 1) lots of widgets are packed and passed in.
	 *  - widgets are created
	 *  - widgets have no parent (detached or not attached yet)
	 *
	 * 2) array of widgets and data objects passed in with flag makeWidgetsFromChildren
	 *  - some widgets are not created
	 *  - all objects have no parent
	 *
	 * 3) expand is called with makeWidgetsFromChildren=true
	 *  - some objects need to be turned into widgets
	 *  - some widgets have parent (e.g markup), some widgets and objects do not
	 *
	 *  Will folderize a node as side-effect.
	 */
	setChildren: function(childrenArray) {
		//dojo.profile.start("setChildren "+this);
		//dojo.debug("setChildren in "+this);
		
		
		if (this.isTreeNode && !this.isFolder) {
			//dojo.debug("folder parent "+parent+ " isfolder "+parent.isFolder);
			this.setFolder();
		} else if (this.isTreeNode) {
			this.state = this.loadStates.LOADED;
		}
		
		var hadChildren = this.children.length > 0;
		
        if (hadChildren && childrenArray){
            // perf: most of time setChildren used for empty nodes, so save function call
            this.destroyChildren()
        }
        
		if (childrenArray) {
			this.children = childrenArray;
		}
		


		var hasChildren = this.children.length > 0;
		if (this.isTreeNode && hasChildren != hadChildren) {
			// call only when hasChildren state changes
			this.viewSetHasChildren();
		}
		


		for(var i=0; i<this.children.length; i++) {
			var child = this.children[i];
			
			//dojo.profile.start("setChildren - create "+this);
			
			if (!(child instanceof dojo.widget.Widget)) {
				
				child = this.children[i] = this.tree.createNode(child);
				var childWidgetCreated = true;	
				//dojo.debugShallow(child)
				
				//dojo.debug("setChildren creates node "+child);
			} else {
				var childWidgetCreated = false;
			}
			
			//dojo.profile.end("setChildren - create "+this);

			//dojo.profile.start("setChildren - attach "+this);

			if (!child.parent) { // detached child
				
				//dojo.debug("detached child "+child);
				
				child.parent = this;

				//dojo.profile.start("setChildren - updateTree "+this);
				
				if (this.tree !== child.tree) {				
					child.updateTree(this.tree);
				}
				//dojo.profile.end("setChildren - updateTree "+this);

			
				//dojo.debug("Add layout for "+child);
				child.viewAddLayout();
				this.containerNode.appendChild(child.domNode);
					
				var message = {
					child: child,
					index: i,
					parent: this,
					childWidgetCreated: childWidgetCreated
				}
			
				delete dojo.widget.manager.topWidgets[child.widgetId];
		

				//dojo.profile.start("setChildren - event "+this);
				//dojo.debug("publish "+this.tree.eventNames.afterAddChild)
				dojo.event.topic.publish(this.tree.eventNames.afterAddChild, message);

				//dojo.profile.end("setChildren - event "+this);

			}
			
			if (this.tree.eagerWidgetInstantiation) {
				dojo.lang.forEach(this.children, function(child) {
					child.setChildren();
				});
			}

			//dojo.profile.end("setChildren - attach "+this);

		
		}
		


		//dojo.profile.end("setChildren "+this);
		
	},	
	
	
	doAddChild: function(child, index) {
		return this.addChild(child, index, true);
	},
		
	addChild: function(child, index, dontPublishEvent) {
		if (dojo.lang.isUndefined(index)) {
			index = this.children.length;
		}
		
		//dojo.debug("doAddChild "+index+" called for "+this+" child "+child+" existing children "+(this.children.length ? this.children : "<no children>"));
				
		if (!child.isTreeNode){
			dojo.raise("You can only add TreeNode widgets to a "+this.widgetType+" widget!");
			return;
		}
			
		this.children.splice(index, 0, child);
		child.parent = this;
				
		child.addedTo(this, index, dontPublishEvent);
		
		// taken from DomWidget.registerChild
		// delete from widget list that are notified on resize etc (no parent)
		delete dojo.widget.manager.topWidgets[child.widgetId];
				
	},
	
	 /**
     * does not inform children about resize (skips onShow),
     * because on large trees that's slow
     */
    onShow: function() {        
        this.animationInProgress=false;
    },
    
    onHide: function() {        
        this.animationInProgress=false;
    }
	
});

__CPAN_FILE__ src/widget/RadioGroup.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.RadioGroup");

dojo.require("dojo.lang.common");
dojo.require("dojo.event.browser");
dojo.require("dojo.html.selection");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

// summary:
// 	Widget that provides useful/common functionality that may be desirable
// 	when interacting with ul/ol html lists.
//	
// The core behaviour of the lists this widget manages is expected to be determined
// by the css class names defined: 
// 	
// 	 "radioGroup" - Applied to main ol or ul 
//	 "selected"	- Applied to the currently selected li, if any.
//   "itemContent" - Applied to the content contained in a li, this widget embeds a span 
//					within each <li></li> to contain the contents of the li.
// This widget was mostly developed under supervision/guidance from Tom Trenka.
dojo.widget.defineWidget(
	"dojo.widget.RadioGroup", 
	dojo.widget.HtmlWidget,
	function(){
		//	summary
		//	Initializes all properties for the widget.
		
		// Node: Currently selected li, if any
		this.selectedItem=null;
		// Node array: Array of li nodes being managed by widget
		this.items=[];
		// String array: List of optional ids specifying which li's should be selected by default
		this.selected=[];
		
		// String: Css class applied to main ol or ul, value is "radioGroup"
		this.groupCssClass="radioGroup";
		// String: Css class applied to the currently selected li, if any. value of "selected"
		this.selectedCssClass="selected";
		// String: Css class Applied to the content contained in a li, this widget embeds a span 
		// within each <li></li> to contain the contents of the li. value is "itemContent"
		this.itemContentCssClass="itemContent";
	},
	{
		isContainer:false,
		templatePath: null,
		templateCssPath: null,
		
		postCreate:function(){
			// summary: Parses content of widget and sets up the default state of any 
			// default selections / etc. The onSelect function will also be fired for any
			// default selections.
			this.parseStructure();
			dojo.html.addClass(this.domNode, this.groupCssClass);
			this.setupChildren();
			
			dojo.event.browser.addListener(this.domNode, "onclick", dojo.lang.hitch(this, "onSelect"));
			if (this.selectedItem){
				this.selectItem(this.selectedItem);
			}
		},
		
		parseStructure:function() {
			// summary: Sets local radioGroup and items properties, also validates
		    // that domNode contains an expected list.
		    // 
		    // Exception raised if a ul or ol node can't be found in this widgets domNode.
			if(this.domNode.tagName.toLowerCase() != "ul" 
				&& this.domNode.tagName.toLowerCase() != "ol") {
				dojo.raise("RadioGroup: Expected ul or ol content.");
				return;
			}
			
			this.items=[];	//	reset the items.
			var nl=this.domNode.getElementsByTagName("li");
			for (var i=0; i<nl.length; i++){
				if(nl[i].parentNode==this.domNode){
					this.items.push(nl[i]);
				}
			}
		},
		
		add:function(node){
			// summary: Allows the app to add a node on the fly, finishing up
		    // the setup so that we don't need to deal with it on a
		    // widget-wide basis.
			if(node.parentNode!=this.domNode){
				this.domNode.appendChild(node);
			}
			this.items.push(node);
			this.setup(node);
		},
		
		remove:function(node){
			// summary: Removes the specified node from this group, if it exists.
			var idx=-1;
			for(var i=0; i<this.items.length; i++){
				if(this.items[i]==node){
					idx=i;
					break;
				}
			}
			if(idx<0) {return;}
			this.items.splice(idx,1);
			node.parentNode.removeChild(node);
		},
		
		clear:function(){
			// summary: Removes all items in this list
			for(var i=0; i<this.items.length; i++){
				this.domNode.removeChild(this.items[i]);
			}
			this.items=[];
		},
		
		clearSelections:function(){
			// summary: Clears any selected items from being selected
			for(var i=0; i<this.items.length; i++){
				dojo.html.removeClass(this.items[i], this.selectedCssClass);
			}
			this.selectedItem=null;
		},
		
		setup:function(node){
			var span = document.createElement("span");
			dojo.html.disableSelection(span);
			dojo.html.addClass(span, this.itemContentCssClass);
			dojo.dom.moveChildren(node, span);
			node.appendChild(span);
			
			if (this.selected.length > 0) {
				var uid = dojo.html.getAttribute(node, "id");
				if (uid && uid == this.selected){
					this.selectedItem = node;
				}
			}
			dojo.event.browser.addListener(node, "onclick", dojo.lang.hitch(this, "onItemSelect"));
			if (dojo.html.hasAttribute(node, "onitemselect")) {
				var tn = dojo.lang.nameAnonFunc(new Function(dojo.html.getAttribute(node, "onitemselect")), 
												this);
				dojo.event.browser.addListener(node, "onclick", dojo.lang.hitch(this, tn));
			}
		},
		
		setupChildren:function(){
			for (var i=0; i<this.items.length; i++){
				this.setup(this.items[i]);
			}
		},
		
		selectItem:function(node, event, nofire){
			// summary: Sets the selectedItem to passed in node, applies
			// css selection class on new item
			if(this.selectedItem){
				dojo.html.removeClass(this.selectedItem, this.selectedCssClass);
			}
			
			this.selectedItem = node;
			dojo.html.addClass(this.selectedItem, this.selectedCssClass);
			
			// if this is the result of an event, stop here.
			if (!dj_undef("currentTarget", event)){
				return;
			}
			
			//	if there's no nofire flag, passed when this is nailed internally.
			if(!nofire){
				if(dojo.render.html.ie){
					this.selectedItem.fireEvent("onclick");
				}else{
					var e = document.createEvent("MouseEvents");
					e.initEvent("click", true, false);
					this.selectedItem.dispatchEvent(e);
				}
			}
		},
		
		getValue:function() {
			// summary: Gets the currently selected item, if any.
			return this.selectedItem; /*Node*/
		},
		
		onSelect:function(e) { 
			// summary: When the ul or ol contained by this widget is selected this function
			// is fired. A good function to listen to via dojo.event.connect. 
		},
		
		onItemSelect:function(e) {
			// summary: when an individual li is selected
			if (!dj_undef("currentTarget", e)){
				this.selectItem(e.currentTarget, e);
			}
		}
	}
);

__CPAN_FILE__ src/widget/Repeater.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Repeater");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.string");
dojo.require("dojo.event.*");
dojo.require("dojo.experimental");
dojo.experimental("dojo.widget.Repeater");

dojo.widget.defineWidget("dojo.widget.Repeater", dojo.widget.HtmlWidget,
	{
		name: "",
		rowTemplate: "",
		myObject: null,
		pattern: "",
		useDnd: false,
		isContainer: true,

		initialize: function(args,frag) {
			var node = this.getFragNodeRef(frag);
			node.removeAttribute("dojotype");
			this.setRow(dojo.string.trim(node.innerHTML), {});
			node.innerHTML="";
			frag=null;
		},

		postCreate: function(args,frag){
			if (this.useDnd) {
				dojo.require("dojo.dnd.*");
				var dnd = new dojo.dnd.HtmlDropTarget(this.domNode, [this.widgetId]);
			}
		},

		reIndexRows: function() {
			for(var i=0,len=this.domNode.childNodes.length; i<len;i++) {
				var elems = ["INPUT", "SELECT", "TEXTAREA"];
				for (var k=0; k < elems.length; k++) {
					var list = this.domNode.childNodes[i].getElementsByTagName(elems[k]);
					for (var j=0,len2=list.length; j<len2; j++) {
						var name = list[j].name;
						var index=dojo.string.escape("regexp", this.pattern);
						index = index.replace(/%\\{index\\}/g,"%{index}");
						var nameRegexp = dojo.string.substituteParams(index, {"index": "[0-9]*"});
						var newName= dojo.string.substituteParams(this.pattern, {"index": "" + i});
						var re=new RegExp(nameRegexp,"g");
						list[j].name = name.replace(re,newName);
					}
				}
			}
		},

		onDeleteRow: function(e) {
			var index=dojo.string.escape("regexp", this.pattern);
			index = index.replace(/%\\{index\\}/g,"%{index}");
			var nameRegexp = dojo.string.substituteParams(index, {"index": "([0-9]*)"});
			var re=new RegExp(nameRegexp,"g");
			this.deleteRow(re.exec(e.target.name)[1]);
		},
		hasRows: function() {
			if (this.domNode.childNodes.length > 0) {
				return true;
			}
			return false;
		},

		getRowCount: function() {
			return this.domNode.childNodes.length;
		},

		deleteRow: function(idx) {
			this.domNode.removeChild(this.domNode.childNodes[idx]);
			this.reIndexRows();
		},

		changeRowPosition: function(e) {
			if (e.dragStatus == "dropFailure") {
				this.domNode.removeChild(e["dragSource"].domNode);
			} else if (e.dragStatus == "dropSuccess") {
				//  nothing to do
			} // else-if
			this.reIndexRows();
		},
		setRow: function(template, myObject) {
			template = dojo.string.substituteParams(template, {"index": "0"});
			this.rowTemplate=template;
			this.myObject = myObject;
		},
		getRow: function() {
			return this.rowTemplate;
		},
		onAddRow: function(e) {
		},
		addRow: function() {
			var node = document.createElement('span');
			node.innerHTML=this.getRow();
			if (node.childNodes.length == 1) {
				node=node.childNodes[0];
			}
			this.domNode.appendChild(node);
			var parser = new dojo.xml.Parse();
			var frag = parser.parseElement(node, null, true);
			dojo.widget.getParser().createSubComponents(frag, this);
			var elems = ["INPUT", "SELECT", "IMG"];
			for (var k=0; k < elems.length; k++) {
				var list = node.getElementsByTagName(elems[k]);
				for(var i=0, len=list.length; i<len; i++) {
					var child = list[i];
					if(child.nodeType != 1) {continue};
					if (child.getAttribute("rowFunction") != null) {
						if(typeof(this.myObject[child.getAttribute("rowFunction")]) == "undefined") {
							dojo.debug("Function " + child.getAttribute("rowFunction") + " not found");
						} else { 
							this.myObject[child.getAttribute("rowFunction")](child);
						}
					} else if (child.getAttribute("rowAction") != null) {
						if(child.getAttribute("rowAction") == "delete") {
							child.name=dojo.string.substituteParams(this.pattern, {"index": "0"});
							dojo.event.connect(child, "onclick", this, "onDeleteRow");
						} // if
					} // else-if
				} // for
			} // for
			this.reIndexRows();
			if (this.useDnd) { // bind to DND
				node=new dojo.dnd.HtmlDragSource(node, this.widgetId);
				dojo.event.connect(node, "onDragEnd", this, "changeRowPosition");
			}
			this.onAddRow();
		}
});



__CPAN_FILE__ src/widget/DropdownContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DropdownContainer");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.PopupContainer");
dojo.require("dojo.event.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.display");
dojo.require("dojo.html.iframe");
dojo.require("dojo.html.util");

// summary:
//		dojo.widget.DropdownContainer provides an input box and a button for a dropdown.
//		In subclass, the dropdown can be specified.
dojo.widget.defineWidget(
	"dojo.widget.DropdownContainer",
	dojo.widget.HtmlWidget,
	{
		// String: width of the input box
		inputWidth: "7em",
		// String: id of this widget
		id: "",
		// String: id of the input box
		inputId: "",
		// String: name of the input box
		inputName: "",
		// dojo.uri.Uri: icon for the dropdown button
		iconURL: dojo.uri.dojoUri("src/widget/templates/images/combo_box_arrow.png"),
		// dojo.uri.Uri: alt text for the dropdown button icon
		iconAlt: "",

		inputNode: null,
		buttonNode: null,
		containerNode: null,

		// String: toggle property of the dropdown
		containerToggle: "plain",
		// Int: toggle duration property of the dropdown
		containerToggleDuration: 150,
		containerAnimInProgress: false,

		templateString: '<span style="white-space:nowrap"><input type="hidden" name="" value="" dojoAttachPoint="valueNode" /><input name="" type="text" value="" style="vertical-align:middle;" dojoAttachPoint="inputNode" autocomplete="off" /> <img src="${this.iconURL}" alt="${this.iconAlt}" dojoAttachEvent="onclick: onIconClick" dojoAttachPoint="buttonNode" style="vertical-align:middle; cursor:pointer; cursor:hand" /></span>',
		templateCssPath: "",

		fillInTemplate: function(args, frag){
			var source = this.getFragNodeRef(frag);

			this.popup = dojo.widget.createWidget("PopupContainer", {toggle: this.containerToggle, toggleDuration: this.containerToggleDuration});

			this.containerNode = this.popup.domNode;

			this.domNode.appendChild(this.popup.domNode);
			if(this.id) { this.domNode.id = this.id; }
			if(this.inputId){ this.inputNode.id = this.inputId; }
			if(this.inputName){ this.inputNode.name = this.inputName; }
			this.inputNode.style.width = this.inputWidth;

			dojo.event.connect(this.inputNode, "onchange", this, "onInputChange");
		},

		onIconClick: function(evt){
			if(!this.isEnabled) return;
			if(!this.popup.isShowingNow){
				this.popup.open(this.inputNode, this, this.buttonNode);
			}else{
				this.popup.close();
			}
		},

		hideContainer: function(){
			// summary: hide the dropdown
			if(this.popup.isShowingNow){
				this.popup.close();
			}
		},

		onInputChange: function(){
			// summary: signal for changes in the input box
		}
	}
);

__CPAN_FILE__ src/widget/validate.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.validate");

dojo.deprecated("dojo.widget.validate", 
	"use one of the specific widgets in dojo.widget.<name>Textbox instead", "0.5");

__CPAN_FILE__ src/widget/LinkPane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.LinkPane");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.html.style");

// summary
//	LinkPane is just a ContentPane that loads data remotely (via the href attribute),
//	and has markup similar to an anchor.  The anchor's body (the words between <a> and </a>)
//	become the label of the widget (used for TabContainer, AccordionContainer, etc.)
// usage
//	<a href="foo.html">my label</a>
dojo.widget.defineWidget(
	"dojo.widget.LinkPane",
	dojo.widget.ContentPane,
{
	// I'm using a template because the user may specify the input as
	// <a href="foo.html">label</a>, in which case we need to get rid of the
	// <a> because we don't want a link.
	templateString: '<div class="dojoLinkPane"></div>',

	fillInTemplate: function(args, frag){
		var source = this.getFragNodeRef(frag);

		// If user has specified node contents, they become the label
		// (the link must be plain text)
		this.label += source.innerHTML;

		var source = this.getFragNodeRef(frag);
		dojo.html.copyStyle(this.domNode, source);
	}
});

__CPAN_FILE__ src/widget/TreeV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
 * Tree model does all the drawing, visual node management etc.
 * Throws events about clicks on it, so someone may catch them and process
 * Tree knows nothing about DnD stuff, covered in TreeDragAndDrop and (if enabled) attached by controller
*/

/**
 * TODO: use domNode.cloneNode instead of createElement for grid
 * Should be faster (lyxsus)
 */
dojo.provide("dojo.widget.TreeV3");

dojo.require("dojo.widget.TreeWithNode");
dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeNodeV3");

dojo.widget.defineWidget(
	"dojo.widget.TreeV3",
	[dojo.widget.HtmlWidget, dojo.widget.TreeWithNode],
	function() {
		this.eventNames = {};
		
		this.DndAcceptTypes = [];
		this.actionsDisabled = [];
		
		this.listeners = [];
		
		this.tree = this;
	},
{
	DndMode: "",

	/**
	 * factory to generate default widgets
	 */
	defaultChildWidget: null,
	
	defaultChildTitle: "New Node", // for editing
	
	
	eagerWidgetInstantiation: false,
	
	eventNamesDefault: {

		// tree created.. Perform tree-wide actions if needed
		afterTreeCreate: "afterTreeCreate",
		beforeTreeDestroy: "beforeTreeDestroy",
		/* can't name it "beforeDestroy", because such name causes memleaks in IE */
		beforeNodeDestroy: "beforeNodeDestroy",
		afterChangeTree: "afterChangeTree",

		afterSetFolder: "afterSetFolder",
		afterUnsetFolder: "afterUnsetFolder",		
		beforeMoveFrom: "beforeMoveFrom",
		beforeMoveTo: "beforeMoveTo",
		afterMoveFrom: "afterMoveFrom",
		afterMoveTo: "afterMoveTo",
		afterAddChild: "afterAddChild",
		afterDetach: "afterDetach",
		afterExpand: "afterExpand",
		beforeExpand: "beforeExpand",
		afterSetTitle: "afterSetTitle",		
		afterCollapse: "afterCollapse",	
		beforeCollapse: "beforeCollapse"
	},

	classPrefix: "Tree",
	
	style: "",
	
	/**
	 * is it possible to add a new child to leaf ?
	 */	
	allowAddChildToLeaf: true,
	
	/**
	 * when last children is removed from node should it stop being a "folder" ?
	 */
	unsetFolderOnEmpty: true,


	DndModes: {
		BETWEEN: 1,
		ONTO: 2
	},

	DndAcceptTypes: "",

    // will have cssRoot before it 
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TreeV3.css"),

	templateString: '<div style="${this.style}">\n</div>',

	isExpanded: true, // consider this "root node" to be always expanded

	isTree: true,
	
	

	createNode: function(data) {
			
		data.tree = this.widgetId;		
		
		if (data.widgetName) {
			// TODO: check if such widget has createSimple			
			return dojo.widget.createWidget(data.widgetName, data);		
		} else if (this.defaultChildWidget.prototype.createSimple) {			
			return this.defaultChildWidget.prototype.createSimple(data);					
		} else {
			var ns = this.defaultChildWidget.prototype.ns; 
			var wt = this.defaultChildWidget.prototype.widgetType; 

			return dojo.widget.createWidget(ns + ":" + wt, data); 
		}
 	    	
	},
				

	// expandNode has +- CSS background. Not img.src for performance, background src string resides in single place.
	// selection in KHTML/Mozilla disabled treewide, IE requires unselectable for every node
	// you can add unselectable if you want both in postCreate of tree and in this template

	// create new template and put into prototype
	makeNodeTemplate: function() {
		
		var domNode = document.createElement("div");
		dojo.html.setClass(domNode, this.classPrefix+"Node "+this.classPrefix+"ExpandLeaf "+this.classPrefix+"ChildrenNo");		
		this.nodeTemplate = domNode;
		
		var expandNode = document.createElement("div");
		var clazz = this.classPrefix+"Expand";
		if (dojo.render.html.ie) {
			clazz = clazz + ' ' + this.classPrefix+"IEExpand";
		}
		dojo.html.setClass(expandNode, clazz);
		
		this.expandNodeTemplate = expandNode;

		// need <span> inside <div>
		// div for multiline support, span for styling exactly the text, not whole line
		var labelNode = document.createElement("span");
		dojo.html.setClass(labelNode, this.classPrefix+"Label");
		this.labelNodeTemplate = labelNode;
		
		var contentNode = document.createElement("div");
		var clazz = this.classPrefix+"Content";
		
		/**
		 * IE does not support min-height properly so I have to rely
		 * on this hack
		 * FIXME: do it in CSS only, remove iconHeight from code
		 */
		if (dojo.render.html.ie) {
			clazz = clazz + ' ' + this.classPrefix+"IEContent";
		}	
		
				
		dojo.html.setClass(contentNode, clazz);
		
		this.contentNodeTemplate = contentNode;
		
		domNode.appendChild(expandNode);
		domNode.appendChild(contentNode);
		contentNode.appendChild(labelNode);
		
		
	},

	makeContainerNodeTemplate: function() {
		
		var div = document.createElement('div');
		div.style.display = 'none';			
		dojo.html.setClass(div, this.classPrefix+"Container");
		
		this.containerNodeTemplate = div;
		
	},

	
	actions: {
    	ADDCHILD: "ADDCHILD"
	},


	getInfo: function() {
		var info = {
			widgetId: this.widgetId,
			objectId: this.objectId
		}

		return info;
	},

	adjustEventNames: function() {
		
		for(var name in this.eventNamesDefault) {
			if (dojo.lang.isUndefined(this.eventNames[name])) {
				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
			}
		}
	},

	
	adjustDndMode: function() {
		var _this = this;
		
		
		var DndMode = 0;
		dojo.lang.forEach(this.DndMode.split(';'),
			function(elem) {
				var mode = _this.DndModes[dojo.string.trim(elem).toUpperCase()];
				if (mode) DndMode = DndMode | mode;
			}
		 );
	
		
		this.DndMode = DndMode;

	},
	
	/**
	 * publish destruction event so that any listeners should stop listening
	 */
	destroy: function() {
		dojo.event.topic.publish(this.tree.eventNames.beforeTreeDestroy, { source: this } );

		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
	},

	initialize: function(args){
		
		this.domNode.widgetId = this.widgetId;
		
		for(var i=0; i<this.actionsDisabled.length;i++) {
			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
		}
		
		//dojo.debug(args.defaultChildWidget ? true : false)
		
		if (!args.defaultChildWidget) {
			this.defaultChildWidget = dojo.widget.TreeNodeV3;
		} else {
			this.defaultChildWidget = dojo.lang.getObjPathValue(args.defaultChildWidget);
		}
		
		this.adjustEventNames();
		this.adjustDndMode();

		this.makeNodeTemplate();
		this.makeContainerNodeTemplate();
		
		this.containerNode = this.domNode;
		
		dojo.html.setClass(this.domNode, this.classPrefix+"Container");
		
		var _this = this;
			
		//dojo.html.disableSelection(this.domNode)
				
		dojo.lang.forEach(this.listeners,
			function(elem) {
				var t = dojo.lang.isString(elem) ? dojo.widget.byId(elem) : elem;
				t.listenTree(_this)				
			}
		);
		

		
		

	},

	
	postCreate: function() {						
		dojo.event.topic.publish(this.eventNames.afterTreeCreate, { source: this } );
	},
	
	
	/**
	 * Move child to newParent as last child
	 * redraw tree and update icons.
	 *
	 * Called by target, saves source in event.
	 * events are published for BOTH trees AFTER update.
	*/
	move: function(child, newParent, index) {
		
		if (!child.parent) {
			dojo.raise(this.widgetType+": child can be moved only while it's attached");
		}
		
		var oldParent = child.parent;
		var oldTree = child.tree;
		var oldIndex = child.getParentIndex();
		var newTree = newParent.tree;
		var newParent = newParent;
		var newIndex = index;

		var message = {
				oldParent: oldParent, oldTree: oldTree, oldIndex: oldIndex,
				newParent: newParent, newTree: newTree, newIndex: newIndex,
				child: child
		};

		dojo.event.topic.publish(oldTree.eventNames.beforeMoveFrom, message);
		dojo.event.topic.publish(newTree.eventNames.beforeMoveTo, message);
		
		this.doMove.apply(this, arguments);

		
		/* publish events here about structural changes for both source and target trees */
		dojo.event.topic.publish(oldTree.eventNames.afterMoveFrom, message);
		dojo.event.topic.publish(newTree.eventNames.afterMoveTo, message);

	},


	/* do actual parent change here. Write remove child first */
	doMove: function(child, newParent, index) {
		//dojo.debug("MOVE "+child+" to "+newParent+" at "+index);

		//var parent = child.parent;
		child.doDetach();

		//dojo.debug("addChild "+child+" to "+newParent+" at "+index);

		newParent.doAddChild(child, index);
	},

	toString: function() {
		return "["+this.widgetType+" ID:"+this.widgetId	+"]"
	}

});

__CPAN_FILE__ src/widget/ResizableTextarea.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ResizableTextarea");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.LayoutContainer");
dojo.require("dojo.widget.ResizeHandle");

dojo.widget.defineWidget(
	"dojo.widget.ResizableTextarea",
	dojo.widget.HtmlWidget,
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/ResizableTextarea.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/ResizableTextarea.css"),
	isContainer: false,
	textAreaNode: null,
	textAreaContainer: null,
	textAreaContainerNode: null,
	statusBar: null,
	statusBarContainerNode: null,
	statusLabelNode: null,
	statusLabel: null,
	rootLayoutNode: null,
	resizeHandleNode: null,
	resizeHandle: null,

	fillInTemplate: function(args, frag){
		this.textAreaNode = this.getFragNodeRef(frag).cloneNode(true);

		// FIXME: Safari apparently needs this!
		dojo.body().appendChild(this.domNode);

		this.rootLayout = dojo.widget.createWidget(
			"LayoutContainer",
			{
				minHeight: 50,
				minWidth: 100
			},
			this.rootLayoutNode
		);


		this.textAreaContainer = dojo.widget.createWidget(
			"LayoutContainer",
			{ layoutAlign: "client" },
			this.textAreaContainerNode
		);
		this.rootLayout.addChild(this.textAreaContainer);

		this.textAreaContainer.domNode.appendChild(this.textAreaNode);
		with(this.textAreaNode.style){
			width="100%";
			height="100%";
		}

		this.statusBar = dojo.widget.createWidget(
			"LayoutContainer",
			{ 
				layoutAlign: "bottom", 
				minHeight: 28
			},
			this.statusBarContainerNode
		);
		this.rootLayout.addChild(this.statusBar);

		this.statusLabel = dojo.widget.createWidget(
			"LayoutContainer",
			{ 
				layoutAlign: "client", 
				minWidth: 50
			},
			this.statusLabelNode
		);
		this.statusBar.addChild(this.statusLabel);

		this.resizeHandle = dojo.widget.createWidget(
			"ResizeHandle", 
			{ targetElmId: this.rootLayout.widgetId },
			this.resizeHandleNode
		);
		this.statusBar.addChild(this.resizeHandle);
		// dojo.debug(this.rootLayout.widgetId);

		// dojo.event.connect(this.resizeHandle, "beginSizing", this, "hideContent");
		// dojo.event.connect(this.resizeHandle, "endSizing", this, "showContent");
	},

	hideContent: function(){
		this.textAreaNode.style.display = "none";
	},

	showContent: function(){
		this.textAreaNode.style.display = "";
	}
});

__CPAN_FILE__ src/widget/DomWidget.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DomWidget");

dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.Widget");
dojo.require("dojo.dom");
dojo.require("dojo.html.style");
dojo.require("dojo.xml.Parse");
dojo.require("dojo.uri.*");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.extras");

dojo.widget._cssFiles = {};
dojo.widget._cssStrings = {};
dojo.widget._templateCache = {};

// Object: a mapping of strings that are used in template variable replacement
dojo.widget.defaultStrings = {
	dojoRoot: dojo.hostenv.getBaseScriptUri(),
	baseScriptUri: dojo.hostenv.getBaseScriptUri()
};

dojo.widget.fillFromTemplateCache = function(	/*DomWidget*/				obj, 
												/*String||dojo.uri.Uri*/	templatePath,
												/*String, optional*/		templateString,
												/*Boolean, optional*/		avoidCache){
	// summary:
	//		static method to build from a template w/ or w/o a real widget in
	//		place
	// obj: an instance of dojo.widget.DomWidget to initialize the template for
	// templatePath: the URL to get the template from	
	// templateString:
	//		a string to use in lieu of fetching the template from a URL
	// avoidCache:
	//		should the template system not use whatever is in the cache and
	//		always use the passed templatePath or templateString?

	// dojo.debug("avoidCache:", avoidCache);
	var tpath = templatePath || obj.templatePath;

	var tmplts = dojo.widget._templateCache;
	if(!obj["widgetType"]) { // don't have a real template here
		do {
			var dummyName = "__dummyTemplate__" + dojo.widget._templateCache.dummyCount++;
		} while(tmplts[dummyName]);
		obj.widgetType = dummyName;
	}
	var wt = obj.widgetType;

	var ts = tmplts[wt];
	if(!ts){
		tmplts[wt] = { "string": null, "node": null };
		if(avoidCache){
			ts = {};
		}else{
			ts = tmplts[wt];
		}
	}
	if((!obj.templateString)&&(!avoidCache)){
		obj.templateString = templateString || ts["string"];
	}
	if((!obj.templateNode)&&(!avoidCache)){
		obj.templateNode = ts["node"];
	}
	if((!obj.templateNode)&&(!obj.templateString)&&(tpath)){
		// fetch a text fragment and assign it to templateString
		// NOTE: we rely on blocking IO here!
		var tstring = dojo.hostenv.getText(tpath);
		if(tstring){
			// strip <?xml ...?> declarations so that external SVG and XML
			// documents can be added to a document without worry
			tstring = tstring.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
			var matches = tstring.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
			if(matches){
				tstring = matches[1];
			}
		}else{
			tstring = "";
		}
		obj.templateString = tstring;
		if(!avoidCache){
			tmplts[wt]["string"] = tstring;
		}
	}
	if((!ts["string"])&&(!avoidCache)){
		ts.string = obj.templateString;
	}
}
dojo.widget._templateCache.dummyCount = 0;

// Array: list of properties to search for node-to-property mappings
dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
// String: name of the property to use for mapping DOM events to widget functions
dojo.widget.eventAttachProperty = "dojoAttachEvent";
// String: property name of code to evaluate when the widget is constructed
dojo.widget.onBuildProperty = "dojoOnBuild";
// Array:  possible accessibility values to set on widget elements - role or state
dojo.widget.waiNames  = ["waiRole", "waiState"];
// Object: Contains functions to set accessibility roles and states 
// 	onto widget elements
dojo.widget.wai = {
	waiRole: { 	
				// String: information for mapping accessibility role
				name: "waiRole", 
				// String: URI of the namespace for the set of roles
				"namespace": "http://www.w3.org/TR/xhtml2", 
				// String: alias to assign the namespace
				alias: "x2",
				// String: prefix to assign to the role value
				prefix: "wairole:"
	},
	waiState: { 
				// String: informatin for mapping accessibility state
				name: "waiState", 
				// String: URI of the namespace for the set of states
				"namespace": "http://www.w3.org/2005/07/aaa", 
				// String: alias to assign the namespace
				alias: "aaa",
				// String: empty string - state value does not require prefix
				prefix: ""
	},
	setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
		// Summary: Use appropriate API to set the role or state attribute onto the element.
		// Description: In IE use the generic setAttribute() api.  Append a namespace
		//   alias to the attribute name and appropriate prefix to the value. 
		//   Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
		//   add the appropriate prefix to the attribute value.
		if(dojo.render.html.ie){
			node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
		}else{
			node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
		}
	},

	getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
		// Summary:  Use the appropriate API to retrieve the role or state value
		// Description: In IE use the generic getAttribute() api.  An alias value 
		// 	was added to the attribute name to simulate a namespace when the attribute
		//  was set.  Otherwise use the getAttributeNS() api to retrieve the state value
		if(dojo.render.html.ie){
			return node.getAttribute(this[ns].alias+":"+attr);
		}else{
			return node.getAttributeNS(this[ns]["namespace"], attr);
		}
	},
	removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
		// Summary:  Use the appropriate API to remove the role or state value
		// Description: In IE use the generic removeAttribute() api.  An alias value 
		// 	was added to the attribute name to simulate a namespace when the attribute
		//  was set.  Otherwise use the removeAttributeNS() api to remove the state value
		var success = true; //only IE returns a value
		if(dojo.render.html.ie){
			 success = node.removeAttribute(this[ns].alias+":"+attr);
		}else{
			node.removeAttributeNS(this[ns]["namespace"], attr);
		}
		return success;
	}
};

dojo.widget.attachTemplateNodes = function(	/*DomNode*/		rootNode, 
											/*Widget*/		targetObj, 
											/*Array*/		events ){
	// summary:
	//		map widget properties and functions to the handlers specified in
	//		the dom node and it's descendants. This function iterates over all
	//		nodes and looks for these properties:
	//			* dojoAttachPoint
	//			* dojoAttachEvent	
	//			* waiRole
	//			* waiState
	//			* any "dojoOn*" proprties passed in the events array
	// rootNode:
	//		the node to search for properties. All children will be searched.
	// events: a list of properties generated from getDojoEventsFromStr.

	// FIXME: this method is still taking WAAAY too long. We need ways of optimizing:
	//	a.) what we are looking for on each node
	//	b.) the nodes that are subject to interrogation (use xpath instead?)
	//	c.) how expensive event assignment is (less eval(), more connect())
	// var start = new Date();
	var elementNodeType = dojo.dom.ELEMENT_NODE;

	function trim(str){
		return str.replace(/^\s+|\s+$/g, "");
	}

	if(!rootNode){ 
		rootNode = targetObj.domNode;
	}

	if(rootNode.nodeType != elementNodeType){
		return;
	}
	// alert(events.length);

	var nodes = rootNode.all || rootNode.getElementsByTagName("*");
	var _this = targetObj;
	for(var x=-1; x<nodes.length; x++){
		var baseNode = (x == -1) ? rootNode : nodes[x];
		// FIXME: is this going to have capitalization problems?  Could use getAttribute(name, 0); to get attributes case-insensitve
		var attachPoint = [];
		if(!targetObj.widgetsInTemplate || !baseNode.getAttribute('dojoType')){
			for(var y=0; y<this.attachProperties.length; y++){
				var tmpAttachPoint = baseNode.getAttribute(this.attachProperties[y]);
				if(tmpAttachPoint){
					attachPoint = tmpAttachPoint.split(";");
					for(var z=0; z<attachPoint.length; z++){
						if(dojo.lang.isArray(targetObj[attachPoint[z]])){
							targetObj[attachPoint[z]].push(baseNode);
						}else{
							targetObj[attachPoint[z]]=baseNode;
						}
					}
					break;
				}
			}

			var attachEvent = baseNode.getAttribute(this.eventAttachProperty);
			if(attachEvent){
				// NOTE: we want to support attributes that have the form
				// "domEvent: nativeEvent; ..."
				var evts = attachEvent.split(";");
				for(var y=0; y<evts.length; y++){
					if((!evts[y])||(!evts[y].length)){ continue; }
					var thisFunc = null;
					var tevt = trim(evts[y]);
					if(evts[y].indexOf(":") >= 0){
						// oh, if only JS had tuple assignment
						var funcNameArr = tevt.split(":");
						tevt = trim(funcNameArr[0]);
						thisFunc = trim(funcNameArr[1]);
					}
					if(!thisFunc){
						thisFunc = tevt;
					}
	
					var tf = function(){ 
						var ntf = new String(thisFunc);
						return function(evt){
							if(_this[ntf]){
								_this[ntf](dojo.event.browser.fixEvent(evt, this));
							}
						};
					}();
					dojo.event.browser.addListener(baseNode, tevt, tf, false, true);
					// dojo.event.browser.addListener(baseNode, tevt, dojo.lang.hitch(_this, thisFunc));
				}
			}
	
			for(var y=0; y<events.length; y++){
				//alert(events[x]);
				var evtVal = baseNode.getAttribute(events[y]);
				if((evtVal)&&(evtVal.length)){
					var thisFunc = null;
					var domEvt = events[y].substr(4); // clober the "dojo" prefix
					thisFunc = trim(evtVal);
					var funcs = [thisFunc];
					if(thisFunc.indexOf(";")>=0){
						funcs = dojo.lang.map(thisFunc.split(";"), trim);
					}
					for(var z=0; z<funcs.length; z++){
						if(!funcs[z].length){ continue; }
						var tf = function(){ 
							var ntf = new String(funcs[z]);
							return function(evt){
								if(_this[ntf]){
									_this[ntf](dojo.event.browser.fixEvent(evt, this));
								}
							}
						}();
						dojo.event.browser.addListener(baseNode, domEvt, tf, false, true);
						// dojo.event.browser.addListener(baseNode, domEvt, dojo.lang.hitch(_this, funcs[z]));
					}
				}
			}
		}
		// continue;

		// FIXME: we need to put this into some kind of lookup structure
		// instead of direct assignment
		var tmpltPoint = baseNode.getAttribute(this.templateProperty);
		if(tmpltPoint){
			targetObj[tmpltPoint]=baseNode;
		}

		dojo.lang.forEach(dojo.widget.waiNames, function(name){
			var wai = dojo.widget.wai[name];
			var val = baseNode.getAttribute(wai.name);
			if(val){
				if(val.indexOf('-') == -1){ 
					dojo.widget.wai.setAttr(baseNode, wai.name, "role", val);
				}else{
					// this is a state-value pair
					var statePair = val.split('-');
					dojo.widget.wai.setAttr(baseNode, wai.name, statePair[0], statePair[1]);
				}
			}
		}, this);

		var onBuild = baseNode.getAttribute(this.onBuildProperty);
		if(onBuild){
			eval("var node = baseNode; var widget = targetObj; "+onBuild);
		}
	}

}

dojo.widget.getDojoEventsFromStr = function(/*String*/str){
	// summary:
	//		generates a list of properties with names that match the form
	//		dojoOn*
	// str: the template string to search
	
	// var lstr = str.toLowerCase();
	var re = /(dojoOn([a-z]+)(\s?))=/gi;
	var evts = str ? str.match(re)||[] : [];
	var ret = [];
	var lem = {};
	for(var x=0; x<evts.length; x++){
		if(evts[x].length < 1){ continue; }
		var cm = evts[x].replace(/\s/, "");
		cm = (cm.slice(0, cm.length-1));
		if(!lem[cm]){
			lem[cm] = true;
			ret.push(cm);
		}
	}
	return ret; // Array
}

/*
dojo.widget.buildAndAttachTemplate = function(obj, templatePath, templateCssPath, templateString, targetObj) {
	this.buildFromTemplate(obj, templatePath, templateCssPath, templateString);
	var node = dojo.dom.createNodesFromText(obj.templateString, true)[0];
	this.attachTemplateNodes(node, targetObj||obj, dojo.widget.getDojoEventsFromStr(templateString));
	return node;
}
*/


// summary:
//		dojo.widget.DomWidget is the superclass that provides behavior for all
//		DOM-based renderers, including HtmlWidget and SvgWidget. DomWidget
//		implements the templating system that most widget authors use to define
//		the UI for their widgets.
dojo.declare("dojo.widget.DomWidget", 
	dojo.widget.Widget,
	function(){
		if((arguments.length>0)&&(typeof arguments[0] == "object")){
			this.create(arguments[0]);
		}
	},
	{							 
		// DomNode: a node that represents the widget template. Pre-empts both templateString and templatePath.
		templateNode: null,

		// String:
		//		a string that represents the widget template. Pre-empts the
		//		templatePath. In builds that have their strings "interned", the
		//		templatePath is converted to an inline templateString, thereby
		//		preventing a synchronous network call.
		templateString: null,

		// String:
		//		a string that represents the CSS for the widgettemplate.
		//		Pre-empts the templateCssPath. In builds that have their
		//		strings "interned", the templateCssPath is converted to an
		//		inline templateCssString, thereby preventing a synchronous
		//		network call.
		templateCssString: null,

		// Boolean:
		//		should the widget not replace the node from which it was
		//		constructed? Widgets that apply behaviors to pre-existing parts
		//		of a page can be implemented easily by setting this to "true".
		//		In these cases, the domNode property will point to the node
		//		which the widget was created from.
		preventClobber: false,

		// DomNode:
		//		this is our visible representation of the widget! Other DOM
		//		Nodes may by assigned to other properties, usually through the
		//		template system's dojoAttachPonit syntax, but the domNode
		//		property is the canonical "top level" node in widget UI.
		domNode: null, 

		// DomNode:
		//		holds child elements. "containerNode" is generally set via a
		//		dojoAttachPoint assignment and it designates where widgets that
		//		are defined as "children" of the parent will be placed
		//		visually.
		containerNode: null,

		// Boolean:
		//		should we parse the template to find widgets that might be
		//		declared in markup inside it? false by default.
		widgetsInTemplate: false,

		addChild: function(	/*Widget*/				widget, 
							/*DomNode, optional*/	overrideContainerNode, 
							/*String, optional*/	pos, 
							/*DomNode, optional*/	ref,
							/*int, optional*/		insertIndex){
			// summary:
			//		Process the given child widget, inserting it's dom node as
			//		a child of our dom node
			// overrideContainerNode: a non-default container node for the widget
			// pos:
			//		can be one of "before", "after", "first", or "last". This
			//		has the same meaning as in dojo.dom.insertAtPosition()
			// ref: a node to place the widget relative to
			// insertIndex: DOM index, same meaning as in dojo.dom.insertAtIndex()

			// FIXME: should we support addition at an index in the children arr and
			// order the display accordingly? Right now we always append.
			if(!this.isContainer){ // we aren't allowed to contain other widgets, it seems
				dojo.debug("dojo.widget.DomWidget.addChild() attempted on non-container widget");
				return null;
			}else{
				if(insertIndex == undefined){
					insertIndex = this.children.length;
				}
				this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
				this.registerChild(widget, insertIndex);
			}
			return widget; // Widget: the widget that was inserted
		},
		
		addWidgetAsDirectChild: function(	/*Widget*/				widget, 
											/*DomNode*/				overrideContainerNode, 
											/*String, optional*/	pos, 
											/*DomNode, optional*/	ref, 
											/*int, optional*/		insertIndex){
			// summary:
			//		Process the given child widget, inserting it's dom node as
			//		a child of our dom node
			// overrideContainerNode: a non-default container node for the widget
			// pos:
			//		can be one of "before", "after", "first", or "last". This
			//		has the same meaning as in dojo.dom.insertAtPosition()
			// ref: a node to place the widget relative to
			// insertIndex: DOM index, same meaning as in dojo.dom.insertAtIndex()
			if((!this.containerNode)&&(!overrideContainerNode)){
				this.containerNode = this.domNode;
			}
			var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
			if(!pos){ pos = "after"; }
			if(!ref){ 
				if(!cn){ cn = dojo.body(); }
				ref = cn.lastChild; 
			}
			if(!insertIndex) { insertIndex = 0; }
			widget.domNode.setAttribute("dojoinsertionindex", insertIndex);

			// insert the child widget domNode directly underneath my domNode, in the
			// specified position (by default, append to end)
			if(!ref){
				cn.appendChild(widget.domNode);
			}else{
				// FIXME: was this meant to be the (ugly hack) way to support insert @ index?
				//dojo.dom[pos](widget.domNode, ref, insertIndex);

				// CAL: this appears to be the intended way to insert a node at a given position...
				if (pos == 'insertAtIndex'){
					// dojo.debug("idx:", insertIndex, "isLast:", ref === cn.lastChild);
					dojo.dom.insertAtIndex(widget.domNode, ref.parentNode, insertIndex);
				}else{
					// dojo.debug("pos:", pos, "isLast:", ref === cn.lastChild);
					if((pos == "after")&&(ref === cn.lastChild)){
						cn.appendChild(widget.domNode);
					}else{
						dojo.dom.insertAtPosition(widget.domNode, cn, pos);
					}
				}
			}
		},

		registerChild: function(/*Widget*/widget, /*int*/insertionIndex){
			// summary: record that given widget descends from me
			// widget: the widget that is now a child
			// inesrtionIndex: where in the children[] array to place it

			// we need to insert the child at the right point in the parent's 
			// 'children' array, based on the insertionIndex

			widget.dojoInsertionIndex = insertionIndex;

			var idx = -1;
			for(var i=0; i<this.children.length; i++){

				//This appears to fix an out of order issue in the case of mixed
				//markup and programmatically added children.  Previously, if a child
				//existed from markup, and another child was addChild()d without specifying
				//any additional parameters, it would end up first in the list, when in fact
				//it should be after.  I can't see cases where this would break things, but
				//I could see no other obvious solution. -dustin

				if (this.children[i].dojoInsertionIndex <= insertionIndex){
					idx = i;
				}
			}

			this.children.splice(idx+1, 0, widget);

			widget.parent = this;
			widget.addedTo(this, idx+1);
			
			// If this widget was created programatically, then it was erroneously added
			// to dojo.widget.manager.topWidgets.  Fix that here.
			delete dojo.widget.manager.topWidgets[widget.widgetId];
		},

		removeChild: function(/*Widget*/widget){
			// summary: detach child domNode from parent domNode
			dojo.dom.removeNode(widget.domNode);

			// remove child widget from parent widget 
			return dojo.widget.DomWidget.superclass.removeChild.call(this, widget); // Widget
		},

		getFragNodeRef: function(/*Object*/frag){
			// summary:
			//		returns the source node, if any, that the widget was
			//		declared from
			// frag:
			//		an opaque data structure generated by the first-pass parser
			if(!frag){return null;} // null
			if(!frag[this.getNamespacedType()]){
				dojo.raise("Error: no frag for widget type " + this.getNamespacedType() 
					+ ", id " + this.widgetId
					+ " (maybe a widget has set it's type incorrectly)");
			}
			return frag[this.getNamespacedType()]["nodeRef"]; // DomNode
		},
		
		postInitialize: function(/*Object*/args, /*Object*/frag, /*Widget*/parentComp){
			// summary:
			//		Replace the source domNode with the generated dom
			//		structure, and register the widget with its parent.
			//		This is an implementation of the stub function defined in
			//		dojo.widget.Widget.
			
			//dojo.profile.start(this.widgetType + " postInitialize");
			
			var sourceNodeRef = this.getFragNodeRef(frag);
			// Stick my generated dom into the output tree
			//alert(this.widgetId + ": replacing " + sourceNodeRef + " with " + this.domNode.innerHTML);
			if (parentComp && (parentComp.snarfChildDomOutput || !sourceNodeRef)){
				// Add my generated dom as a direct child of my parent widget
				// This is important for generated widgets, and also cases where I am generating an
				// <li> node that can't be inserted back into the original DOM tree
				parentComp.addWidgetAsDirectChild(this, "", "insertAtIndex", "",  args["dojoinsertionindex"], sourceNodeRef);
			} else if (sourceNodeRef){
				// Do in-place replacement of the my source node with my generated dom
				if(this.domNode && (this.domNode !== sourceNodeRef)){
					var oldNode = sourceNodeRef.parentNode.replaceChild(this.domNode, sourceNodeRef);
				}
			}

			// Register myself with my parent, or with the widget manager if
			// I have no parent
			// TODO: the code below erroneously adds all programatically generated widgets
			// to topWidgets (since we don't know who the parent is until after creation finishes)
			if ( parentComp ) {
				parentComp.registerChild(this, args.dojoinsertionindex);
			} else {
				dojo.widget.manager.topWidgets[this.widgetId]=this;
			}

			if(this.widgetsInTemplate){
				var parser = new dojo.xml.Parse();

				var subContainerNode;
				//TODO: use xpath here?
				var subnodes = this.domNode.getElementsByTagName("*");
				for(var i=0;i<subnodes.length;i++){
					if(subnodes[i].getAttribute('dojoAttachPoint') == 'subContainerWidget'){
						subContainerNode = subnodes[i];
//						break;
					}
					if(subnodes[i].getAttribute('dojoType')){
						subnodes[i].setAttribute('_isSubWidget', true);
					}
				}
				if (this.isContainer && !this.containerNode){
					//no containerNode is available, which means a widget is used as a container. find it here and move
					//all dom nodes defined in the main html page as children of this.domNode into the actual container
					//widget's node (at this point, the subwidgets defined in the template file is not parsed yet)
					if(subContainerNode){
						var src = this.getFragNodeRef(frag);
						if (src){
							dojo.dom.moveChildren(src, subContainerNode);
							//do not need to follow children nodes in the main html page, as they
							//will be dealt with in the subContainerWidget
							frag['dojoDontFollow'] = true;
						}
					}else{
						dojo.debug("No subContainerWidget node can be found in template file for widget "+this);
					}
				}

				var templatefrag = parser.parseElement(this.domNode, null, true);
				// createSubComponents not createComponents because frag has already been created
				dojo.widget.getParser().createSubComponents(templatefrag, this);
	
				//find all the sub widgets defined in the template file of this widget
				var subwidgets = [];
				var stack = [this];
				var w;
				while((w = stack.pop())){
					for(var i = 0; i < w.children.length; i++){
						var cwidget = w.children[i];
						if(cwidget._processedSubWidgets || !cwidget.extraArgs['_issubwidget']){ continue; }
						subwidgets.push(cwidget);
						if(cwidget.isContainer){
							stack.push(cwidget);
						}
					}
				}
	
				//connect event to this widget/attach dom node
				for(var i = 0; i < subwidgets.length; i++){
					var widget = subwidgets[i];
					if(widget._processedSubWidgets){
						dojo.debug("This should not happen: widget._processedSubWidgets is already true!");
						return;
					}
					widget._processedSubWidgets = true;
					if(widget.extraArgs['dojoattachevent']){
						var evts = widget.extraArgs['dojoattachevent'].split(";");
						for(var j=0; j<evts.length; j++){
							var thisFunc = null;
							var tevt = dojo.string.trim(evts[j]);
							if(tevt.indexOf(":") >= 0){
								// oh, if only JS had tuple assignment
								var funcNameArr = tevt.split(":");
								tevt = dojo.string.trim(funcNameArr[0]);
								thisFunc = dojo.string.trim(funcNameArr[1]);
							}
							if(!thisFunc){
								thisFunc = tevt;
							}
							if(dojo.lang.isFunction(widget[tevt])){
								dojo.event.kwConnect({
									srcObj: widget, 
									srcFunc: tevt, 
									targetObj: this, 
									targetFunc: thisFunc
								});
							}else{
								alert(tevt+" is not a function in widget "+widget);
							}
						}
					}
	
					if(widget.extraArgs['dojoattachpoint']){
						//don't attach widget.domNode here, as we do not know which
						//dom node we should connect to (in checkbox widget case, 
						//it is inputNode). So we make the widget itself available
						this[widget.extraArgs['dojoattachpoint']] = widget;
					}
				}
			}

			//dojo.profile.end(this.widgetType + " postInitialize");

			// Expand my children widgets
			/* dojoDontFollow is important for a very special case
			 * basically if you have a widget that you instantiate from script
			 * and that widget is a container, and it contains a reference to a parent
			 * instance, the parser will start recursively parsing until the browser
			 * complains.  So the solution is to set an initialization property of 
			 * dojoDontFollow: true and then it won't recurse where it shouldn't
			 */
			if(this.isContainer && !frag["dojoDontFollow"]){
				//alert("recurse from " + this.widgetId);
				// build any sub-components with us as the parent
				dojo.widget.getParser().createSubComponents(frag, this);
			}
		},

		// method over-ride
		buildRendering: function(/*Object*/args, /*Object*/frag){
			// summary:
			//		Construct the UI for this widget, generally from a
			//		template. This can be over-ridden for custom UI creation to
			//		to side-step the template system.  This is an
			//		implementation of the stub function defined in
			//		dojo.widget.Widget.

			// DOM widgets construct themselves from a template
			var ts = dojo.widget._templateCache[this.widgetType];
			
			// Handle style for this widget here, as even if templatePath
			// is not set, style specified by templateCssString or templateCssPath
			// should be applied. templateCssString has higher priority
			// than templateCssPath
			if(args["templatecsspath"]){
				args["templateCssPath"] = args["templatecsspath"];
			}
			var cpath = args["templateCssPath"] || this.templateCssPath;
			if(cpath && !dojo.widget._cssFiles[cpath.toString()]){
				if((!this.templateCssString)&&(cpath)){
					this.templateCssString = dojo.hostenv.getText(cpath);
					this.templateCssPath = null;
				}
				dojo.widget._cssFiles[cpath.toString()] = true;
			}
		
			if((this["templateCssString"])&&(!this.templateCssString["loaded"])){
				dojo.html.insertCssText(this.templateCssString, null, cpath);
				if(!this.templateCssString){ this.templateCssString = ""; }
				this.templateCssString.loaded = true;
			}
			if(	
				(!this.preventClobber)&&(
					(this.templatePath)||
					(this.templateNode)||
					(
						(this["templateString"])&&(this.templateString.length) 
					)||
					(
						(typeof ts != "undefined")&&( (ts["string"])||(ts["node"]) )
					)
				)
			){
				// if it looks like we can build the thing from a template, do it!
				this.buildFromTemplate(args, frag);
			}else{
				// otherwise, assign the DOM node that was the source of the widget
				// parsing to be the root node
				this.domNode = this.getFragNodeRef(frag);
			}
			this.fillInTemplate(args, frag); 	// this is where individual widgets
												// will handle population of data
												// from properties, remote data
												// sets, etc.
	},

		buildFromTemplate: function(/*Object*/args, /*Object*/frag){
			// summary:
			//		Called by buildRendering, creates the actual UI in a DomWidget.

			// var start = new Date();
			// copy template properties if they're already set in the templates object
			// dojo.debug("buildFromTemplate:", this);
			var avoidCache = false;
			if(args["templatepath"]){
				avoidCache = true;
				args["templatePath"] = args["templatepath"];
			}
			dojo.widget.fillFromTemplateCache(	this, 
												args["templatePath"], 
												null,
												avoidCache);
			var ts = dojo.widget._templateCache[this.widgetType];
			if((ts)&&(!avoidCache)){
				if(!this.templateString.length){
					this.templateString = ts["string"];
				}
				if(!this.templateNode){
					this.templateNode = ts["node"];
				}
			}
			var matches = false;
			var node = null;
			// var tstr = new String(this.templateString); 
			var tstr = this.templateString; 
			// attempt to clone a template node, if there is one
			if((!this.templateNode)&&(this.templateString)){
				matches = this.templateString.match(/\$\{([^\}]+)\}/g);
				if(matches) {
					// if we do property replacement, don't create a templateNode
					// to clone from.
					var hash = this.strings || {};
					// FIXME: should this hash of default replacements be cached in
					// templateString?
					for(var key in dojo.widget.defaultStrings) {
						if(dojo.lang.isUndefined(hash[key])) {
							hash[key] = dojo.widget.defaultStrings[key];
						}
					}
					// FIXME: this is a lot of string munging. Can we make it faster?
					for(var i = 0; i < matches.length; i++) {
						var key = matches[i];
						key = key.substring(2, key.length-1);
						var kval = (key.substring(0, 5) == "this.") ? dojo.lang.getObjPathValue(key.substring(5), this) : hash[key];
						var value;
						if((kval)||(dojo.lang.isString(kval))){
							value = new String((dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval);
							// Safer substitution, see heading "Attribute values" in  
							// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
							while (value.indexOf("\"") > -1) {
								value=value.replace("\"","&quot;");
							}
							tstr = tstr.replace(matches[i], value);
						}
					}
				}else{
					// otherwise, we are required to instantiate a copy of the template
					// string if one is provided.
					
					// FIXME: need to be able to distinguish here what should be done
					// or provide a generic interface across all DOM implementations
					// FIMXE: this breaks if the template has whitespace as its first 
					// characters
					// node = this.createNodesFromText(this.templateString, true);
					// this.templateNode = node[0].cloneNode(true); // we're optimistic here
					this.templateNode = this.createNodesFromText(this.templateString, true)[0];
					if(!avoidCache){
						ts.node = this.templateNode;
					}
				}
			}
			if((!this.templateNode)&&(!matches)){ 
				dojo.debug("DomWidget.buildFromTemplate: could not create template");
				return false;
			}else if(!matches){
				node = this.templateNode.cloneNode(true);
				if(!node){ return false; }
			}else{
				node = this.createNodesFromText(tstr, true)[0];
			}

			// recurse through the node, looking for, and attaching to, our
			// attachment points which should be defined on the template node.

			this.domNode = node;
			// dojo.profile.start("attachTemplateNodes");
			this.attachTemplateNodes();
			// dojo.profile.end("attachTemplateNodes");
		
			// relocate source contents to templated container node
			// this.containerNode must be able to receive children, or exceptions will be thrown
			if (this.isContainer && this.containerNode){
				var src = this.getFragNodeRef(frag);
				if (src){
					dojo.dom.moveChildren(src, this.containerNode);
				}
			}
		},

		attachTemplateNodes: function(/*DomNode*/baseNode, /*Widget*/targetObj){
			// summary: 
			//		hooks up event handlers and property/node linkages. Calls
			//		dojo.widget.attachTemplateNodes to do all the hard work.
			// baseNode: defaults to "this.domNode"
			// targetObj: defaults to "this"
			if(!baseNode){ baseNode = this.domNode; }
			if(!targetObj){ targetObj = this; }
			return dojo.widget.attachTemplateNodes(baseNode, targetObj, 
						dojo.widget.getDojoEventsFromStr(this.templateString));
		},

		fillInTemplate: function(){
			// summary:
			//		stub function! sub-classes may use as a default UI
			//		initializer function. The UI rendering will be available by
			//		the time this is called from buildRendering. If
			//		buildRendering is over-ridden, this function may not be
			//		fired!
			// dojo.unimplemented("dojo.widget.DomWidget.fillInTemplate");
		},
		
		// method over-ride
		destroyRendering: function(){
			// summary: UI destructor
			try{
				delete this.domNode;
			}catch(e){ /* squelch! */ }
		},

		// FIXME: method over-ride
		cleanUp: function(){},
		
		getContainerHeight: function(){
			// summary: unimplemented!
			dojo.unimplemented("dojo.widget.DomWidget.getContainerHeight");
		},

		getContainerWidth: function(){
			// summary: unimplemented!
			dojo.unimplemented("dojo.widget.DomWidget.getContainerWidth");
		},

		createNodesFromText: function(){
			// summary: unimplemented!
			dojo.unimplemented("dojo.widget.DomWidget.createNodesFromText");
		}
	}
);

__CPAN_FILE__ src/widget/FisheyeList.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.FisheyeList");

//
// TODO
// fix SVG support, and turn it on only if the browser supports it
// fix really long labels in vertical mode
//

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.html.style");
dojo.require("dojo.html.selection");
dojo.require("dojo.html.util");
dojo.require("dojo.event.*");

/*
 * summary
 *	Menu similar to the fish eye menu on the Mac OS
 * usage
 *	<div dojoType="FisheyeList"
 *	itemWidth="40" itemHeight="40"
 *	itemMaxWidth="150" itemMaxHeight="150"
 *	orientation="horizontal"
 *	effectUnits="2"
 *	itemPadding="10"
 *	attachEdge="center"
 *	labelEdge="bottom">
 *
 *		<div dojoType="FisheyeListItem"
 *			id="item1"
 *			onclick="alert('click on' + this.caption + '(from widget id ' + this.widgetId + ')!');"
 *			caption="Item 1"
 *			iconsrc="images/fisheye_1.png">
 *		</div>
 *		...
 *	</div>
 */
dojo.widget.defineWidget(
	"dojo.widget.FisheyeList",
	dojo.widget.HtmlWidget,
function(){
	this.pos = {x: -1, y: -1};		// current cursor position, relative to the grid

	this.EDGE = {
		CENTER: 0,
		LEFT: 1,
		RIGHT: 2,
		TOP: 3,
		BOTTOM: 4
	};
	
	// for conservative trigger mode, when triggered, timerScale is gradually increased from 0 to 1
	this.timerScale = 1.0;

},
{
	templateString: '<div class="dojoHtmlFisheyeListBar"></div>',
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/FisheyeList.css"),

	isContainer: true,
	snarfChildDomOutput: true,

	// Integer
	//	width of menu item (in pixels) in it's dormant state (when the mouse is far away)
	itemWidth: 40,

	// Integer
	//	height of menu item (in pixels) in it's dormant state (when the mouse is far away)
	itemHeight: 40,

	// Integer
	//	width of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
	itemMaxWidth: 150,

	// Integer
	//	height of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
	itemMaxHeight: 150,


	// String
	//	orientation of the menu, either "horizontal" or "vertical"
	orientation: 'horizontal',

	// Boolean
	//	if true, don't start enlarging menu items until mouse is over an image;
	//	if false, start enlarging menu items as the mouse moves near them.
	conservativeTrigger: false,

	// Number
	//	controls how much reaction the menu makes, relative to the distance of the mouse from the menu
	effectUnits: 2,
	
	// Integer
	//	padding (in pixels) betweeen each menu item
	itemPadding: 10,

	// String
	//	controls the border that the menu items don't expand past;
	//	for example, if set to "top", then the menu items will drop downwards as they expand.
	// values
	//	"center", "left", "right", "top", "bottom".
	attachEdge: 'center',

	// String
	//	controls were the labels show up in relation to the menu item icons
	// values
	//	"center", "left", "right", "top", "bottom".
	labelEdge: 'bottom',

	// Boolean
	//	for browsers that support svg, use the svg image (specified in FisheyeListIem.svgSrc)
	//	rather than the iconSrc image attribute
	enableCrappySvgSupport: false,

	fillInTemplate: function() {
		dojo.html.disableSelection(this.domNode);

		this.isHorizontal = (this.orientation == 'horizontal');
		this.selectedNode = -1;

		this.isOver = false;
		this.hitX1 = -1;
		this.hitY1 = -1;
		this.hitX2 = -1;
		this.hitY2 = -1;

		//
		// only some edges make sense...
		//
		this.anchorEdge = this._toEdge(this.attachEdge, this.EDGE.CENTER);
		this.labelEdge  = this._toEdge(this.labelEdge,  this.EDGE.TOP);

		if ( this.isHorizontal && (this.anchorEdge == this.EDGE.LEFT  )){ this.anchorEdge = this.EDGE.CENTER; }
		if ( this.isHorizontal && (this.anchorEdge == this.EDGE.RIGHT )){ this.anchorEdge = this.EDGE.CENTER; }
		if (!this.isHorizontal && (this.anchorEdge == this.EDGE.TOP   )){ this.anchorEdge = this.EDGE.CENTER; }
		if (!this.isHorizontal && (this.anchorEdge == this.EDGE.BOTTOM)){ this.anchorEdge = this.EDGE.CENTER; }

		if (this.labelEdge == this.EDGE.CENTER){ this.labelEdge = this.EDGE.TOP; }
		if ( this.isHorizontal && (this.labelEdge == this.EDGE.LEFT  )){ this.labelEdge = this.EDGE.TOP; }
		if ( this.isHorizontal && (this.labelEdge == this.EDGE.RIGHT )){ this.labelEdge = this.EDGE.TOP; }
		if (!this.isHorizontal && (this.labelEdge == this.EDGE.TOP   )){ this.labelEdge = this.EDGE.LEFT; }
		if (!this.isHorizontal && (this.labelEdge == this.EDGE.BOTTOM)){ this.labelEdge = this.EDGE.LEFT; }

		//
		// figure out the proximity size
		//
		this.proximityLeft   = this.itemWidth  * (this.effectUnits - 0.5);
		this.proximityRight  = this.itemWidth  * (this.effectUnits - 0.5);
		this.proximityTop    = this.itemHeight * (this.effectUnits - 0.5);
		this.proximityBottom = this.itemHeight * (this.effectUnits - 0.5);

		if (this.anchorEdge == this.EDGE.LEFT){
			this.proximityLeft = 0;
		}
		if (this.anchorEdge == this.EDGE.RIGHT){
			this.proximityRight = 0;
		}
		if (this.anchorEdge == this.EDGE.TOP){
			this.proximityTop = 0;
		}
		if (this.anchorEdge == this.EDGE.BOTTOM){
			this.proximityBottom = 0;
		}
		if (this.anchorEdge == this.EDGE.CENTER){
			this.proximityLeft   /= 2;
			this.proximityRight  /= 2;
			this.proximityTop    /= 2;
			this.proximityBottom /= 2;
		}
	},
	
	postCreate: function() {
		this._initializePositioning();

		//
		// in liberal trigger mode, activate menu whenever mouse is close
		//
		if( !this.conservativeTrigger ){
			dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
		}
		
		// Deactivate the menu if mouse is moved off screen (doesn't work for FF?)
		dojo.event.connect(document.documentElement, "onmouseout", this, "_onBodyOut");
		dojo.event.connect(this, "addChild", this, "_initializePositioning");
	},

	_initializePositioning: function(){
		this.itemCount = this.children.length;

		this.barWidth  = (this.isHorizontal ? this.itemCount : 1) * this.itemWidth;
		this.barHeight = (this.isHorizontal ? 1 : this.itemCount) * this.itemHeight;

		this.totalWidth  = this.proximityLeft + this.proximityRight  + this.barWidth;
		this.totalHeight = this.proximityTop  + this.proximityBottom + this.barHeight;

		//
		// calculate effect ranges for each item
		//
		for (var i=0; i<this.children.length; i++){

			this.children[i].posX = this.itemWidth  * (this.isHorizontal ? i : 0);
			this.children[i].posY = this.itemHeight * (this.isHorizontal ? 0 : i);

			this.children[i].cenX = this.children[i].posX + (this.itemWidth  / 2);
			this.children[i].cenY = this.children[i].posY + (this.itemHeight / 2);

			var isz = this.isHorizontal ? this.itemWidth : this.itemHeight;
			var r = this.effectUnits * isz;
			var c = this.isHorizontal ? this.children[i].cenX : this.children[i].cenY;
			var lhs = this.isHorizontal ? this.proximityLeft : this.proximityTop;
			var rhs = this.isHorizontal ? this.proximityRight : this.proximityBottom;
			var siz = this.isHorizontal ? this.barWidth : this.barHeight;

			var range_lhs = r;
			var range_rhs = r;

			if (range_lhs > c+lhs){ range_lhs = c+lhs; }
			if (range_rhs > (siz-c+rhs)){ range_rhs = siz-c+rhs; }

			this.children[i].effectRangeLeft = range_lhs / isz;
			this.children[i].effectRangeRght = range_rhs / isz;

			//dojo.debug('effect range for '+i+' is '+range_lhs+'/'+range_rhs);
		}

		//
		// create the bar
		//
		this.domNode.style.width = this.barWidth + 'px';
		this.domNode.style.height = this.barHeight + 'px';

		//
		// position the items
		//
		for (var i=0; i<this.children.length; i++){
			var itm = this.children[i];
			var elm = itm.domNode;
			elm.style.left   = itm.posX + 'px';
			elm.style.top    = itm.posY + 'px';
			elm.style.width  = this.itemWidth + 'px';
			elm.style.height = this.itemHeight + 'px';
			
			if ( itm.svgNode ) {
				itm.svgNode.style.position = 'absolute';
				itm.svgNode.style.left = this.itemPadding+'%';
				itm.svgNode.style.top = this.itemPadding+'%';
				itm.svgNode.style.width = (100 - 2 * this.itemPadding) + '%';
				itm.svgNode.style.height = (100 - 2 * this.itemPadding) + '%';
				itm.svgNode.style.zIndex = 1;
	
				itm.svgNode.setSize(this.itemWidth, this.itemHeight);
			} else {
				itm.imgNode.style.left = this.itemPadding+'%';
				itm.imgNode.style.top = this.itemPadding+'%';
				itm.imgNode.style.width = (100 - 2 * this.itemPadding) + '%';
				itm.imgNode.style.height = (100 - 2 * this.itemPadding) + '%';
			}
		}

		//
		// calc the grid
		//
		this._calcHitGrid();
	},

	_onBodyOut: function(/*Event*/ e){
		// clicking over an object inside of body causes this event to fire; ignore that case
		if( dojo.html.overElement(dojo.body(), e) ){
			return;
		}
		this._setDormant(e);
	},

	_setDormant: function(/*Event*/ e){
		// summary: called when mouse moves out of menu's range

		if( !this.isOver ){ return; }	// already dormant?
		this.isOver = false;

		if ( this.conservativeTrigger ) {
			// user can't re-trigger the menu expansion
			// until he mouses over a icon again
			dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
		}
		this._onGridMouseMove(-1, -1);
	},

	_setActive: function(/*Event*/ e){
		// summary: called when mouse is moved into menu's range

		if( this.isOver ){ return; }	// already activated?
		this.isOver = true;

		if ( this.conservativeTrigger ) {
			// switch event handlers so that we handle mouse events from anywhere near
			// the menu
			dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");

			this.timerScale=0.0;

			// call mouse handler to do some initial necessary calculations/positioning
			this._onMouseMove(e);

			// slowly expand the icon size so it isn't jumpy
			this._expandSlowly();
		}
	},

	_onMouseMove: function(/*Event*/ e) {
		// summary: called when mouse is moved
		if ((e.pageX >= this.hitX1) && (e.pageX <= this.hitX2) &&
			(e.pageY >= this.hitY1) && (e.pageY <= this.hitY2)){
			if( !this.isOver ){
				this._setActive(e);
			}
			this._onGridMouseMove(e.pageX-this.hitX1, e.pageY-this.hitY1);
		}else{
			if (this.isOver){
				this._setDormant(e);
			}
		}
	},

	onResized: function() {
		this._calcHitGrid();
	},

	_onGridMouseMove: function(x, y){
		// summary: called when mouse is moved in the vicinity of the menu
		this.pos = {x:x, y:y};
		this._paint();
	},
	
	_paint: function(){
		var x=this.pos.x;
		var y=this.pos.y;

		if( this.itemCount <= 0 ){ return; }

		//
		// figure out our main index
		//
		var pos = this.isHorizontal ? x : y;
		var prx = this.isHorizontal ? this.proximityLeft : this.proximityTop;
		var siz = this.isHorizontal ? this.itemWidth : this.itemHeight;
		var sim = this.isHorizontal ? 
			(1.0-this.timerScale)*this.itemWidth + this.timerScale*this.itemMaxWidth :
			(1.0-this.timerScale)*this.itemHeight + this.timerScale*this.itemMaxHeight ;

		var cen = ((pos - prx) / siz) - 0.5;
		var max_off_cen = (sim / siz) - 0.5;

		if (max_off_cen > this.effectUnits){ max_off_cen = this.effectUnits; }

		//
		// figure out our off-axis weighting
		//
		var off_weight = 0;

		if (this.anchorEdge == this.EDGE.BOTTOM){
			var cen2 = (y - this.proximityTop) / this.itemHeight;
			off_weight = (cen2 > 0.5) ? 1 : y / (this.proximityTop + (this.itemHeight / 2));
		}
		if (this.anchorEdge == this.EDGE.TOP){
			var cen2 = (y - this.proximityTop) / this.itemHeight;
			off_weight = (cen2 < 0.5) ? 1 : (this.totalHeight - y) / (this.proximityBottom + (this.itemHeight / 2));
		}
		if (this.anchorEdge == this.EDGE.RIGHT){
			var cen2 = (x - this.proximityLeft) / this.itemWidth;
			off_weight = (cen2 > 0.5) ? 1 : x / (this.proximityLeft + (this.itemWidth / 2));
		}
		if (this.anchorEdge == this.EDGE.LEFT){
			var cen2 = (x - this.proximityLeft) / this.itemWidth;
			off_weight = (cen2 < 0.5) ? 1 : (this.totalWidth - x) / (this.proximityRight + (this.itemWidth / 2));
		}
		if (this.anchorEdge == this.EDGE.CENTER){
			if (this.isHorizontal){
				off_weight = y / (this.totalHeight);
			}else{
				off_weight = x / (this.totalWidth);
			}

			if (off_weight > 0.5){
				off_weight = 1 - off_weight;
			}

			off_weight *= 2;
		}

		//
		// set the sizes
		//
		for(var i=0; i<this.itemCount; i++){
			var weight = this._weighAt(cen, i);
			if (weight < 0){weight = 0;}
			this._setItemSize(i, weight * off_weight);
		}

		//
		// set the positions
		//

		var main_p = Math.round(cen);
		var offset = 0;

		if (cen < 0){
			main_p = 0;

		}else if (cen > this.itemCount - 1){

			main_p = this.itemCount -1;

		}else{

			offset = (cen - main_p) * ((this.isHorizontal ? this.itemWidth : this.itemHeight) - this.children[main_p].sizeMain);
		}

		this._positionElementsFrom(main_p, offset);
	},

	_weighAt: function(/*Integer*/ cen, /*Integer*/ i){
		var dist = Math.abs(cen - i);
		var limit = ((cen - i) > 0) ? this.children[i].effectRangeRght : this.children[i].effectRangeLeft;
		return (dist > limit) ? 0 : (1 - dist / limit);			// Integer
	},

	_setItemSize: function(p, scale){
		scale *= this.timerScale;
		var w = Math.round(this.itemWidth  + ((this.itemMaxWidth  - this.itemWidth ) * scale));
		var h = Math.round(this.itemHeight + ((this.itemMaxHeight - this.itemHeight) * scale));

		if (this.isHorizontal){

			this.children[p].sizeW = w;
			this.children[p].sizeH = h;

			this.children[p].sizeMain = w;
			this.children[p].sizeOff  = h;

			var y = 0;
			if (this.anchorEdge == this.EDGE.TOP){
				y = (this.children[p].cenY - (this.itemHeight / 2));
			}else if (this.anchorEdge == this.EDGE.BOTTOM){
				y = (this.children[p].cenY - (h - (this.itemHeight / 2)));
			}else{
				y = (this.children[p].cenY - (h / 2));
			}

			this.children[p].usualX = Math.round(this.children[p].cenX - (w / 2));
			this.children[p].domNode.style.top  = y + 'px';
			this.children[p].domNode.style.left  = this.children[p].usualX + 'px';

		}else{

			this.children[p].sizeW = w;
			this.children[p].sizeH = h;

			this.children[p].sizeOff  = w;
			this.children[p].sizeMain = h;

			var x = 0;
			if (this.anchorEdge == this.EDGE.LEFT){
				x = this.children[p].cenX - (this.itemWidth / 2);
			}else if (this.anchorEdge == this.EDGE.RIGHT){
				x = this.children[p].cenX - (w - (this.itemWidth / 2));
			}else{
				x = this.children[p].cenX - (w / 2);
			}

			this.children[p].domNode.style.left = x + 'px';
			this.children[p].usualY = Math.round(this.children[p].cenY - (h / 2));

			this.children[p].domNode.style.top  = this.children[p].usualY + 'px';
		}

		this.children[p].domNode.style.width  = w + 'px';
		this.children[p].domNode.style.height = h + 'px';

		if (this.children[p].svgNode){
			this.children[p].svgNode.setSize(w, h);
		}
	},

	_positionElementsFrom: function(p, offset){

		var pos = 0;

		if (this.isHorizontal){
			pos = Math.round(this.children[p].usualX + offset);
			this.children[p].domNode.style.left = pos + 'px';
		}else{
			pos = Math.round(this.children[p].usualY + offset);
			this.children[p].domNode.style.top = pos + 'px';
		}
		this._positionLabel(this.children[p]);


		//
		// position before
		//
		var bpos = pos;
		for(var i=p-1; i>=0; i--){
			bpos -= this.children[i].sizeMain;

			if (this.isHorizontal){
				this.children[i].domNode.style.left = bpos + 'px';
			}else{
				this.children[i].domNode.style.top = bpos + 'px';
			}
			this._positionLabel(this.children[i]);
		}

		//
		// position after
		//
		var apos = pos;
		for(var i=p+1; i<this.itemCount; i++){
			apos += this.children[i-1].sizeMain;

			if (this.isHorizontal){
				this.children[i].domNode.style.left = apos + 'px';
			}else{
				this.children[i].domNode.style.top = apos + 'px';
			}
			this._positionLabel(this.children[i]);
		}

	},

	_positionLabel: function(itm){

		var x = 0;
		var y = 0;
		
		var mb = dojo.html.getMarginBox(itm.lblNode);

		if (this.labelEdge == this.EDGE.TOP){
			x = Math.round((itm.sizeW / 2) - (mb.width / 2));
			y = -mb.height;
		}

		if (this.labelEdge == this.EDGE.BOTTOM){
			x = Math.round((itm.sizeW / 2) - (mb.width / 2));
			y = itm.sizeH;
		}

		if (this.labelEdge == this.EDGE.LEFT){
			x = -mb.width;
			y = Math.round((itm.sizeH / 2) - (mb.height / 2));
		}

		if (this.labelEdge == this.EDGE.RIGHT){
			x = itm.sizeW;
			y = Math.round((itm.sizeH / 2) - (mb.height / 2));
		}

		itm.lblNode.style.left = x + 'px';
		itm.lblNode.style.top  = y + 'px';
	},

	_calcHitGrid: function(){

		var pos = dojo.html.getAbsolutePosition(this.domNode, true);

		this.hitX1 = pos.x - this.proximityLeft;
		this.hitY1 = pos.y - this.proximityTop;
		this.hitX2 = this.hitX1 + this.totalWidth;
		this.hitY2 = this.hitY1 + this.totalHeight;

		//dojo.debug(this.hitX1+','+this.hitY1+' // '+this.hitX2+','+this.hitY2);
	},

	_toEdge: function(inp, def){
		return this.EDGE[inp.toUpperCase()] || def;
	},
	
	_expandSlowly: function(){
		// summary: slowly expand the image to user specified max size
		if( !this.isOver ){ return; }
		this.timerScale += 0.2;
		this._paint();
		if ( this.timerScale<1.0 ) {
			dojo.lang.setTimeout(this, "_expandSlowly", 10);
		}
	},

	destroy: function(){
		// need to disconnect when we destroy
		dojo.event.disconnect(document.documentElement, "onmouseout", this, "_onBodyOut");
		dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
		dojo.widget.FisheyeList.superclass.destroy.call(this);
	}
});

/*
 * summary
 *	Menu item inside of a FisheyeList.
 *	See FisheyeList documentation for details on usage.
 */
dojo.widget.defineWidget(
	"dojo.widget.FisheyeListItem",
	dojo.widget.HtmlWidget,
{
	// String
	//	pathname to image file (jpg, gif, png, etc.) of icon for this menu item
	iconSrc: "",

	// String
	//	pathname to svg file of icon for this menu item
	svgSrc: "",
	
	// String
	//	label to print next to the icon, when it is moused-over
	caption: "",

	// String
	//	will be set to the id of the orginal div element
	id: "",

	_blankImgPath: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),

	templateString:
		'<div class="dojoHtmlFisheyeListItem">' +
		'  <img class="dojoHtmlFisheyeListItemImage" dojoAttachPoint="imgNode" dojoAttachEvent="onMouseOver;onMouseOut;onClick">' +
		'  <div class="dojoHtmlFisheyeListItemLabel" dojoAttachPoint="lblNode"></div>' +
		'</div>',
	
	fillInTemplate: function() {
		//
		// set image
		// TODO: turn on/off SVG support based on browser version.
		// this.parent.enableCrappySvgSupport is not available to this function
		//
		if (this.svgSrc != ""){
			this.svgNode = this._createSvgNode(this.svgSrc);
			this.domNode.appendChild(this.svgNode);
			this.imgNode.style.display = 'none';
		} else if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.render.html.ie)&&(!dojo.render.html.ie70)){
			/* we set the id of the new fisheyeListItem to the id of the div defined in the HTML */
			if (dojo.dom.hasParent(this.imgNode) && this.id != ""){
				var parent = this.imgNode.parentNode;
				parent.setAttribute("id", this.id);
			}
			this.imgNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='scale')";
			this.imgNode.src = this._blankImgPath.toString();
		} else {
			if (dojo.dom.hasParent(this.imgNode) && this.id != ""){
				var parent = this.imgNode.parentNode;
				parent.setAttribute("id", this.id);
			}
			this.imgNode.src = this.iconSrc;
		}

		//
		// Label
		//
		if ( this.lblNode ) {
			this.lblNode.appendChild(document.createTextNode(this.caption));
		}
		dojo.html.disableSelection(this.domNode);
	},
	
	_createSvgNode: function(src){
		var elm = document.createElement('embed');
		elm.src = src;
		elm.type = 'image/svg+xml';
		//elm.style.border = '1px solid black';
		elm.style.width = '1px';
		elm.style.height = '1px';
		elm.loaded = 0;
		elm.setSizeOnLoad = false;

		elm.onload = function(){
			this.svgRoot = this.getSVGDocument().rootElement;
			this.svgDoc = this.getSVGDocument().documentElement;
			this.zeroWidth = this.svgRoot.width.baseVal.value;
			this.zeroHeight = this.svgRoot.height.baseVal.value;
			this.loaded = true;

			if (this.setSizeOnLoad){
				this.setSize(this.setWidth, this.setHeight);
			}
		}

		elm.setSize = function(w, h){
			if (!this.loaded){
				this.setWidth = w;
				this.setHeight = h;
				this.setSizeOnLoad = true;
				return;
			}

			this.style.width = w+'px';
			this.style.height = h+'px';
			this.svgRoot.width.baseVal.value = w;
			this.svgRoot.height.baseVal.value = h;

			var scale_x = w / this.zeroWidth;
			var scale_y = h / this.zeroHeight;

			for(var i=0; i<this.svgDoc.childNodes.length; i++){
				if (this.svgDoc.childNodes[i].setAttribute){
					this.svgDoc.childNodes[i].setAttribute( "transform", "scale("+scale_x+","+scale_y+")" );
				}
			}
		}

		return elm;
	},

	onMouseOver: function(/*Event*/ e) {
		// summary: callback when user moves mouse over this menu item
		// in conservative mode, don't activate the menu until user mouses over an icon
		if( !this.parent.isOver ){
			this.parent._setActive(e);
		}
		if ( this.caption != "" ) {
			dojo.html.addClass(this.lblNode, "selected");
			this.parent._positionLabel(this);
		}
	},
	
	onMouseOut: function(/*Event*/ e) {
		// summary: callback when user moves mouse off of this menu item
		dojo.html.removeClass(this.lblNode, "selected");
	},

	onClick: function(/*Event*/ e) {
		// summary: user overridable callback when user clicks this menu item
	}
});


__CPAN_FILE__ src/widget/ProgressBar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ProgressBar");

// requires here
dojo.require("dojo.widget.*"); // necessary
dojo.require("dojo.event");
dojo.require("dojo.dom.*");
dojo.require("dojo.html.style");
dojo.require("dojo.string.*");
dojo.require("dojo.lfx.*");

dojo.widget.defineWidget(
	"dojo.widget.ProgressBar",
	dojo.widget.HtmlWidget,
	{
		// Constructor arguments
		progressValue: "0",
		maxProgressValue: 100,
		width: 300,
		height: 30,
		frontPercentClass: "frontPercent",
		backPercentClass: "backPercent",
		frontBarClass: "frontBar",
		backBarClass: "backBar",
		hasText: "false",
		isVertical:"false",
		showOnlyIntegers: "false",
		dataSource: "",
		pollInterval: "3000",
		duration: "1000",
//		leftImage: null,
//		centerImage: null,
//		rightImage: null,
		templatePath: dojo.uri.dojoUri("src/widget/templates/ProgressBar.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/ProgressBar.css"),
		
	
		// attach points
		containerNode: null,
		internalProgress: null,
	
		// private members
		_pixelUnitRatio: 0.0,
		// _pixelRatio := width/100
		_pixelPercentRatio: 0.0,
		_unitPercentRatio: 0.0,
		_unitPixelRatio: 0.0,
		_floatDimension: 0.0,
		_intDimension: 0,
		_progressPercentValue: "0%",
		_floatMaxProgressValue: 0.0,
		_dimension: "width",
		_pixelValue: 0,
		_oInterval: null,
		_animation: null,
		_animationStopped: true,
		_progressValueBak: false,
		_hasTextBak: false,
		// public functions
		fillInTemplate: function(args, frag){
			this.internalProgress.className = this.frontBarClass;
			this.containerNode.className = this.backBarClass;
			if (this.isVertical == "true"){
				this.internalProgress.style.bottom="0px";
				this.internalProgress.style.left="0px";
				this._dimension = "height";
			} else {
				this.internalProgress.style.top="0px";
				this.internalProgress.style.left="0px";
				this._dimension = "width";
			}
			this.frontPercentLabel.className = this.frontPercentClass;
			this.backPercentLabel.className = this.backPercentClass;
			this.progressValue = "" + this.progressValue; 
			this.domNode.style.height = this.height; 
			this.domNode.style.width = this.width;
			this._intDimension = parseInt("0" + eval("this." + this._dimension));
			this._floatDimension = parseFloat("0" + eval("this."+this._dimension));
			this._pixelPercentRatio = this._floatDimension/100;
			this.setMaxProgressValue(this.maxProgressValue, true);
			this.setProgressValue(dojo.string.trim(this.progressValue), true);
			dojo.debug("float dimension: " + this._floatDimension);
			dojo.debug("this._unitPixelRatio: " + this._unitPixelRatio);
			this.showText(this.hasText);
		},
		showText: function(visible){
			if (visible == "true"){
				this.backPercentLabel.style.display="block";
				this.frontPercentLabel.style.display="block";
			} else {
				this.backPercentLabel.style.display="none";
				this.frontPercentLabel.style.display="none";
			}
			this.hasText = visible;
		},
		postCreate: function(args, frag){
			// labels position
			this.render();
		},
		_backupValues: function(){
			this._progressValueBak = this.progressValue;
			this._hasTextBak = this.hasText;
		},
		_restoreValues: function(){
				this.setProgressValue(this._progressValueBak);
				this.showText(this._hasTextBak);
		},
		_setupAnimation: function(){
			var _self = this;
			dojo.debug("internalProgress width: " + this.internalProgress.style.width);
			this._animation = dojo.lfx.html.slideTo(this.internalProgress, 
				{top: 0, left: this.width-parseInt(this.internalProgress.style.width)}, parseInt(this.duration), null, 
					function(){
						var _backAnim = dojo.lfx.html.slideTo(_self.internalProgress, 
						{ top: 0, left: 0 }, parseInt(_self.duration));
						dojo.event.connect(_backAnim, "onEnd", function(){
							if (!_self._animationStopped){
								_self._animation.play();
							}
							});
						if (!_self._animationStopped){
							_backAnim.play();
						}
						_backAnim = null; // <-- to avoid memory leaks in IE
					}
				);
		},
		getMaxProgressValue: function(){
			return this.maxProgressValue;
		},
		setMaxProgressValue: function(maxValue, noRender){
			if (!this._animationStopped){
				return;
			}
			this.maxProgressValue = maxValue;
			this._floatMaxProgressValue = parseFloat("0" + this.maxProgressValue);
			this._pixelUnitRatio = this._floatDimension/this.maxProgressValue;
			this._unitPercentRatio = this._floatMaxProgressValue/100;
			this._unitPixelRatio = this._floatMaxProgressValue/this._floatDimension;
			this.setProgressValue(this.progressValue, true);
			if (!noRender){
				this.render();
			}
		},
		setProgressValue: function(value, noRender){
			if (!this._animationStopped){
				return;
			}
			// transformations here
			this._progressPercentValue = "0%";
			var _value=dojo.string.trim("" + value);
			var _floatValue = parseFloat("0" + _value);
			var _intValue = parseInt("0" + _value);
			var _pixelValue = 0;
			if (dojo.string.endsWith(_value, "%", false)){
				this._progressPercentValue = Math.min(_floatValue.toFixed(1), 100) + "%";
				_value = Math.min((_floatValue)*this._unitPercentRatio, this.maxProgressValue);
				_pixelValue = Math.min((_floatValue)*this._pixelPercentRatio, eval("this."+this._dimension));
			} else {
				this.progressValue = Math.min(_floatValue, this.maxProgressValue);
				this._progressPercentValue = Math.min((_floatValue/this._unitPercentRatio).toFixed(1), 100) + "%";
				_pixelValue = Math.min(_floatValue/this._unitPixelRatio, eval("this."+this._dimension));
			}
			this.progressValue = dojo.string.trim(_value);
			this._pixelValue = _pixelValue;
			if (!noRender){
				this.render();
			}
		},
		setCurrentPercentProgress: function(percentProgress){
			this._setCurrentPixelProgress(percentProgress);
		},
		getProgressValue: function(){
			return this.progressValue;
		},
		getProgressPercentValue: function(){
			return this._progressPercentValue;
		},
		setDataSource: function(dataSource){
			this.dataSource = dataSource;
		},
		setPollInterval: function(pollInterval){
			this.pollInterval = pollInterval;
		},
		start: function(){
			var _showFunction = dojo.lang.hitch(this, this._showRemoteProgress);
			this._oInterval = setInterval(_showFunction, this.pollInterval);
		},
		startAnimation: function(){
			if (this._animationStopped) {
				this._backupValues();
				this.setProgressValue("10%");
				this._animationStopped = false;
				this._setupAnimation();
				this.showText(false);
				this.internalProgress.style.height="105%";
				this._animation.play();
			}
		},
		stopAnimation: function(){
			if (this._animation) {
				this._animationStopped = true;
				this._animation.stop();
				this.internalProgress.style.height="100%";
				this.internalProgress.style.left = "0px";
				this._restoreValues();
				this._setLabelPosition();
			}
		},
		_showRemoteProgress: function(){
			var _self = this;
//			dojo.debug("getMax: "+this.getMaxProgressValue()+" getprval: "+this.getProgressValue());
			if ( (this.getMaxProgressValue() == this.getProgressValue()) &&
				this._oInterval){
				clearInterval(this._oInterval);
				this._oInterval = null;
				this.setProgressValue("100%");
				return;	
			}
			var bArgs = {
				url: _self.dataSource,
				method: "POST",
				mimetype: "text/json",
				error: function(type, errorObj){
					dojo.debug("[ProgressBar] showRemoteProgress error");
				},
				load: function(type, data, evt){
					//dojo.debug(data["progress"]);
					_self.setProgressValue(
						(_self._oInterval ? data["progress"] : "100%")
					);
//				dojo.debug("_oInterval: "+_self._oInterval);
				}
			};
			dojo.io.bind(bArgs);
		},
		render: function(){
			this._setPercentLabel(dojo.string.trim(this._progressPercentValue));
			this._setPixelValue(this._pixelValue);
			this._setLabelPosition();
		},
		// private functions
		_setLabelPosition: function(){
			var _widthFront = 
				dojo.html.getContentBox(this.frontPercentLabel).width;
			var _heightFront = 
				dojo.html.getContentBox(this.frontPercentLabel).height;
			var _widthBack = 
				dojo.html.getContentBox(this.backPercentLabel).width;
			var _heightBack = 
				dojo.html.getContentBox(this.backPercentLabel).height;
			var _leftFront = (this.width - _widthFront)/2 + "px";
			var _bottomFront = (parseInt(this.height) - parseInt(_heightFront))/2 + "px";
			var _leftBack = (this.width - _widthBack)/2 + "px";
			var _bottomBack = (parseInt(this.height) - parseInt(_heightBack))/2 + "px";
			this.frontPercentLabel.style.left = _leftFront;
			this.backPercentLabel.style.left = _leftBack; 
			this.frontPercentLabel.style.bottom = _bottomFront;
			this.backPercentLabel.style.bottom = _bottomBack; 
//			dojo.debug("bottom: "+this.backPercentLabel.style.bottom);
//			dojo.debug("BOTTOM: "+_bottom);
		},
		_setPercentLabel: function(percentValue){
			dojo.dom.removeChildren(this.frontPercentLabel);
			dojo.dom.removeChildren(this.backPercentLabel);
			var _percentValue = this.showOnlyIntegers == "false" ? 
				percentValue : parseInt(percentValue) + "%";
			this.frontPercentLabel.
				appendChild(document.createTextNode(_percentValue));
			this.backPercentLabel.
				appendChild(document.createTextNode(_percentValue));
		},
		_setPixelValue: function(value){
			eval("this.internalProgress.style." + this._dimension + " = " + value + " + 'px'");
			this.onChange();
		},
		onChange: function(){
		}
	});
	

__CPAN_FILE__ src/widget/UsTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.UsTextbox");

dojo.require("dojo.widget.ValidationTextbox");
dojo.require("dojo.validate.us");

dojo.widget.defineWidget(
	"dojo.widget.UsStateTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary: a Textbox which tests for a United States state abbreviation
		// allowTerritories  Allow Guam, Puerto Rico, etc.  Default is true.
		// allowMilitary     Allow military 'states', e.g. Armed Forces Europe (AE). Default is true.

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// Initialize properties in super-class.
			dojo.widget.UsStateTextbox.superclass.mixInProperties.apply(this, arguments);

			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.allowterritories){
				this.flags.allowTerritories = (localProperties.allowterritories == "true");
			}
			if(localProperties.allowmilitary){
				this.flags.allowMilitary = (localProperties.allowmilitary == "true");
			}
		},

		isValid: function(){
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.us.isState(this.textbox.value, this.flags);
		}
	}
);

/*
  ****** UsZipTextbox ******

  A subclass of ValidationTextbox.
  Over-rides isValid to test if input is a US zip code.
  Validates zip-5 and zip-5 plus 4.
*/
dojo.widget.defineWidget(
	"dojo.widget.UsZipTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary: a Textbox which tests for a United States postal code
		isValid: function(){
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.us.isZipCode(this.textbox.value);
		}
	}
);

dojo.widget.defineWidget(
	"dojo.widget.UsSocialSecurityNumberTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary: a Textbox which tests for a United States Social Security number
		isValid: function(){
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.us.isSocialSecurityNumber(this.textbox.value);
		}
	}
);

dojo.widget.defineWidget(
	"dojo.widget.UsPhoneNumberTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary: a Textbox which tests for a United States 10-digit telephone number, extension is optional.

		isValid: function(){
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.us.isPhoneNumber(this.textbox.value);
		}
	}
);

__CPAN_FILE__ src/widget/TreeControllerExtension.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
 * Additional tree utils
 *
 */
dojo.provide("dojo.widget.TreeControllerExtension");

dojo.declare(
	"dojo.widget.TreeControllerExtension",
	null,
{
	saveExpandedIndices: function(node, field) {
		var obj = {};

		for(var i=0; i<node.children.length; i++) {
			if (node.children[i].isExpanded) {
				var key = dojo.lang.isUndefined(field) ? i : node.children[i][field];
				obj[key] = this.saveExpandedIndices(node.children[i], field);
			}
		}

		return obj;
	},


	restoreExpandedIndices: function(node, savedIndices, field) {
		var _this = this;

		var handler = function(node, savedIndices) {
			this.node = node; //.children[i];
			this.savedIndices = savedIndices; //[i];
			// recursively read next savedIndices level and apply to opened node
			this.process = function() {
				//dojo.debug("Callback applied for "+this.node);
				_this.restoreExpandedIndices(this.node, this.savedIndices, field);
			};
		}


		for(var i=0; i<node.children.length; i++) {
			var child = node.children[i];

			var found = false;
			var key = -1;

			//dojo.debug("Check "+child)
			// process field set case
			if (dojo.lang.isUndefined(field) && savedIndices[i]) {
				found = true;
				key = i;
			}

			// process case when field is not set
			if (field) {
				for(var key in savedIndices) {
					//dojo.debug("Compare "+key+" "+child[field])
					if (key == child[field]) {
						found = true;
						break;
					}
				}
			}

			// if we found anything - expand it
			if (found) {
				//dojo.debug("Found at "+key)
				var h = new handler(child, savedIndices[key]);
				_this.expand(child, false, h, h.process);
			} else if (child.isExpanded) { // not found, so collapse
				//dojo.debug("Collapsing all descendants "+node.children[i])
				dojo.lang.forEach(child.getDescendants(), function(elem) { _this.collapse(elem); });
				//this.collapse(node.children[i]);
			}

		}


	}

});






__CPAN_FILE__ src/widget/RealNumberTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.RealNumberTextbox");

dojo.require("dojo.widget.IntegerTextbox");
dojo.require("dojo.validate.common");

/*
  ****** RealNumberTextbox ******

  A subclass that extends IntegerTextbox.
  Over-rides isValid/isInRange to test for real number input.
  Has 5 new properties that can be specified as attributes in the markup.

  @attr places    The exact number of decimal places.  If omitted, it's unlimited and optional.
  @attr exponent  Can be true or false.  If omitted the exponential part is optional.
  @attr eSigned   Is the exponent signed?  Can be true or false, if omitted the sign is optional.
  @attr min  Minimum signed value.  Default is -Infinity
  @attr max  Maximum signed value.  Default is +Infinity
*/
dojo.widget.defineWidget(
	"dojo.widget.RealNumberTextbox",
	dojo.widget.IntegerTextbox,
	{
		mixInProperties: function(localProperties, frag){
			// First initialize properties in super-class.
			dojo.widget.RealNumberTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if (localProperties.places){ 
				this.flags.places = Number(localProperties.places);
			}
			if((localProperties.exponent == "true")||
				(localProperties.exponent == "always")){
				this.flags.exponent = true;
			}else if((localProperties.exponent == "false")||(localProperties.exponent == "never")){
				this.flags.exponent = false;
			}else{
				this.flags.exponent = [ true, false ]; // optional
			}
			if((localProperties.esigned == "true")||(localProperties.esigned == "always")){
				this.flags.eSigned = true;
			}else if((localProperties.esigned == "false")||(localProperties.esigned == "never")){
				this.flags.eSigned = false;
			}else{
				this.flags.eSigned = [ true, false ]; // optional
			}
			if(localProperties.min){ 
				this.flags.min = parseFloat(localProperties.min);
			}
			if(localProperties.max){ 
				this.flags.max = parseFloat(localProperties.max);
			}
		},

		// Over-ride for real number validation
		isValid: function(){
			return dojo.validate.isRealNumber(this.textbox.value, this.flags);
		},
		isInRange: function(){
			return dojo.validate.isInRange(this.textbox.value, this.flags);
		}

	}
);

__CPAN_FILE__ src/widget/ComboBox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ComboBox");

dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.html.*");
dojo.require("dojo.html.display");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.iframe");
dojo.require("dojo.string");
dojo.require("dojo.widget.html.stabile");
dojo.require("dojo.widget.PopupContainer");

dojo.widget.incrementalComboBoxDataProvider = function(/*String*/ url, /*Number*/ limit, /*Number*/ timeout){
	this.searchUrl = url;
	this.inFlight = false;
	this.activeRequest = null;
	this.allowCache = false;

	this.cache = {};

	this.init = function(/*Widget*/ cbox){
		this.searchUrl = cbox.dataUrl;
	};

	this.addToCache = function(/*String*/ keyword, /*Array*/ data){
		if(this.allowCache){
			this.cache[keyword] = data;
		}
	};

	this.startSearch = function(/*String*/ searchStr, /*String*/ type, /*Boolean*/ ignoreLimit){
		if(this.inFlight){
			// FIXME: implement backoff!
		}
		var tss = encodeURIComponent(searchStr);
		var realUrl = dojo.string.substituteParams(this.searchUrl, {"searchString": tss});
		var _this = this;
		var request = dojo.io.bind({
			url: realUrl,
			method: "get",
			mimetype: "text/json",
			load: function(type, data, evt){
				_this.inFlight = false;
				if(!dojo.lang.isArray(data)){
					var arrData = [];
					for(var key in data){
						arrData.push([data[key], key]);
					}
					data = arrData;
				}
				_this.addToCache(searchStr, data);
				_this.provideSearchResults(data);
			}
		});
		this.inFlight = true;
	};
};

dojo.widget.ComboBoxDataProvider = function(/*Array*/ dataPairs, /*Number*/ limit, /*Number*/ timeout){
	// NOTE: this data provider is designed as a naive reference
	// implementation, and as such it is written more for readability than
	// speed. A deployable data provider would implement lookups, search
	// caching (and invalidation), and a significantly less naive data
	// structure for storage of items.

	this.data = [];
	this.searchTimeout = timeout || 500;
	this.searchLimit = limit || 30;
	this.searchType = "STARTSTRING"; // may also be "STARTWORD" or "SUBSTRING"
	this.caseSensitive = false;
	// for caching optimizations
	this._lastSearch = "";
	this._lastSearchResults = null;

	this.init = function(/*Widget*/ cbox, /*DomNode*/ node){
		if(!dojo.string.isBlank(cbox.dataUrl)){
			this.getData(cbox.dataUrl);
		}else{
			// check to see if we can populate the list from <option> elements
			if((node)&&(node.nodeName.toLowerCase() == "select")){
				// NOTE: we're not handling <optgroup> here yet
				var opts = node.getElementsByTagName("option");
				var ol = opts.length;
				var data = [];
				for(var x=0; x<ol; x++){
					var text = opts[x].textContent || opts[x].innerText || opts[x].innerHTML;
					var keyValArr = [String(text), String(opts[x].value)];
					data.push(keyValArr);
					if(opts[x].selected){ 
						cbox.setAllValues(keyValArr[0], keyValArr[1]);
					}
				}
				this.setData(data);
			}
		}
	};

	this.getData = function(/*String*/ url){
		dojo.io.bind({
			url: url,
			load: dojo.lang.hitch(this, function(type, data, evt){ 
				if(!dojo.lang.isArray(data)){
					var arrData = [];
					for(var key in data){
						arrData.push([data[key], key]);
					}
					data = arrData;
				}
				this.setData(data);
			}),
			mimetype: "text/json"
		});
	};

	this.startSearch = function(/*String*/ searchStr, /*String*/ type, /*Boolean*/ ignoreLimit){
		// FIXME: need to add timeout handling here!!
		this._preformSearch(searchStr, type, ignoreLimit);
	};

	this._preformSearch = function(/*String*/ searchStr, /*String*/ type, /*Boolean*/ ignoreLimit){
		//
		//	NOTE: this search is LINEAR, which means that it exhibits perhaps
		//	the worst possible speed characteristics of any search type. It's
		//	written this way to outline the responsibilities and interfaces for
		//	a search.
		//
		var st = type||this.searchType;
		// FIXME: this is just an example search, which means that we implement
		// only a linear search without any of the attendant (useful!) optimizations
		var ret = [];
		if(!this.caseSensitive){
			searchStr = searchStr.toLowerCase();
		}
		for(var x=0; x<this.data.length; x++){
			if((!ignoreLimit)&&(ret.length >= this.searchLimit)){
				break;
			}
			// FIXME: we should avoid copies if possible!
			var dataLabel = new String((!this.caseSensitive) ? this.data[x][0].toLowerCase() : this.data[x][0]);
			if(dataLabel.length < searchStr.length){
				// this won't ever be a good search, will it? What if we start
				// to support regex search?
				continue;
			}

			if(st == "STARTSTRING"){
				if(searchStr == dataLabel.substr(0, searchStr.length)){
					ret.push(this.data[x]);
				}
			}else if(st == "SUBSTRING"){
				// this one is a gimmie
				if(dataLabel.indexOf(searchStr) >= 0){
					ret.push(this.data[x]);
				}
			}else if(st == "STARTWORD"){
				// do a substring search and then attempt to determine if the
				// preceeding char was the beginning of the string or a
				// whitespace char.
				var idx = dataLabel.indexOf(searchStr);
				if(idx == 0){
					// implicit match
					ret.push(this.data[x]);
				}
				if(idx <= 0){
					// if we didn't match or implicily matched, march onward
					continue;
				}
				// otherwise, we have to go figure out if the match was at the
				// start of a word...
				// this code is taken almost directy from nWidgets
				var matches = false;
				while(idx!=-1){
					// make sure the match either starts whole string, or
					// follows a space, or follows some punctuation
					if(" ,/(".indexOf(dataLabel.charAt(idx-1)) != -1){
						// FIXME: what about tab chars?
						matches = true; break;
					}
					idx = dataLabel.indexOf(searchStr, idx+1);
				}
				if(!matches){
					continue;
				}else{
					ret.push(this.data[x]);
				}
			}
		}
		this.provideSearchResults(ret);
	};

	this.provideSearchResults = function(/*Array*/ resultsDataPairs){
	};

	this.addData = function(/*Array*/ pairs){
		// FIXME: incredibly naive and slow!
		this.data = this.data.concat(pairs);
	};

	this.setData = function(/*Array*/ pdata){
		// populate this.data and initialize lookup structures
		this.data = pdata;
	};
	
	if(dataPairs){
		this.setData(dataPairs);
	}
};

dojo.widget.defineWidget(
	"dojo.widget.ComboBox",
	dojo.widget.HtmlWidget,
	{
		// Applies to any renderer
		isContainer: false,
	
		forceValidOption: false,
		searchType: "stringstart",
		dataProvider: null,
	
		startSearch: function(/*String*/ searchString){},
		selectNextResult: function(){},
		selectPrevResult: function(){},
		setSelectedResult: function(){},

		// HTML specific stuff
		autoComplete: true,
		name: "", // clone in the name from the DOM node
		textInputNode: null,
		comboBoxValue: null,
		comboBoxSelectionValue: null,
		optionsListWrapper: null,
		optionsListNode: null,
		downArrowNode: null,
		searchTimer: null,
		searchDelay: 100,
		dataUrl: "",
		fadeTime: 200,
		disabled: false,
		// maxListLength limits list to X visible rows, scroll on rest 
		maxListLength: 8, 
		// mode can also be "remote" for JSON-returning live search or "html" for
		// dumber live search
		mode: "local", 
		selectedResult: null,
		_highlighted_option: null,
		_prev_key_backspace: false,
		_prev_key_esc: false,
		_gotFocus: false,
		_mouseover_list: false,
		dataProviderClass: "dojo.widget.ComboBoxDataProvider",
		buttonSrc: dojo.uri.dojoUri("src/widget/templates/images/combo_box_arrow.png"),

		//the old implementation has builtin fade toggle, so we mimic it here
		dropdownToggle: "fade",

		templatePath: dojo.uri.dojoUri("src/widget/templates/ComboBox.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/ComboBox.css"),


		setValue: function(/*String*/ value){
			this.comboBoxValue.value = value;
			if (this.textInputNode.value != value){ // prevent mucking up of selection
				this.textInputNode.value = value;
				// only change state and value if a new value is set
				dojo.widget.html.stabile.setState(this.widgetId, this.getState(), true);
				this.onValueChanged(value);
			}
		},

		// for user to override
		onValueChanged: function(){ },

		getValue: function(){
			return this.comboBoxValue.value;
		},
	
		getState: function(){
			return {value: this.getValue()};
		},

		setState: function(/*Object*/ state){
			this.setValue(state.value);
		},

		enable:function(){
			this.disabled=false;
			this.isEnabled = true; 
			this.textInputNode.removeAttribute("disabled");
		},
 
		disable: function(){
			this.disabled = true; 
			this.isEnabled = false;
			this.textInputNode.setAttribute("disabled",true); 
		}, 

		getCaretPos: function(/*DomNode*/ element){
			// khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
			if(dojo.lang.isNumber(element.selectionStart)){
				// FIXME: this is totally borked on Moz < 1.3. Any recourse?
				return element.selectionStart;
			}else if(dojo.render.html.ie){
				// in the case of a mouse click in a popup being handled,
				// then the document.selection is not the textarea, but the popup
				// var r = document.selection.createRange();
				// hack to get IE 6 to play nice. What a POS browser.
				var tr = document.selection.createRange().duplicate();
				var ntr = element.createTextRange();
				tr.move("character",0);
				ntr.move("character",0);
				try {
					// If control doesnt have focus, you get an exception.
					// Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
					// There appears to be no workaround for this - googled for quite a while.
					ntr.setEndPoint("EndToEnd", tr);
					return String(ntr.text).replace(/\r/g,"").length;
				} catch (e){
					return 0; // If focus has shifted, 0 is fine for caret pos.
				}
				
			}
		},

		setCaretPos: function(/*DomNode*/ element, /*Number*/ location){
			location = parseInt(location);
			this.setSelectedRange(element, location, location);
		},

		setSelectedRange: function(/*DomNode*/ element, /*Number*/ start, /*Number*/ end){
			if(!end){ end = element.value.length; }  // NOTE: Strange - should be able to put caret at start of text?
			// Mozilla
			// parts borrowed from http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130
			if(element.setSelectionRange){
				element.focus();
				element.setSelectionRange(start, end);
			}else if(element.createTextRange){ // IE
				var range = element.createTextRange();
				with(range){
					collapse(true);
					moveEnd('character', end);
					moveStart('character', start);
					select();
				}
			}else{ //otherwise try the event-creation hack (our own invention)
				// do we need these?
				element.value = element.value;
				element.blur();
				element.focus();
				// figure out how far back to go
				var dist = parseInt(element.value.length)-end;
				var tchar = String.fromCharCode(37);
				var tcc = tchar.charCodeAt(0);
				for(var x = 0; x < dist; x++){
					var te = document.createEvent("KeyEvents");
					te.initKeyEvent("keypress", true, true, null, false, false, false, false, tcc, tcc);
					element.dispatchEvent(te);
				}
			}
		},

		// does the keyboard related stuff
		_handleKeyEvents: function(/*Event*/ evt){
			if(evt.ctrlKey || evt.altKey || !evt.key){ return; }

			// reset these
			this._prev_key_backspace = false;
			this._prev_key_esc = false;

			var k = dojo.event.browser.keys;
			var doSearch = true;

			switch(evt.key){
	 			case k.KEY_DOWN_ARROW:
					if(!this.popupWidget.isShowingNow){
						this.startSearchFromInput();
					}
					this.highlightNextOption();
					dojo.event.browser.stopEvent(evt);
					return;
				case k.KEY_UP_ARROW:
					this.highlightPrevOption();
					dojo.event.browser.stopEvent(evt);
					return;
				case k.KEY_TAB:
					// using linux alike tab for autocomplete
					if(!this.autoComplete && this.popupWidget.isShowingNow && this._highlighted_option){
						dojo.event.browser.stopEvent(evt);
						this.selectOption({ 'target': this._highlighted_option, 'noHide': false});
	
						// put caret last
						this.setSelectedRange(this.textInputNode, this.textInputNode.value.length, null);
					}else{
						this.selectOption();
						return;
					}
					break;
				case k.KEY_ENTER:
					// prevent submitting form if we press enter with list open
					if(this.popupWidget.isShowingNow){
						dojo.event.browser.stopEvent(evt);
					}
					if(this.autoComplete){
						this.selectOption();
						return;
					}
					// fallthrough
				case " ":
					if(this.popupWidget.isShowingNow && this._highlighted_option){
						dojo.event.browser.stopEvent(evt);
						this.selectOption();
						this.hideResultList();
						return;
					}
					break;
				case k.KEY_ESCAPE:
					this.hideResultList();
					this._prev_key_esc = true;
					return;
				case k.KEY_BACKSPACE:
					this._prev_key_backspace = true;
					if(!this.textInputNode.value.length){
						this.setAllValues("", "");
						this.hideResultList();
						doSearch = false;
					}
					break;
				case k.KEY_RIGHT_ARROW: // fall through
				case k.KEY_LEFT_ARROW: // fall through
					doSearch = false;
					break;
				default:// non char keys (F1-F12 etc..)  shouldn't open list
					if(evt.charCode==0){
						doSearch = false;
					}
			}

			if(this.searchTimer){
				clearTimeout(this.searchTimer);
			}
			if(doSearch){
				// if we have gotten this far we dont want to keep our highlight
				this.blurOptionNode();
	
				// need to wait a tad before start search so that the event bubbles through DOM and we have value visible
				this.searchTimer = setTimeout(dojo.lang.hitch(this, this.startSearchFromInput), this.searchDelay);
			}
		},

		// When inputting characters using an input method, such as Asian  
		// languages, it will generate this event instead of onKeyDown event 
		compositionEnd: function(/*Event*/ evt){
			evt.key = evt.keyCode;
			this._handleKeyEvents(evt);
		},

		onKeyUp: function(/*Event*/ evt){
			this.setValue(this.textInputNode.value);
		},

		setSelectedValue: function(/*String*/ value){
			// FIXME, not sure what to do here!
			this.comboBoxSelectionValue.value = value;
		},

		setAllValues: function(/*String*/ value1, /*String*/ value2){
			this.setSelectedValue(value2);
			this.setValue(value1);
		},

		// does the actual highlight
		focusOptionNode: function(/*DomNode*/ node){
			if(this._highlighted_option != node){
				this.blurOptionNode();
				this._highlighted_option = node;
				dojo.html.addClass(this._highlighted_option, "dojoComboBoxItemHighlight");
			}
		},

		// removes highlight on highlighted
		blurOptionNode: function(){
			if(this._highlighted_option){
				dojo.html.removeClass(this._highlighted_option, "dojoComboBoxItemHighlight");
				this._highlighted_option = null;
			}
		},

		highlightNextOption: function(){
			if((!this._highlighted_option) || !this._highlighted_option.parentNode){
				this.focusOptionNode(this.optionsListNode.firstChild);
			}else if(this._highlighted_option.nextSibling){
				this.focusOptionNode(this._highlighted_option.nextSibling);
			}
			dojo.html.scrollIntoView(this._highlighted_option);
		},

		highlightPrevOption: function(){
			if(this._highlighted_option && this._highlighted_option.previousSibling){
				this.focusOptionNode(this._highlighted_option.previousSibling);
			}else{
				this._highlighted_option = null;
				this.hideResultList();
				return;
			}
			dojo.html.scrollIntoView(this._highlighted_option);
		},

		itemMouseOver: function(/*Event*/ evt){
			if (evt.target === this.optionsListNode){ return; }
			this.focusOptionNode(evt.target);
			dojo.html.addClass(this._highlighted_option, "dojoComboBoxItemHighlight");
		},

		itemMouseOut: function(/*Event*/ evt){
			if (evt.target === this.optionsListNode){ return; }
			this.blurOptionNode();
		},

		// reset button size; this function is called when the input area has changed size
		onResize: function(){
			var inputSize = dojo.html.getContentBox(this.textInputNode);
			if( inputSize.height == 0 ){
				// need more time to calculate size
				dojo.lang.setTimeout(this, "onResize", 50);
				return;
			}
			var buttonSize = { width: inputSize.height, height: inputSize.height};
			dojo.html.setContentBox(this.downArrowNode, buttonSize);
		},

		fillInTemplate: function(/*Object*/ args, /*Object*/ frag){
			// For inlining a table we need browser specific CSS
			dojo.html.applyBrowserClass(this.domNode);

			var source = this.getFragNodeRef(frag); 
			if (! this.name && source.name){ this.name = source.name; } 
			this.comboBoxValue.name = this.name; 
			this.comboBoxSelectionValue.name = this.name+"_selected";

			/* different nodes get different parts of the style */
			dojo.html.copyStyle(this.domNode, source);
			dojo.html.copyStyle(this.textInputNode, source);
			dojo.html.copyStyle(this.downArrowNode, source);
			with (this.downArrowNode.style){ // calculate these later
				width = "0px";
				height = "0px";
			}

			var dpClass;
			if(this.mode == "remote"){
				dpClass = dojo.widget.incrementalComboBoxDataProvider;
			}else if(typeof this.dataProviderClass == "string"){
				dpClass = dojo.evalObjPath(this.dataProviderClass)
			}else{
				dpClass = this.dataProviderClass;
			}
			this.dataProvider = new dpClass();
			this.dataProvider.init(this, this.getFragNodeRef(frag));

			this.popupWidget = new dojo.widget.createWidget("PopupContainer", 
				{toggle: this.dropdownToggle, toggleDuration: this.toggleDuration});
			dojo.event.connect(this, 'destroy', this.popupWidget, 'destroy');
			this.optionsListNode = this.popupWidget.domNode;
			this.domNode.appendChild(this.optionsListNode);
			dojo.html.addClass(this.optionsListNode, 'dojoComboBoxOptions');
			dojo.event.connect(this.optionsListNode, 'onclick', this, 'selectOption');
			dojo.event.connect(this.optionsListNode, 'onmouseover', this, '_onMouseOver');
			dojo.event.connect(this.optionsListNode, 'onmouseout', this, '_onMouseOut');
			
			dojo.event.connect(this.optionsListNode, "onmouseover", this, "itemMouseOver");
			dojo.event.connect(this.optionsListNode, "onmouseout", this, "itemMouseOut");
		},

		focus: function(){
			// summary
			//	set focus to input node from code
			this.tryFocus();
		},

		openResultList: function(/*Array*/ results){
			if (!this.isEnabled){
				return;
			}
			this.clearResultList();
			if(!results.length){
				this.hideResultList();
			}

			if(	(this.autoComplete)&&
				(results.length)&&
				(!this._prev_key_backspace)&&
				(this.textInputNode.value.length > 0)){
				var cpos = this.getCaretPos(this.textInputNode);
				// only try to extend if we added the last character at the end of the input
				if((cpos+1) > this.textInputNode.value.length){
					// only add to input node as we would overwrite Capitalisation of chars
					this.textInputNode.value += results[0][0].substr(cpos);
					// build a new range that has the distance from the earlier
					// caret position to the end of the first string selected
					this.setSelectedRange(this.textInputNode, cpos, this.textInputNode.value.length);
				}
			}

			var even = true;
			while(results.length){
				var tr = results.shift();
				if(tr){
					var td = document.createElement("div");
					td.appendChild(document.createTextNode(tr[0]));
					td.setAttribute("resultName", tr[0]);
					td.setAttribute("resultValue", tr[1]);
					td.className = "dojoComboBoxItem "+((even) ? "dojoComboBoxItemEven" : "dojoComboBoxItemOdd");
					even = (!even);
					this.optionsListNode.appendChild(td);
				}
			}

			// show our list (only if we have content, else nothing)
			this.showResultList();
		},

		onFocusInput: function(){
			this._hasFocus = true;
		},

		onBlurInput: function(){
			this._hasFocus = false;
			this._handleBlurTimer(true, 500);
		},

		// collect all blur timers issues here
		_handleBlurTimer: function(/*Boolean*/clear, /*Number*/ millisec){
			if(this.blurTimer && (clear || millisec)){
				clearTimeout(this.blurTimer);
			}
			if(millisec){ // we ignore that zero is false and never sets as that never happens in this widget
				this.blurTimer = dojo.lang.setTimeout(this, "checkBlurred", millisec);
			}
		},
	
		// these 2 are needed in IE and Safari as inputTextNode loses focus when scrolling optionslist
		_onMouseOver: function(/*Event*/ evt){
			if(!this._mouseover_list){
				this._handleBlurTimer(true, 0);
				this._mouseover_list = true;
			}
		},

		_onMouseOut:function(/*Event*/ evt){
			var relTarget = evt.relatedTarget;
			if(!relTarget || relTarget.parentNode!=this.optionsListNode){
				this._mouseover_list = false;
				this._handleBlurTimer(true, 100);
				this.tryFocus();
			}
		},

		_isInputEqualToResult: function(/*String*/ result){
			var input = this.textInputNode.value;
			if(!this.dataProvider.caseSensitive){
				input = input.toLowerCase();
				result = result.toLowerCase();
			}
			return (input == result);
		},

		_isValidOption: function(){
			var tgt = dojo.html.firstElement(this.optionsListNode);
			var isValidOption = false;
			while(!isValidOption && tgt){
				if(this._isInputEqualToResult(tgt.getAttribute("resultName"))){
					isValidOption = true;
				}else{
					tgt = dojo.html.nextElement(tgt);
				}
			}
			return isValidOption;
		},

		checkBlurred: function(){
			if(!this._hasFocus && !this._mouseover_list){
				this.hideResultList();
				// clear the list if the user empties field and moves away.
				if(!this.textInputNode.value.length){
					this.setAllValues("", "");
					return;
				}

				var isValidOption = this._isValidOption();
				// enforce selection from option list
				if(this.forceValidOption && !isValidOption){
					this.setAllValues("", "");
					return;
				}
				if(!isValidOption){// clear
					this.setSelectedValue("");
				}
			}
		},

		sizeBackgroundIframe: function(){
			var mb = dojo.html.getMarginBox(this.optionsListNode);
			if( mb.width==0 || mb.height==0 ){
				// need more time to calculate size
				dojo.lang.setTimeout(this, "sizeBackgroundIframe", 100);
				return;
			}
		},

		selectOption: function(/*Event*/ evt){
			var tgt = null;
			if(!evt){
				evt = { target: this._highlighted_option };
			}

			if(!dojo.html.isDescendantOf(evt.target, this.optionsListNode)){
				// handle autocompletion where the the user has hit ENTER or TAB
	
				// if the input is empty do nothing
				if(!this.textInputNode.value.length){
					return;
				}
				tgt = dojo.html.firstElement(this.optionsListNode);

				// user has input value not in option list
				if(!tgt || !this._isInputEqualToResult(tgt.getAttribute("resultName"))){
					return;
				}
				// otherwise the user has accepted the autocompleted value
			}else{
				tgt = evt.target; 
			}

			while((tgt.nodeType!=1)||(!tgt.getAttribute("resultName"))){
				tgt = tgt.parentNode;
				if(tgt === dojo.body()){
					return false;
				}
			}

			this.selectedResult = [tgt.getAttribute("resultName"), tgt.getAttribute("resultValue")];
			this.setAllValues(tgt.getAttribute("resultName"), tgt.getAttribute("resultValue"));
			if(!evt.noHide){
				this.hideResultList();
				this.setSelectedRange(this.textInputNode, 0, null);
			}
			this.tryFocus();
		},

		clearResultList: function(){
			if(this.optionsListNode.innerHTML){
				this.optionsListNode.innerHTML = "";  // browser natively knows how to collect this memory
			}
		},

		hideResultList: function(){
			this.popupWidget.close();
		},

		showResultList: function(){
			// Our dear friend IE doesnt take max-height so we need to calculate that on our own every time
			var childs = this.optionsListNode.childNodes;
			if(childs.length){
				var visibleCount = this.maxListLength;
				if(childs.length < visibleCount){
					visibleCount = childs.length;
				}

				with(this.optionsListNode.style)
				{
					display = "";
					if(visibleCount == childs.length){
						//no scrollbar is required, so unset height to let browser calcuate it,
						//as in css, overflow is already set to auto
						height = "";
					}else{
						//show it first to get the correct dojo.style.getOuterHeight(childs[0])
						//FIXME: shall we cache the height of the item?
						height = visibleCount * dojo.html.getMarginBox(childs[0]).height +"px";
					}
					width = (dojo.html.getMarginBox(this.domNode).width-2)+"px";
					
				}
				this.popupWidget.open(this.domNode, this, this.downArrowNode);
			}else{
				this.hideResultList();
			}
		},

		handleArrowClick: function(){
			this._handleBlurTimer(true, 0);
			this.tryFocus();
			if(this.popupWidget.isShowingNow){
				this.hideResultList();
			}else{
				// forces full population of results, if they click
				// on the arrow it means they want to see more options
				this.startSearch("");
			}
		},

		tryFocus: function(){
			try {
				this.textInputNode.focus();
			} catch (e){
				// element isn't focusable if disabled, or not visible etc - not easy to test for.
	 		};
		},

		startSearchFromInput: function(){
			this.startSearch(this.textInputNode.value);
		},

		postCreate: function(){
			this.onResize();
			dojo.event.connect(this, "startSearch", this.dataProvider, "startSearch");
			dojo.event.connect(this.dataProvider, "provideSearchResults", this, "openResultList");
			dojo.event.connect(this.textInputNode, "onblur", this, "onBlurInput");
			dojo.event.connect(this.textInputNode, "onfocus", this, "onFocusInput");
			if (this.disabled){ 
				this.disable();
			}
			var s = dojo.widget.html.stabile.getState(this.widgetId);
			if (s){
				this.setState(s);
			}
		}
	}
);

__CPAN_FILE__ src/widget/SplitContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.SplitContainer");

//
// TODO
// make it prettier
// active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
//

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.html.style");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.selection");
dojo.require("dojo.io.cookie");

dojo.widget.defineWidget(
	"dojo.widget.SplitContainer",
	dojo.widget.HtmlWidget,
	function(){
		this.sizers = [];
	},
{
	isContainer: true,

	// variables
	virtualSizer: null,
	isHorizontal: null,
	paneBefore: null,
	paneAfter: null,
	isSizing: false,
	dragOffset: 0,
	startPoint: 0,
	lastPoint: 0,
	sizingSplitter: null,
	screenToClientOffset: 0,
	isDraggingLeft: 0,
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/SplitContainer.css"),
	originPos: 0,

	// parameters (user settable)
	activeSizing: false,
	sizerWidth: 15,
	orientation: 'horizontal',
	persist: true,		// save splitter positions in a cookie

	debugName: '',

	fillInTemplate: function(){

		dojo.html.insertCssFile(this.templateCssPath, null, true);
		dojo.html.addClass(this.domNode, "dojoSplitContainer");
		// overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
		// to keep other combined css classes from inadvertantly making the overflow visible
		if (dojo.render.html.moz) {
		        this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
		}
		
		var content = dojo.html.getContentBox(this.domNode);
		this.paneWidth = content.width;
		this.paneHeight = content.height;

		this.isHorizontal = (this.orientation == 'horizontal');

		//dojo.debug("fillInTemplate for "+this.debugName);
	},

	onResized: function(e){
		var content = dojo.html.getContentBox(this.domNode);
		this.paneWidth = content.width;
		this.paneHeight = content.height;
		this.layoutPanels();
	},

	postCreate: function(args, fragment, parentComp){

		// dojo.debug("post create for "+this.debugName);

		// attach the children and create the draggers
		for(var i=0; i<this.children.length; i++){
            with(this.children[i].domNode.style){
                position = "absolute";
            }
            dojo.html.addClass(this.children[i].domNode,
                "dojoSplitPane");

            if(i == this.children.length-1){
                break;
            }

            this._addSizer();
		}

		// create the fake dragger
		if (typeof this.sizerWidth == "object") { 
			try {
				this.sizerWidth = parseInt(this.sizerWidth.toString()); 
			} catch(e) { this.sizerWidth = 15; }
		}
		this.virtualSizer = document.createElement('div');
		this.virtualSizer.style.position = 'absolute';
		this.virtualSizer.style.display = 'none';
		//this.virtualSizer.style.backgroundColor = 'lime';
		this.virtualSizer.style.zIndex = 10;
		this.virtualSizer.className = this.isHorizontal ? 'dojoSplitContainerVirtualSizerH' : 'dojoSplitContainerVirtualSizerV';
		this.domNode.appendChild(this.virtualSizer);

		dojo.html.disableSelection(this.virtualSizer);

		if(this.persist){
			this.restoreState();
		}

		// size the panels once the browser has caught up
		this.resizeSoon();
	},

    _injectChild: function(child) {
        with(child.domNode.style){
            position = "absolute";
        }
        dojo.html.addClass(child.domNode,
            "dojoSplitPane");
    },

    _addSizer: function() {
        var i = this.sizers.length;

        this.sizers[i] = document.createElement('div');
        this.sizers[i].style.position = 'absolute';
        this.sizers[i].className = this.isHorizontal ? 'dojoSplitContainerSizerH' : 'dojoSplitContainerSizerV';

        var self = this;
        var handler = (function(){ var sizer_i = i; return function(e){ self.beginSizing(e, sizer_i); } })();
        dojo.event.connect(this.sizers[i], "onmousedown", handler);

        this.domNode.appendChild(this.sizers[i]);
        dojo.html.disableSelection(this.sizers[i]);
    },

    removeChild: function(widget){
        // Remove sizer, but only if widget is really our child and
        // we have at least one sizer to throw away
        if (this.sizers.length > 0) {
            for(var x=0; x<this.children.length; x++){
                if(this.children[x] === widget){
                    var i = this.sizers.length - 1;
                    this.domNode.removeChild(this.sizers[i]);
                    this.sizers.length = i;
                    break;
                }
            }
        }

        // Remove widget and repaint
        dojo.widget.SplitContainer.superclass.removeChild.call(this, widget, arguments);
        this.onResized();
    },

    addChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
        dojo.widget.SplitContainer.superclass.addChild.call(this, widget, overrideContainerNode, pos, ref, insertIndex);
        this._injectChild(widget);

        if (this.children.length > 1) {
            this._addSizer();
        }

        this.layoutPanels();
    },

    layoutPanels: function(){
        if (this.children.length == 0){ return; }

		//
		// calculate space
		//

		var space = this.isHorizontal ? this.paneWidth : this.paneHeight;

		if (this.children.length > 1){

			space -= this.sizerWidth * (this.children.length - 1);
		}


		//
		// calculate total of SizeShare values
		//

		var out_of = 0;

		for(var i=0; i<this.children.length; i++){

			out_of += this.children[i].sizeShare;
		}


		//
		// work out actual pixels per sizeshare unit
		//

		var pix_per_unit = space / out_of;


		//
		// set the SizeActual member of each pane
		//

		var total_size = 0;

		for(var i=0; i<this.children.length-1; i++){

			var size = Math.round(pix_per_unit * this.children[i].sizeShare);
			this.children[i].sizeActual = size;
			total_size += size;
		}
		this.children[this.children.length-1].sizeActual = space - total_size;

		//
		// make sure the sizes are ok
		//

		this.checkSizes();


		//
		// now loop, positioning each pane and letting children resize themselves
		//

		var pos = 0;
		var size = this.children[0].sizeActual;
		this.movePanel(this.children[0].domNode, pos, size);
		this.children[0].position = pos;
		this.children[0].checkSize();
		pos += size;

		for(var i=1; i<this.children.length; i++){

			// first we position the sizing handle before this pane
			this.movePanel(this.sizers[i-1], pos, this.sizerWidth);
			this.sizers[i-1].position = pos;
			pos += this.sizerWidth;

			size = this.children[i].sizeActual;
			this.movePanel(this.children[i].domNode, pos, size);
			this.children[i].position = pos;
			this.children[i].checkSize();
			pos += size;
		}
	},

	movePanel: function(panel, pos, size){
		if (this.isHorizontal){
			panel.style.left = pos + 'px';
			panel.style.top = 0;

			dojo.html.setMarginBox(panel, { width: size, height: this.paneHeight });
		}else{
			panel.style.left = 0;
			panel.style.top = pos + 'px';

			dojo.html.setMarginBox(panel, { width: this.paneWidth, height: size });
		}
	},

	growPane: function(growth, pane){

		if (growth > 0){
			if (pane.sizeActual > pane.sizeMin){
				if ((pane.sizeActual - pane.sizeMin) > growth){

					// stick all the growth in this pane
					pane.sizeActual = pane.sizeActual - growth;
					growth = 0;
				}else{
					// put as much growth in here as we can
					growth -= pane.sizeActual - pane.sizeMin;
					pane.sizeActual = pane.sizeMin;
				}
			}
		}
		return growth;
	},

	checkSizes: function(){

		var total_min_size = 0;
		var total_size = 0;

		for(var i=0; i<this.children.length; i++){

			total_size += this.children[i].sizeActual;
			total_min_size += this.children[i].sizeMin;
		}

		// only make adjustments if we have enough space for all the minimums

		if (total_min_size <= total_size){

			var growth = 0;

			for(var i=0; i<this.children.length; i++){

				if (this.children[i].sizeActual < this.children[i].sizeMin){

					growth += this.children[i].sizeMin - this.children[i].sizeActual;
					this.children[i].sizeActual = this.children[i].sizeMin;
				}
			}

			if (growth > 0){
				if (this.isDraggingLeft){
					for(var i=this.children.length-1; i>=0; i--){
						growth = this.growPane(growth, this.children[i]);
					}
				}else{
					for(var i=0; i<this.children.length; i++){
						growth = this.growPane(growth, this.children[i]);
					}
				}
			}
		}else{

			for(var i=0; i<this.children.length; i++){
				this.children[i].sizeActual = Math.round(total_size * (this.children[i].sizeMin / total_min_size));
			}
		}
	},

	beginSizing: function(e, i){
		this.paneBefore = this.children[i];
		this.paneAfter = this.children[i+1];

		this.isSizing = true;
		this.sizingSplitter = this.sizers[i];
		this.originPos = dojo.html.getAbsolutePosition(this.children[0].domNode, true, dojo.html.boxSizing.MARGIN_BOX);
		if (this.isHorizontal){
			var client = (e.layerX ? e.layerX : e.offsetX);
			var screen = e.pageX;
			this.originPos = this.originPos.x;
		}else{
			var client = (e.layerY ? e.layerY : e.offsetY);
			var screen = e.pageY;
			this.originPos = this.originPos.y;
		}
		this.startPoint = this.lastPoint = screen;
		this.screenToClientOffset = screen - client;
		this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;

		if (!this.activeSizing){
			this.showSizingLine();
		}

		//
		// attach mouse events
		//

		dojo.event.connect(document.documentElement, "onmousemove", this, "changeSizing");
		dojo.event.connect(document.documentElement, "onmouseup", this, "endSizing");
		dojo.event.browser.stopEvent(e);
	},

	changeSizing: function(e){
		this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
		if (this.activeSizing){
			this.movePoint();
			this.updateSize();
		}else{
			this.movePoint();
			this.moveSizingLine();
		}
		dojo.event.browser.stopEvent(e);
	},

	endSizing: function(e){

		if (!this.activeSizing){
			this.hideSizingLine();
		}

		this.updateSize();

		this.isSizing = false;

		dojo.event.disconnect(document.documentElement, "onmousemove", this, "changeSizing");
		dojo.event.disconnect(document.documentElement, "onmouseup", this, "endSizing");
		
		if(this.persist){
			this.saveState(this);
		}
	},

	movePoint: function(){

		// make sure lastPoint is a legal point to drag to
		var p = this.lastPoint - this.screenToClientOffset;

		var a = p - this.dragOffset;
		a = this.legaliseSplitPoint(a);
		p = a + this.dragOffset;

		this.lastPoint = p + this.screenToClientOffset;
	},

	legaliseSplitPoint: function(a){

		a += this.sizingSplitter.position;

		this.isDraggingLeft = (a > 0) ? 1 : 0;

		if (!this.activeSizing){

			if (a < this.paneBefore.position + this.paneBefore.sizeMin){

				a = this.paneBefore.position + this.paneBefore.sizeMin;
			}

			if (a > this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin))){

				a = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
			}
		}

		a -= this.sizingSplitter.position;

		this.checkSizes();

		return a;
	},

	updateSize: function(){
		var pos = this.lastPoint - this.dragOffset - this.originPos;

		var start_region = this.paneBefore.position;
		var end_region   = this.paneAfter.position + this.paneAfter.sizeActual;

		this.paneBefore.sizeActual = pos - start_region;
		this.paneAfter.position    = pos + this.sizerWidth;
		this.paneAfter.sizeActual  = end_region - this.paneAfter.position;

		for(var i=0; i<this.children.length; i++){

			this.children[i].sizeShare = this.children[i].sizeActual;
		}

		this.layoutPanels();
	},

	showSizingLine: function(){

		this.moveSizingLine();

		if (this.isHorizontal){
			dojo.html.setMarginBox(this.virtualSizer, { width: this.sizerWidth, height: this.paneHeight });
		}else{
			dojo.html.setMarginBox(this.virtualSizer, { width: this.paneWidth, height: this.sizerWidth });
		}

		this.virtualSizer.style.display = 'block';
	},

	hideSizingLine: function(){
		this.virtualSizer.style.display = 'none';
	},

	moveSizingLine: function(){
		var pos = this.lastPoint - this.startPoint + this.sizingSplitter.position;
		if (this.isHorizontal){
			this.virtualSizer.style.left = pos + 'px';
		}else{
			var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
			this.virtualSizer.style.top = pos + 'px';
		}

	},
	
	_getCookieName: function(i) {
		return this.widgetId + "_" + i;
	},

	restoreState: function () {
		for(var i=0; i<this.children.length; i++) {
			var cookieName = this._getCookieName(i);
			var cookieValue = dojo.io.cookie.getCookie(cookieName);
			if (cookieValue != null) {
				var pos = parseInt(cookieValue);
				if (typeof pos == "number") {
					this.children[i].sizeShare=pos;
				}
			}
		}
	},

	saveState: function (){
		for(var i=0; i<this.children.length; i++) {
			var cookieName = this._getCookieName(i);
			dojo.io.cookie.setCookie(cookieName, this.children[i].sizeShare, null, null, null, null);
		}
	}
});

// These arguments can be specified for the children of a SplitContainer.
// Since any widget can be specified as a SplitContainer child, mix them
// into the base widget class.  (This is a hack, but it's effective.)
dojo.lang.extend(dojo.widget.Widget, {
	sizeMin: 10,
	sizeShare: 10
});

// Deprecated class for split pane children.
// Actually any widget can be the child of a split pane
dojo.widget.defineWidget(
	"dojo.widget.SplitContainerPanel",
	dojo.widget.ContentPane,
	{}
);


__CPAN_FILE__ src/widget/FloatingPane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.FloatingPane");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Manager");
dojo.require("dojo.html.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.iframe");
dojo.require("dojo.html.selection");
dojo.require("dojo.lfx.shadow");
dojo.require("dojo.widget.html.layout");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.dnd.HtmlDragMove");
dojo.require("dojo.widget.Dialog");		// for ModalFloatingPane
dojo.require("dojo.widget.ResizeHandle");

// summary
//	Base class for FloatingPane, ModalFloatingPane
dojo.declare(
	"dojo.widget.FloatingPaneBase",
	null,
	{
		// String
		//	text to display in floating pane's title bar (ex: "My Window")
		title: '',
		
		// String
		//	path of icon to display in floating pane's title bar
		iconSrc: '',
		
		// Boolean
		//	if true, display a shadow behind the floating pane
		hasShadow: false,
		
		// Boolean
		//	if true, and the floating pane is inside another container (ContentPane, another FloatingPane, etc.),
		//	then don't allow the floating pane to be dragged outside of it's container
		constrainToContainer: false,
		
		// String
		//	widget id of TaskBar widget;
		//	if specified, then an icon for this FloatingPane will be added to the specified TaskBar
		taskBarId: "",
		
		// Boolean
		//	if true, allow user to resize floating pane
		resizable: true,
		
		// Boolean
		//	if true, display title bar for this floating pane
		titleBarDisplay: true,

		// String
		//	control whether window is initially not displayed ("minimized"), displayed full screen ("maximized"),
		//	or just displayed normally ("normal")
		// Values
		//	"normal", "maximized", "minimized"
		windowState: "normal",
		
		// Boolean
		//	display button to close window
		displayCloseAction: false,
		
		// Boolean
		//	display button to minimize window (ie, window disappears so only the taskbar item remains)
		displayMinimizeAction: false,

		// Boolean
		//	display button to maximize window (ie, to take up the full screen)
		displayMaximizeAction: false,

		// Related to connecting to taskbar
		// TODO: use topics rather than repeated connect attempts?
		_max_taskBarConnectAttempts: 5,
		_taskBarConnectAttempts: 0,

		templatePath: dojo.uri.dojoUri("src/widget/templates/FloatingPane.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/FloatingPane.css"),

		fillInFloatingPaneTemplate: function(args, frag){
			// summary: this should be called by fillInTemplate() of the widget that I'm mixed into

			// Copy style info from input node to output node
			var source = this.getFragNodeRef(frag);
			dojo.html.copyStyle(this.domNode, source);
	
			// necessary for safari, khtml (for computing width/height)
			dojo.body().appendChild(this.domNode);
	
			// if display:none then state=minimized, otherwise state=normal
			if(!this.isShowing()){
				this.windowState="minimized";
			}
	
			// <img src=""> can hang IE!  better get rid of it
			if(this.iconSrc==""){
				dojo.html.removeNode(this.titleBarIcon);
			}else{
				this.titleBarIcon.src = this.iconSrc.toString();// dojo.uri.Uri obj req. toString()
			}
	
			if(this.titleBarDisplay){	
				this.titleBar.style.display="";
				dojo.html.disableSelection(this.titleBar);
	
				this.titleBarIcon.style.display = (this.iconSrc=="" ? "none" : "");
	
				this.minimizeAction.style.display = (this.displayMinimizeAction ? "" : "none");
				this.maximizeAction.style.display= 
					(this.displayMaximizeAction && this.windowState!="maximized" ? "" : "none");
				this.restoreAction.style.display= 
					(this.displayMaximizeAction && this.windowState=="maximized" ? "" : "none");
				this.closeAction.style.display= (this.displayCloseAction ? "" : "none");
	
				this.drag = new dojo.dnd.HtmlDragMoveSource(this.domNode);	
				if (this.constrainToContainer) {
					this.drag.constrainTo();
				}
				this.drag.setDragHandle(this.titleBar);
	
				var self = this;
	
				dojo.event.topic.subscribe("dragMove",
					function (info){
						if (info.source.domNode == self.domNode){
							dojo.event.topic.publish('floatingPaneMove', { source: self } );
						}
					}
				);
			}
	
			if(this.resizable){
				this.resizeBar.style.display="";
				this.resizeHandle = dojo.widget.createWidget("ResizeHandle", {targetElmId: this.widgetId, id:this.widgetId+"_resize"});
				this.resizeBar.appendChild(this.resizeHandle.domNode);
			}
	
			// add a drop shadow
			if(this.hasShadow){
				this.shadow=new dojo.lfx.shadow(this.domNode);
			}
	
			// Prevent IE bleed-through problem
			this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
	
			if( this.taskBarId ){
				this._taskBarSetup();
			}
	
			// counteract body.appendChild above
			dojo.body().removeChild(this.domNode);
		},
	
		postCreate: function(){
			if (dojo.hostenv.post_load_) {
				this._setInitialWindowState();
			} else {
				dojo.addOnLoad(this, "_setInitialWindowState");
			}
		},
	
		maximizeWindow: function(/*Event*/ evt) {
			// summary: maximize the window
			var mb = dojo.html.getMarginBox(this.domNode);
			this.previous={
				width: mb.width || this.width,
				height: mb.height || this.height,
				left: this.domNode.style.left,
				top: this.domNode.style.top,
				bottom: this.domNode.style.bottom,
				right: this.domNode.style.right
			};
			if(this.domNode.parentNode.style.overflow.toLowerCase() != 'hidden'){
				this.parentPrevious={
					overflow: this.domNode.parentNode.style.overflow
				};
				dojo.debug(this.domNode.parentNode.style.overflow);
				this.domNode.parentNode.style.overflow = 'hidden';
			}

			this.domNode.style.left =
				dojo.html.getPixelValue(this.domNode.parentNode, "padding-left", true) + "px";
			this.domNode.style.top =
				dojo.html.getPixelValue(this.domNode.parentNode, "padding-top", true) + "px";

			if ((this.domNode.parentNode.nodeName.toLowerCase() == 'body')) {
				var viewport = dojo.html.getViewport();
				var padding = dojo.html.getPadding(dojo.body());
				this.resizeTo(viewport.width-padding.width, viewport.height-padding.height);
			} else {
				var content = dojo.html.getContentBox(this.domNode.parentNode);
				this.resizeTo(content.width, content.height);
			}
			this.maximizeAction.style.display="none";
			this.restoreAction.style.display="";

			//disable resize and drag
			if(this.resizeHandle){
				this.resizeHandle.domNode.style.display="none";
			}
			this.drag.setDragHandle(null);

			this.windowState="maximized";
		},
	
		minimizeWindow: function(/*Event*/ evt) {
			// summary: hide the window so that only the icon in the taskbar is shown
			this.hide();
			for(var attr in this.parentPrevious){
				this.domNode.parentNode.style[attr] = this.parentPrevious[attr];
			}
			this.lastWindowState = this.windowState;
			this.windowState = "minimized";
		},
	
		restoreWindow: function(/*Event*/ evt) {
			// summary: set the winow to normal size (neither maximized nor minimized)
			if (this.windowState=="minimized") {
				this.show();
				if(this.lastWindowState == "maximized"){
					this.domNode.parentNode.style.overflow = 'hidden';
					this.windowState="maximized";
				}else{ //normal
					this.windowState="normal";
				}
			} else if (this.windowState=="maximized"){
				for(var attr in this.previous){
					this.domNode.style[attr] = this.previous[attr];
				}
				for(var attr in this.parentPrevious){
					this.domNode.parentNode.style[attr] = this.parentPrevious[attr];
				}
				this.resizeTo(this.previous.width, this.previous.height);
				this.previous=null;
				this.parentPrevious=null;

				this.restoreAction.style.display="none";
				this.maximizeAction.style.display=this.displayMaximizeAction ? "" : "none";

				if(this.resizeHandle){
					this.resizeHandle.domNode.style.display="";
				}
				this.drag.setDragHandle(this.titleBar);
				this.windowState="normal";
			} else { //normal
				// do nothing
			}
		},

		toggleDisplay: function(){
			// summary: switch between hidden mode and displayed mode (either maximized or normal, depending on state before window was minimized)
			if(this.windowState=="minimized"){
				this.restoreWindow();
			}else{
				this.minimizeWindow();
			}
		},

		closeWindow: function(/*Event*/ evt) {
			// summary: destroy this window
			dojo.html.removeNode(this.domNode);
			this.destroy();
		},
	
		onMouseDown: function(/*Event*/ evt) {
			// summary: callback when user clicks anywhere on the floating pane
			this.bringToTop();
		},
	
		bringToTop: function() {
			// summary
			//	all the floating panes are stacked in z-index order; bring this floating pane to the top of that stack,
			//	so that it's displayed in front of all the other floating panes
			var floatingPanes= dojo.widget.manager.getWidgetsByType(this.widgetType);
			var windows = [];
			for (var x=0; x<floatingPanes.length; x++) {
				if (this.widgetId != floatingPanes[x].widgetId) {
						windows.push(floatingPanes[x]);
				}
			}
	
			windows.sort(function(a,b) {
				return a.domNode.style.zIndex - b.domNode.style.zIndex;
			});
			
			windows.push(this);
	
			var floatingPaneStartingZ = 100;
			for (x=0; x<windows.length;x++) {
				windows[x].domNode.style.zIndex = floatingPaneStartingZ + x*2;
			}
		},
	
		_setInitialWindowState: function() {
			if(this.isShowing()){
				this.width=-1;	// force resize
				var mb = dojo.html.getMarginBox(this.domNode);
				this.resizeTo(mb.width, mb.height);
			}
			if (this.windowState == "maximized") {
				this.maximizeWindow();
				this.show();
				return;
			}
	
			if (this.windowState=="normal") {
				this.show();
				return;
			}
	
			if (this.windowState=="minimized") {
				this.hide();
				return;
			}
	
			this.windowState="minimized";
		},
	
		_taskBarSetup: function() {
			// summary: add icon to task bar, connected to me
			var taskbar = dojo.widget.getWidgetById(this.taskBarId);
			if (!taskbar){
				if (this._taskBarConnectAttempts <  this._max_taskBarConnectAttempts) {
					dojo.lang.setTimeout(this, this._taskBarSetup, 50);
					this._taskBarConnectAttempts++;
				} else {
					dojo.debug("Unable to connect to the taskBar");
				}
				return;
			}
			taskbar.addChild(this);
		},

		showFloatingPane: function(){
			// summary:
			//	bring this floating pane to the top
			this.bringToTop();
		},

		onFloatingPaneShow: function(){
			// summary: callback for when someone calls FloatingPane.show
			var mb = dojo.html.getMarginBox(this.domNode);
			this.resizeTo(mb.width, mb.height);
		},
	
		// summary: set the floating pane to the given size
		resizeTo: function(/*Integer*/ width, /*Integer*/ height){
			dojo.html.setMarginBox(this.domNode, { width: width, height: height });
	
			dojo.widget.html.layout(this.domNode,
				[
				  {domNode: this.titleBar, layoutAlign: "top"},
				  {domNode: this.resizeBar, layoutAlign: "bottom"},
				  {domNode: this.containerNode, layoutAlign: "client"}
				] );
	
			// If any of the children have layoutAlign specified, obey it
			dojo.widget.html.layout(this.containerNode, this.children, "top-bottom");
			
			this.bgIframe.onResized();
			if(this.shadow){ this.shadow.size(width, height); }
			this.onResized();
		},
	
		checkSize: function() {
			// summary
			//	checkSize() is called when the user has resized the browser window,
			// 	but that doesn't affect this widget (or this widget's children)
			// 	so it can be safely ignored...
			// TODO: unless we are maximized.  then we should resize ourself.
		}
	}
);

// summary
//	A non-modal floating window.
//	Attaches to a Taskbar which has an icon for each window.
//	Must specify size (like style="width: 500px; height: 500px;"),
dojo.widget.defineWidget(
	"dojo.widget.FloatingPane",
	[dojo.widget.ContentPane, dojo.widget.FloatingPaneBase], 
{
	fillInTemplate: function(args, frag){	
		this.fillInFloatingPaneTemplate(args, frag);
		dojo.widget.FloatingPane.superclass.fillInTemplate.call(this, args, frag);
	},
	postCreate: function(){
		dojo.widget.FloatingPaneBase.prototype.postCreate.apply(this, arguments);
		dojo.widget.FloatingPane.superclass.postCreate.apply(this, arguments);
	},
	show: function(){
		dojo.widget.FloatingPane.superclass.show.apply(this, arguments);
		this.showFloatingPane();
	},
	onShow: function(){
		dojo.widget.FloatingPane.superclass.onShow.call(this);
		this.onFloatingPaneShow();
	}
});


// summary
//	A modal floating window.
//	This widget is similar to the Dialog widget, but the window, unlike the Dialog, can be moved.
//	Must specify size (like style="width: 500px; height: 500px;"),
dojo.widget.defineWidget(
	"dojo.widget.ModalFloatingPane",
	[dojo.widget.FloatingPane, dojo.widget.ModalDialogBase],
	{
		windowState: "minimized",
		displayCloseAction: true,
		postCreate: function(){
			dojo.widget.ModalDialogBase.prototype.postCreate.call(this);
			dojo.widget.ModalFloatingPane.superclass.postCreate.call(this);
		},
		show: function(){
			dojo.widget.ModalFloatingPane.superclass.show.apply(this, arguments);
			this.showModalDialog();
			this.placeModalDialog();
			//place the background div under this modal pane
			this.shared.bg.style.zIndex = this.domNode.style.zIndex-1;
		},
		hide: function(){
			this.hideModalDialog();
			dojo.widget.ModalFloatingPane.superclass.hide.apply(this, arguments);
		},
		closeWindow: function(){
			this.hide();
			dojo.widget.ModalFloatingPane.superclass.closeWindow.apply(this, arguments);
		}
	}
);

__CPAN_FILE__ src/widget/YahooMap.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.YahooMap");
dojo.require("dojo.event.*");
dojo.require("dojo.math");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

(function(){
	var yappid = djConfig["yAppId"]||djConfig["yahooAppId"]||"dojotoolkit";
	if(!dojo.hostenv.post_load_){
		if(yappid == "dojotoolkit"){
			dojo.debug("please provide a unique Yahoo App ID in djConfig.yahooAppId when using the map widget");
		}
		var tag = "<scr"+"ipt src='http://api.maps.yahoo.com/ajaxymap?v=3.0&appid="+yappid+"'></scri"+"pt>";
		if(!dj_global["YMap"]){
			document.write(tag);
		}
	}else{
		dojo.debug("cannot initialize map system after the page has been loaded! Please either manually include the script block provided by Yahoo in your page or require() the YahooMap widget before onload has fired");
	}
})();

dojo.widget.defineWidget(
	"dojo.widget.YahooMap",
	dojo.widget.HtmlWidget,
	function(){
		//	summary
		//	Initialize properties of the widget.
		this.map=null;
		this.datasrc="";
		this.data=[];
		this.width=0;
		this.height=0;
		this.controls=["zoomlong","maptype","pan"];
	},
{
	isContainer: false,
	templatePath:null,
	templateCssPath:null,

	findCenter:function(/* array */aPts){
		//	summary
		//	Find the center lat/lng coordinate based on the passed points.
		var start=new YGeoPoint(37,-90);
		if(aPts.length==0) return start;
		var minLat,maxLat, minLon, maxLon, cLat, cLon;
		minLat=maxLat=aPts[0].Lat;
		minLon=maxLon=aPts[0].Lon;
		for(var i=0; i<aPts.length; i++){
			minLat=Math.min(minLat,aPts[i].Lat);
			maxLat=Math.max(maxLat,aPts[i].Lat);
			minLon=Math.min(minLon,aPts[i].Lon);
			maxLon=Math.max(maxLon,aPts[i].Lon);
		}
		cLat=dojo.math.round((minLat+maxLat)/2,6);
		cLon=dojo.math.round((minLon+maxLon)/2,6);
		return new YGeoPoint(cLat,cLon);	//	YGeoPoint
	},
	setControls:function(){
		//	summary
		//	Set the controls on the map
		var methodmap={
			maptype:"addTypeControl",
			pan:"addPanControl",
			zoomlong:"addZoomLong",
			zoomshort:"addZoomShort"
		}
		var c=this.controls;
		for(var i=0; i<c.length; i++){
			var controlMethod=methodmap[c[i].toLowerCase()];
			if(this.map[controlMethod]){
				this.map[controlMethod]();
			}
		}
	},
	
	parse:function(/* HTMLTable */table){
		//	summary
		//	Parses an HTML table for data to plot on the map.
		this.data=[];

		//	get the column indices
		var h=table.getElementsByTagName("thead")[0];
		if(!h){
			return;
		}

		var a=[];
		var cols=h.getElementsByTagName("td");
		if(cols.length==0){
			cols=h.getElementsByTagName("th");
		}
		for(var i=0; i<cols.length; i++){
			var c=cols[i].innerHTML.toLowerCase();
			if(c=="long") c="lng";
			a.push(c);
		}
		
		//	parse the data
		var b=table.getElementsByTagName("tbody")[0];
		if(!b){
			return;
		}
		for(var i=0; i<b.childNodes.length; i++){
			if(!(b.childNodes[i].nodeName&&b.childNodes[i].nodeName.toLowerCase()=="tr")){
				continue;
			}
			var cells=b.childNodes[i].getElementsByTagName("td");
			var o={};
			for(var j=0; j<a.length; j++){
				var col=a[j];
				if(col=="lat"||col=="lng"){
					o[col]=parseFloat(cells[j].innerHTML);					
				}else{
					o[col]=cells[j].innerHTML;
				}
			}
			this.data.push(o);
		}
	},
	render:function(){
		//	summary
		//	Plots all points in internal data array on the map.
		var pts=[];
		var d=this.data;
		for(var i=0; i<d.length; i++){
			var pt=new YGeoPoint(d[i].lat, d[i].lng);
			pts.push(pt);
			var icon=d[i].icon||null;
			if(icon){
				icon=new YImage(icon);
			}
			var m=new YMarker(pt,icon);
			if(d[i].description){
				m.addAutoExpand("<div>"+d[i].description+"</div>");
			}
			this.map.addOverlay(m);
		}
		var c=this.findCenter(pts);
		var z=this.map.getZoomLevel(pts);
		this.map.drawZoomAndCenter(c,z);
	},
	
	initialize:function(/* object */args, /* object */frag){
		//	summary
		//	Initialize the widget.
		if(!YMap || !YGeoPoint){
			dojo.raise("dojo.widget.YahooMap: The Yahoo Map script must be included in order to use this widget.");
		}
		if(this.datasrc){
			this.parse(dojo.byId(this.datasrc));
		}
		else if(this.domNode.getElementsByTagName("table")[0]){
			this.parse(this.domNode.getElementsByTagName("table")[0]);
		}
	},
	postCreate:function(){
		//	summary
		//	Finalize and plot all points on the widget.
		while(this.domNode.childNodes.length>0){
			this.domNode.removeChild(this.domNode.childNodes[0]);
		}

		if(this.width>0&&this.height>0){
			this.map=new YMap(this.domNode, YAHOO_MAP_REG, new YSize(this.width, this.height));
		}else{
			this.map=new YMap(this.domNode);
		}
		this.setControls();
		this.render();
	}
});

__CPAN_FILE__ src/widget/TreeDemo.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeDemo");
dojo.require("dojo.Deferred");

dojo.widget.TreeDemo = {
	
	reportIfDefered: function(res) {
		if (res instanceof dojo.Deferred) {			
			res.addCallbacks(
				function(res) { /* dojo.debug("OK " + (res ? res: '')); */ return res },
				function(err) { dojo.debug("Error"); dojo.debugShallow(err); }
			);
		}		
	},
	
	resetRandomChildren: function(maxCount) {
		this.randomChildrenMaxCount = maxCount;
		this.randomChildrenCount = 0;
		this.randomChildrenDepth = 0;
	},
	
	
	makeRandomChildren: function(title) {		

		this.randomChildrenDepth++;
			
		var children = [];
		for (var i=1; i<=5; i++) {				

			var t = title+(this.randomChildrenDepth==1 ? '' : '.')+i;
			var node = {title: t};
				
			children.push(node);		
			this.randomChildrenCount++	
			if (this.randomChildrenCount >= this.randomChildrenMaxCount) {
				break;			
			}
		}

		var i=1;
		var _this = this;
		dojo.lang.forEach(children, function(child) {
			var t = title+(_this.randomChildrenDepth==1 ? '' : '.')+i;
			i++;
		
			// first node is always folder for tests
			if (_this.randomChildrenCount<_this.randomChildrenMaxCount && (
				_this.randomChildrenDepth==1 && child === children[0] || _this.randomChildrenDepth<5 && Math.random()>0.3 )
			  ) {
				//dojo.debug("add child "+t);
				child.children = _this.makeRandomChildren(t);	
			}
		});
				

			//dojo.debug("out "+nodeOrTree);
			
		this.randomChildrenDepth--;
			
		return children;			
	},
	
	bindDemoMenu: function(controller) {
		var _t = this;
		
		dojo.event.topic.subscribe('treeContextMenuDestroy/engage',
			function (menuItem) { 
				var node = menuItem.getTreeNode();
				//if (confirm("Delete node with descendants: "+node.title.replace(/(<([^>]+)>)/ig," ") +" ?")) {
				_t.reportIfDefered(controller.destroyChild(node)); 
				
			}
		);

		dojo.event.topic.subscribe('treeContextMenuRefresh/engage',
			function (menuItem) {
                var node = menuItem.getTreeNode();
                _t.reportIfDefered(controller.refreshChildren(node));
			}
		);

		dojo.event.topic.subscribe('treeContextMenuCreate/engage',
			function (menuItem) {
				var node = menuItem.getTreeNode();
				var d = controller.createAndEdit(node, 0);
				_t.reportIfDefered(d);
            }
		);


		dojo.event.topic.subscribe('treeContextMenuUp/engage',
			function (menuItem) {
                var node = menuItem.getTreeNode();
                if (node.isFirstChild()) return;
                _t.reportIfDefered(controller.move(node, node.parent, node.getParentIndex()-1));
            }
		);


		dojo.event.topic.subscribe('treeContextMenuDown/engage',
			function (menuItem) {
                var node = menuItem.getTreeNode();
                if (node.isLastChild()) return;
                _t.reportIfDefered(controller.move(node, node.parent, node.getParentIndex()+1));
            }
		);

		dojo.event.topic.subscribe('treeContextMenuEdit/engage',
			function (menuItem) {
                var node = menuItem.getTreeNode();
                _t.reportIfDefered(controller.editLabelStart(node));
			}
		);


	}
	
	
	
}

__CPAN_FILE__ src/widget/SvgWidget.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.widget.DomWidget");
dojo.provide("dojo.widget.SvgWidget");
dojo.provide("dojo.widget.SVGWidget"); // back compat

dojo.require("dojo.dom");

// SVGWidget is a mixin ONLY
dojo.widget.declare(
	"dojo.widget.SvgWidget",
	dojo.widget.DomWidget,
{
	getContainerHeight: function(){
		// NOTE: container height must be returned as the INNER height
		dojo.unimplemented("dojo.widget.SvgWidget.getContainerHeight");
	},

	getContainerWidth: function(){
		// return this.parent.domNode.offsetWidth;
		dojo.unimplemented("dojo.widget.SvgWidget.getContainerWidth");
	},

	setNativeHeight: function(height){
		// var ch = this.getContainerHeight();
		dojo.unimplemented("dojo.widget.SVGWidget.setNativeHeight");
	},

	createNodesFromText: function(txt, wrap){
		return dojo.dom.createNodesFromText(txt, wrap);
	}
});

dojo.widget.SVGWidget = dojo.widget.SvgWidget;

try{
(function(){
	var tf = function(){
		// FIXME: fill this in!!!
		var rw = new function(){
			dojo.widget.SvgWidget.call(this);
			this.buildRendering = function(){ return; }
			this.destroyRendering = function(){ return; }
			this.postInitialize = function(){ return; }
			this.cleanUp = function(){ return; }
			this.widgetType = "SVGRootWidget";
			this.domNode = document.documentElement;
		}
		var wm = dojo.widget.manager;
		wm.root = rw;
		wm.add(rw);

		// extend the widgetManager with a getWidgetFromNode method
		wm.getWidgetFromNode = function(node){
			var filter = function(x){
				if(x.domNode == node){
					return true;
				}
			}
			var widgets = [];
			while((node)&&(widgets.length < 1)){
				widgets = this.getWidgetsByFilter(filter);
				node = node.parentNode;
			}
			if(widgets.length > 0){
				return widgets[0];
			}else{
				return null;
			}
		}

		wm.getWidgetFromEvent = function(domEvt){
			return this.getWidgetFromNode(domEvt.target);
		}

		wm.getWidgetFromPrimitive = wm.getWidgetFromNode;
	}
	// make sure we get called when the time is right
	dojo.event.connect(dojo.hostenv, "loaded", tf);
})();
}catch(e){ alert(e); }

__CPAN_FILE__ src/widget/SortableTable.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.SortableTable");

dojo.deprecated("SortableTable will be removed in favor of FilteringTable.", "0.5");

dojo.require("dojo.lang.common");
dojo.require("dojo.date.format");
dojo.require("dojo.html.*");
dojo.require("dojo.html.selection");
dojo.require("dojo.html.util");
dojo.require("dojo.html.style");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget(
	"dojo.widget.SortableTable",
	dojo.widget.HtmlWidget,
	function(){
		this.data=[];
		this.selected=[];		//	always an array to handle multiple selections.
		this.columns=[];
	},
	{
		//	custom properties
		enableMultipleSelect: false,
		maximumNumberOfSelections: 0,	//	0 for unlimited, is the default.
		enableAlternateRows: false,
		minRows: 0,	//	0 means ignore.
		defaultDateFormat: "%D",
		sortIndex: 0,		//	index of the column sorted on, first is the default.
		sortDirection: 0,	//	0==asc, 1==desc
		valueField: "Id",	//	if a JSON structure is parsed and there is a field of this name,
							//	a value attribute will be added to the row (tr value="{Id}")

		headClass: "",
		tbodyClass: "",
		headerClass: "",
		headerSortUpClass: "selected",
		headerSortDownClass: "selected",
		rowClass: "",
		rowAlternateClass: "alt",
		rowSelectedClass: "selected",
		columnSelected: "sorted-column",

		isContainer: false,
		templatePath:null,
		templateCssPath:null,

		getTypeFromString:function(/* string */ s){
			//	summary
			//	Find the constructor that matches param s by searching through the entire object tree.
			var parts=s.split("."),i=0,obj=dj_global; 
			do{obj=obj[parts[i++]];}while(i<parts.length&&obj); 
			return(obj!=dj_global)?obj:null;	//	function
		},
		compare:function(/* object */ o1, /* object */ o2){
			//	summary
			//	Compare two objects using a shallow property compare
			for(var p in o1){
				if(!(p in o2)) return false;	//	boolean
				if(o1[p].valueOf()!=o2[p].valueOf()) return false;	//	boolean
			}
			return true;	// boolean
		},
		isSelected:function(/* object */ o){
			//	summary
			//	checked to see if the passed object is in the current selection.
			for(var i=0;i<this.selected.length;i++){
				if(this.compare(this.selected[i],o)){
					return true; // boolean
				}
			}
			return false;	// boolean
		},
		removeFromSelected:function(/* object */ o){
			//	summary
			//	remove the passed object from the current selection.
			var idx=-1;
			for(var i=0;i<this.selected.length;i++){
				if(this.compare(this.selected[i],o)){
					idx=i;
					break;
				}
			}
			if(idx>=0){
				this.selected.splice(idx,1);
			}
		},
		getSelection:function(){
			//	summary
			//	return the array of currently selected objects (JSON format)
			return this.selected;	//	array
		},
		getValue:function(){
			//	summary
			//	return a comma-delimited list of selected valueFields.
			var a=[];
			for(var i=0;i<this.selected.length;i++){
				if (this.selected[i][this.valueField]){
					a.push(this.selected[i][this.valueField]);
				}
			}
			return a.join();	//	string
		},
		reset:function(){
			//	summary
			//	completely resets the internal representations.
			this.columns=[];
			this.data=[];
			this.resetSelections(this.domNode.getElementsByTagName("tbody")[0]);
		},
		resetSelections:function(/* HTMLTableBodyElement */ body){
			this.selected=[];
			var idx=0;
			var rows=body.getElementsByTagName("tr");
			for(var i=0; i<rows.length; i++){
				if(rows[i].parentNode==body){
					rows[i].removeAttribute("selected");
					if(this.enableAlternateRows&&idx%2==1){
						rows[i].className=this.rowAlternateClass;
					}else{
						rows[i].className="";
					}
					idx++;
				}
			}
		},

		getObjectFromRow:function(/* HTMLTableRowElement */ row){
			//	summary
			//	creates a JSON object based on the passed row
			var cells=row.getElementsByTagName("td");
			var o={};
			for(var i=0; i<this.columns.length;i++){
				if(this.columns[i].sortType=="__markup__"){
					//	FIXME: should we parse this instead?  Because if the user may not get back the markup they put in...
					o[this.columns[i].getField()]=cells[i].innerHTML;
				}else{
					var text=dojo.html.renderedTextContent(cells[i]);
					var val=text;
					if (this.columns[i].getType() != String){
						var val=new (this.columns[i].getType())(text);
					}
					o[this.columns[i].getField()]=val;
				}
			}
			if(dojo.html.hasAttribute(row,"value")){
				o[this.valueField]=dojo.html.getAttribute(row,"value");
			}
			return o;	//	object
		},
		setSelectionByRow:function(/* HTMLTableElementRow */ row){
			//	summary
			//	create the selection object based on the passed row, makes sure it's unique.
			//	note that you need to call render manually (because of multi-select operations)
			var o=this.getObjectFromRow(row);
			var b=false;
			for(var i=0;i<this.selected.length;i++){
				if(this.compare(this.selected[i], o)){
					b=true;
					break;
				}
			}
			if(!b){
				this.selected.push(o);
			}
		},

		parseColumns:function(/* HTMLTableHeadElement */ node){
			//	summary
			//	parses the passed element to create column objects
			this.reset();
			var row=node.getElementsByTagName("tr")[0];
			var cells=row.getElementsByTagName("td");
			if (cells.length==0) cells=row.getElementsByTagName("th");
			for(var i=0; i<cells.length; i++){
				var o={
					field:null,
					format:null,
					noSort:false,
					sortType:"String",
					dataType:String,
					sortFunction:null,
					label:null,
					align:"left",
					valign:"middle",
					getField:function(){ return this.field||this.label; },
					getType:function(){ return this.dataType; }
				};
				//	presentation attributes
				if(dojo.html.hasAttribute(cells[i], "align")){
					o.align=dojo.html.getAttribute(cells[i],"align");
				}
				if(dojo.html.hasAttribute(cells[i], "valign")){
					o.valign=dojo.html.getAttribute(cells[i],"valign");
				}

				//	sorting features.
				if(dojo.html.hasAttribute(cells[i], "nosort")){
					o.noSort=dojo.html.getAttribute(cells[i],"nosort")=="true";
				}
				if(dojo.html.hasAttribute(cells[i], "sortusing")){
					var trans=dojo.html.getAttribute(cells[i],"sortusing");
					var f=this.getTypeFromString(trans);
					if (f!=null && f!=window && typeof(f)=="function") 
						o.sortFunction=f;
				}

				if(dojo.html.hasAttribute(cells[i], "field")){
					o.field=dojo.html.getAttribute(cells[i],"field");
				}
				if(dojo.html.hasAttribute(cells[i], "format")){
					o.format=dojo.html.getAttribute(cells[i],"format");
				}
				if(dojo.html.hasAttribute(cells[i], "dataType")){
					var sortType=dojo.html.getAttribute(cells[i],"dataType");
					if(sortType.toLowerCase()=="html"||sortType.toLowerCase()=="markup"){
						o.sortType="__markup__";	//	always convert to "__markup__"
						o.noSort=true;
					}else{
						var type=this.getTypeFromString(sortType);
						if(type){
							o.sortType=sortType;
							o.dataType=type;
						}
					}
				}
				o.label=dojo.html.renderedTextContent(cells[i]);
				this.columns.push(o);

				//	check to see if there's a default sort, and set the properties necessary
				if(dojo.html.hasAttribute(cells[i], "sort")){
					this.sortIndex=i;
					var dir=dojo.html.getAttribute(cells[i], "sort");
					if(!isNaN(parseInt(dir))){
						dir=parseInt(dir);
						this.sortDirection=(dir!=0)?1:0;
					}else{
						this.sortDirection=(dir.toLowerCase()=="desc")?1:0;
					}
				}
			}
		},

		parseData:function(/* array */ data){
			//	summary
			//	Parse the passed JSON data structure, and cast based on columns.
			this.data=[];
			this.selected=[];
			for(var i=0; i<data.length; i++){
				var o={};	//	new data object.
				for(var j=0; j<this.columns.length; j++){
					var field=this.columns[j].getField();
					if(this.columns[j].sortType=="__markup__"){
						o[field]=String(data[i][field]);
					}else{
						var type=this.columns[j].getType();
						var val=data[i][field];
						var t=this.columns[j].sortType.toLowerCase();
						if(type == String) {
							o[field]=val;
						} else {
							if(val!=null){
								o[field]=new type(val);
							}else{
								o[field]=new type();	//	let it use the default.
							}
						}
					}
				}
				//	check for the valueField if not already parsed.
				if(data[i][this.valueField]&&!o[this.valueField]){
					o[this.valueField]=data[i][this.valueField];
				}
				this.data.push(o);
			}
		}, 

		parseDataFromTable:function(/* HTMLTableBodyElement */ tbody){
			//	summary
			//	parses the data in the tbody of a table to create a set of objects.
			//	Will add objects to this.selected if an attribute 'selected="true"' is present on the row.
			this.data=[];
			this.selected=[];
			var rows=tbody.getElementsByTagName("tr");
			for(var i=0; i<rows.length; i++){
				if(dojo.html.getAttribute(rows[i],"ignoreIfParsed")=="true"){
					continue;
				}
				var o={};	//	new data object.
				var cells=rows[i].getElementsByTagName("td");
				for(var j=0; j<this.columns.length; j++){
					var field=this.columns[j].getField();
					if(this.columns[j].sortType=="__markup__"){
						//	FIXME: parse this?
						o[field]=cells[j].innerHTML;
					}else{
						var type=this.columns[j].getType();
						var val=dojo.html.renderedTextContent(cells[j]); //	should be the same index as the column.
						if(type == String){
							o[field]=val;
						} else {
							if (val!=null){
								o[field]=new type(val);
							} else {
								o[field]=new type();	//	let it use the default.
							}
						}
					}
				}
				if(dojo.html.hasAttribute(rows[i],"value")&&!o[this.valueField]){
					o[this.valueField]=dojo.html.getAttribute(rows[i],"value");
				}
				//	FIXME: add code to preserve row attributes in __metadata__ field?
				this.data.push(o);
				
				//	add it to the selections if selected="true" is present.
				if(dojo.html.getAttribute(rows[i],"selected")=="true"){
					this.selected.push(o);
				}
			}
		},
		
		showSelections:function(){
			var body=this.domNode.getElementsByTagName("tbody")[0];
			var rows=body.getElementsByTagName("tr");
			var idx=0;
			for(var i=0; i<rows.length; i++){
				if(rows[i].parentNode==body){
					if(dojo.html.getAttribute(rows[i],"selected")=="true"){
						rows[i].className=this.rowSelectedClass;
					} else {
						if(this.enableAlternateRows&&idx%2==1){
							rows[i].className=this.rowAlternateClass;
						}else{
							rows[i].className="";
						}
					}
					idx++;
				}
			}
		},
		render:function(bDontPreserve){
			//	summary
			//	renders the table to the browser
			var data=[];
			var body=this.domNode.getElementsByTagName("tbody")[0];

			if(!bDontPreserve){
				//	rebuild data and selection
				this.parseDataFromTable(body);
			}

			//	clone this.data for sorting purposes.
			for(var i=0; i<this.data.length; i++){
				data.push(this.data[i]);
			}
			
			var col=this.columns[this.sortIndex];
			if(!col.noSort){
				var field=col.getField();
				if(col.sortFunction){
					var sort=col.sortFunction;
				}else{
					var sort=function(a,b){
						if (a[field]>b[field]) return 1;
						if (a[field]<b[field]) return -1;
						return 0;
					}
				}
				data.sort(sort);
				if(this.sortDirection!=0) data.reverse();
			}

			//	build the table and pop it in.
			while(body.childNodes.length>0) body.removeChild(body.childNodes[0]);
			for(var i=0; i<data.length;i++){
				var row=document.createElement("tr");
				dojo.html.disableSelection(row);
				if (data[i][this.valueField]){
					row.setAttribute("value",data[i][this.valueField]);
				}
				if(this.isSelected(data[i])){
					row.className=this.rowSelectedClass;
					row.setAttribute("selected","true");
				} else {
					if(this.enableAlternateRows&&i%2==1){
						row.className=this.rowAlternateClass;
					}
				}
				for(var j=0;j<this.columns.length;j++){
					var cell=document.createElement("td");
					cell.setAttribute("align", this.columns[j].align);
					cell.setAttribute("valign", this.columns[j].valign);
					dojo.html.disableSelection(cell);
					if(this.sortIndex==j){
						cell.className=this.columnSelected;
					}
					if(this.columns[j].sortType=="__markup__"){
						cell.innerHTML=data[i][this.columns[j].getField()];
						for(var k=0; k<cell.childNodes.length; k++){
							var node=cell.childNodes[k];
							if(node&&node.nodeType==dojo.html.ELEMENT_NODE){
								dojo.html.disableSelection(node);
							}
						}
					}else{
						if(this.columns[j].getType()==Date){
							var format=this.defaultDateFormat;
							if(this.columns[j].format) format=this.columns[j].format;
							cell.appendChild(document.createTextNode(dojo.date.strftime(data[i][this.columns[j].getField()], format)));
						}else{
							cell.appendChild(document.createTextNode(data[i][this.columns[j].getField()]));
						}
					}
					row.appendChild(cell);
				}
				body.appendChild(row);
				dojo.event.connect(row, "onclick", this, "onUISelect");
			}
			
			//	if minRows exist.
			var minRows=parseInt(this.minRows);
			if (!isNaN(minRows) && minRows>0 && data.length<minRows){
				var mod=0;
				if(data.length%2==0) mod=1;
				var nRows=minRows-data.length;
				for(var i=0; i<nRows; i++){
					var row=document.createElement("tr");
					row.setAttribute("ignoreIfParsed","true");
					if(this.enableAlternateRows&&i%2==mod){
						row.className=this.rowAlternateClass;
					}
					for(var j=0;j<this.columns.length;j++){
						var cell=document.createElement("td");
						cell.appendChild(document.createTextNode("\u00A0"));
						row.appendChild(cell);
					}
					body.appendChild(row);
				}
			}
		},

		//	the following the user can override.
		onSelect:function(/* DomEvent */ e){ 
			//	summary
			//	empty function for the user to attach code to, fired by onUISelect
		},
		onUISelect:function(/* DomEvent */ e){
			//	summary
			//	fired when a user selects a row
			var row=dojo.html.getParentByType(e.target,"tr");
			var body=dojo.html.getParentByType(row,"tbody");
			if(this.enableMultipleSelect){
				if(e.metaKey||e.ctrlKey){
					if(this.isSelected(this.getObjectFromRow(row))){
						this.removeFromSelected(this.getObjectFromRow(row));
						row.removeAttribute("selected");
					}else{
						//	push onto the selection stack.
						this.setSelectionByRow(row);
						row.setAttribute("selected","true");
					}
				}else if(e.shiftKey){
					//	the tricky one.  We need to figure out the *last* selected row above, 
					//	and select all the rows in between.
					var startRow;
					var rows=body.getElementsByTagName("tr");
					//	if there's a selection above, we go with that first. 
					for(var i=0;i<rows.length;i++){
						if(rows[i].parentNode==body){
							if(rows[i]==row) break;
							if(dojo.html.getAttribute(rows[i],"selected")=="true"){
								startRow=rows[i];
							}
						}
					}
					//	if there isn't a selection above, we continue with a selection below.
					if(!startRow){
						startRow=row;
						for(;i<rows.length;i++){
							if(dojo.html.getAttribute(rows[i],"selected")=="true"){
								row=rows[i];
								break;
							}
						}
					}
					this.resetSelections(body);
					if(startRow==row){
						//	this is the only selection
						row.setAttribute("selected","true");
						this.setSelectionByRow(row);
					}else{
						var doSelect=false;
						for(var i=0; i<rows.length; i++){
							if(rows[i].parentNode==body){
								rows[i].removeAttribute("selected");
								if(rows[i]==startRow){
									doSelect=true;
								}
								if(doSelect){
									this.setSelectionByRow(rows[i]);
									rows[i].setAttribute("selected","true");
								}
								if(rows[i]==row){
									doSelect=false;
								}
							}
						}
					}
				}else{
					//	reset the selection
					this.resetSelections(body);
					row.setAttribute("selected","true");
					this.setSelectionByRow(row);
				}
			}else{
				//	reset the data selection and go.
				this.resetSelections(body);
				row.setAttribute("selected","true");
				this.setSelectionByRow(row);
			}
			this.showSelections();
			this.onSelect(e);
			e.stopPropagation();
			e.preventDefault();
		},
		onHeaderClick:function(/* DomEvent */ e){
			//	summary
			//	Main handler function for each header column click.
			var oldIndex=this.sortIndex;
			var oldDirection=this.sortDirection;
			var source=e.target;
			var row=dojo.html.getParentByType(source,"tr");
			var cellTag="td";
			if(row.getElementsByTagName(cellTag).length==0) cellTag="th";

			var headers=row.getElementsByTagName(cellTag);
			var header=dojo.html.getParentByType(source,cellTag);
			
			for(var i=0; i<headers.length; i++){
				if(headers[i]==header){
					if(i!=oldIndex){
						//	new col.
						this.sortIndex=i;
						this.sortDirection=0;
						headers[i].className=this.headerSortDownClass
					}else{
						this.sortDirection=(oldDirection==0)?1:0;
						if(this.sortDirection==0){
							headers[i].className=this.headerSortDownClass;
						}else{
							headers[i].className=this.headerSortUpClass;
						}
					}
				}else{
					//	reset the header class.
					headers[i].className=this.headerClass;
				}
			}
			this.render();
		},

		postCreate:function(){ 
			// 	summary
			//	overridden from HtmlWidget, initializes and renders the widget.
			var thead=this.domNode.getElementsByTagName("thead")[0];
			if(this.headClass.length>0){
				thead.className=this.headClass;
			}

			//	disable selections
			dojo.html.disableSelection(this.domNode);

			//	parse the columns.
			this.parseColumns(thead);

			//	attach header handlers.
			var header="td";
			if(thead.getElementsByTagName(header).length==0) header="th";
			var headers=thead.getElementsByTagName(header);
			for(var i=0; i<headers.length; i++){
				if(!this.columns[i].noSort){
					dojo.event.connect(headers[i], "onclick", this, "onHeaderClick");
				}
				if(this.sortIndex==i){
					if(this.sortDirection==0){
						headers[i].className=this.headerSortDownClass;
					}else{
						headers[i].className=this.headerSortUpClass;
					}
				}
			}

			//	parse the tbody element and re-render it.
			var tbody=this.domNode.getElementsByTagName("tbody")[0];
			if (this.tbodyClass.length>0) {
				tbody.className=this.tbodyClass;
			}

			this.parseDataFromTable(tbody);
			this.render(true);
		}
	}
);

__CPAN_FILE__ src/widget/ValidationTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ValidationTextbox");

dojo.require("dojo.widget.Textbox");
dojo.require("dojo.i18n.common");

/*
  ****** ValidationTextbox ******

  A subclass of Textbox.
  Over-ride isValid in subclasses to perform specific kinds of validation.
  Has several new properties that can be specified as attributes in the markup.

  @attr type          		Basic input tag type declaration.
  @attr size          		Basic input tag size declaration.
  @attr type          		Basic input tag maxlength declaration.	
  @attr required          	Can be true or false, default is false.
  @attr validColor        	The color textbox is highlighted for valid input. Default is #cfc.
  @attr invalidColor      	The color textbox is highlighted for invalid input. Default is #fcc.
  @attr invalidClass		Class used to format displayed text in page if necessary to override default class
  @attr invalidMessage    	The message to display if value is invalid.
  @attr missingMessage    	The message to display if value is missing.
  @attr missingClass		Override default class used for missing input data
  @attr listenOnKeyPress	Updates messages on each key press.  Default is true.
  @attr promptMessage		Will not issue invalid message if field is populated with default user-prompt text
*/
dojo.widget.defineWidget(
	"dojo.widget.ValidationTextbox",
	dojo.widget.Textbox,
	function() {
		// this property isn't a primitive and needs to be created on a per-item basis.
		this.flags = {};
	},
	{
		// default values for new subclass properties
		required: false,
		rangeClass: "range",
		invalidClass: "invalid",
		missingClass: "missing",
		classPrefix: "dojoValidate",
		size: "",
		maxlength: "",
		promptMessage: "",
		invalidMessage: "",
		missingMessage: "",
		rangeMessage: "",
		listenOnKeyPress: true,
		htmlfloat: "none",
		lastCheckedValue: null,
	
		templatePath: dojo.uri.dojoUri("src/widget/templates/ValidationTextbox.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/Validate.css"),
		
		// new DOM nodes
		invalidSpan: null,
		missingSpan: null,
		rangeSpan: null,
	
		getValue: function() {
			return this.textbox.value;
		},
	
		setValue: function(value) {
			this.textbox.value = value;
			this.update();
		},
	
		// Need to over-ride with your own validation code in subclasses
		isValid: function() { return true; },
	
		// Need to over-ride with your own validation code in subclasses
		isInRange: function() { return true; },
	
		// Returns true if value is all whitespace
		isEmpty: function() { 
			return ( /^\s*$/.test(this.textbox.value) );
		},
	
		// Returns true if value is required and it is all whitespace.
		isMissing: function() { 
			return ( this.required && this.isEmpty() );
		},
	
		// Called oninit, onblur, and onkeypress.
		// Show missing or invalid messages if appropriate, and highlight textbox field.
		update: function() {
			this.lastCheckedValue = this.textbox.value;
			this.missingSpan.style.display = "none";
			this.invalidSpan.style.display = "none";
			this.rangeSpan.style.display = "none";
	
			var empty = this.isEmpty();
			var valid = true;
			if(this.promptMessage != this.textbox.value){ 
				valid = this.isValid(); 
			}
			var missing = this.isMissing();
	
			// Display at most one error message
			if(missing){
				this.missingSpan.style.display = "";
			}else if( !empty && !valid ){
				this.invalidSpan.style.display = "";
			}else if( !empty && !this.isInRange() ){
				this.rangeSpan.style.display = "";
			}
			this.highlight();
		},
		
		updateClass: function(className){
		//summary: used to ensure that only 1 validation class is set at a time
			var pre = this.classPrefix;
			dojo.html.removeClass(this.textbox,pre+"Empty");
			dojo.html.removeClass(this.textbox,pre+"Valid");
			dojo.html.removeClass(this.textbox,pre+"Invalid");
			dojo.html.addClass(this.textbox,pre+className);
		},
		
		// Called oninit, and onblur.
		highlight: function() {
			// highlight textbox background 
			if (this.isEmpty()) {
				this.updateClass("Empty");
			}else if (this.isValid() && this.isInRange() ){
				this.updateClass("Valid");
			}else if(this.textbox.value != this.promptMessage){ 
				this.updateClass("Invalid");
			}else{
				this.updateClass("Empty");
			}
		},
	
		onfocus: function(evt) {
			if ( !this.listenOnKeyPress) {
				this.updateClass("Empty");
//			    this.textbox.style.backgroundColor = "";
			}
		},
	
		onblur: function(evt) { 
			this.filter();
			this.update(); 
		},
	
		onkeyup: function(evt){ 
			if(this.listenOnKeyPress){ 
				//this.filter();  trim is problem if you have to type two words
				this.update(); 
			}else if (this.textbox.value != this.lastCheckedValue){
				this.updateClass("Empty");
//			    this.textbox.style.backgroundColor = "";
			}
		},

		postMixInProperties: function(localProperties, frag) {
			dojo.widget.ValidationTextbox.superclass.postMixInProperties.apply(this, arguments);
			this.messages = dojo.i18n.getLocalization("dojo.widget", "validate", this.lang);
			dojo.lang.forEach(["invalidMessage", "missingMessage", "rangeMessage"], function(prop) {
				if(this[prop]){ this.messages[prop] = this[prop]; }
			}, this);
		},
	
		// FIXME: why are there to fillInTemplate methods defined here?
		fillInTemplate: function() {
			dojo.widget.ValidationTextbox.superclass.fillInTemplate.apply(this, arguments);

			// Attach isMissing and isValid methods to the textbox.
			// We may use them later in connection with a submit button widget.
			// TODO: this is unorthodox; it seems better to do it another way -- Bill
			this.textbox.isValid = function() { this.isValid.call(this); };
			this.textbox.isMissing = function() { this.isMissing.call(this); };
			this.textbox.isInRange = function() { this.isInRange.call(this); };
			dojo.html.setClass(this.invalidSpan,this.invalidClass);
			this.update(); 
			
			// apply any filters to initial value
			this.filter();

			// set table to be inlined (technique varies by browser)
			if(dojo.render.html.ie){ dojo.html.addClass(this.domNode, "ie"); }
			if(dojo.render.html.moz){ dojo.html.addClass(this.domNode, "moz"); }
			if(dojo.render.html.opera){ dojo.html.addClass(this.domNode, "opera"); }
			if(dojo.render.html.safari){ dojo.html.addClass(this.domNode, "safari"); }
		}
	}
);

__CPAN_FILE__ src/widget/AccordionContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.AccordionContainer");

dojo.require("dojo.widget.*");
dojo.require("dojo.html.*");
dojo.require("dojo.lfx.html");
dojo.require("dojo.html.selection");
dojo.require("dojo.widget.html.layout");
dojo.require("dojo.widget.PageContainer");


/**
 *summary
 *	Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
 *	and switching between panes is visualized by sliding the other panes up/down.
 *
 * description
 *	Front view (3 panes, pane #2 open)
 *	------------------------
 *	|:::Pane#1 title:::    |
 * 	|:::Pane#2 title:::    |
 *	|                      |
 *	|    pane#2 contents   |
 *	|                      |
 *	|:::Pane#3 title:::    |
 *	------------------------
 *
 *	Side view (showing implementation):
 *
 *         viewport    pane#3     pane#2     pane#1
 *            =                                
 *            |                                =
 *            |                      =         |
 *	front     |                      |         |
 *            |                      |         =
 *            |                      =
 *            |          =
 *            =          |
 *                       |
 *                       =
 *
 *	Panes are stacked by z-index like a stack of cards, so they can be slid correctly.
 *	The panes on the bottom extend past the bottom of the viewport (but are hidden).
 *
 * usage
 *	<div dojoType="AccordionContainer">
 *		<div dojoType="ContentPane" label="pane 1">...</div>
 *		...
 *	</div>
 *
 * TODO:
 *	* this widget should extend PageContainer
 *	* call child.onShow(), child.onHide() so you can attach to those methods if you want
 */
 dojo.widget.defineWidget(
	"dojo.widget.AccordionContainer",
	dojo.widget.HtmlWidget,
	{
		isContainer: true,
		
		// String
		//	CSS class name for dom node w/the title
		labelNodeClass: "label",
		
		// String
		//	CSS class name for dom node holding the content
		containerNodeClass: "accBody",

		// Integer
		//	Amount of time (in ms) it takes to slide panes
		duration: 250,

		fillInTemplate: function(){
			with(this.domNode.style){
				// position must be either relative or absolute
				if(position!="absolute"){
					position="relative";
				}
				overflow="hidden";
			}
		},

		addChild: function(/*Widget*/ widget){
			var child = this._addChild(widget);
			this._setSizes();
			return child;	// Widget
		},
		
		_addChild: function(/*Widget*/ widget){
			// summary
			//	Internal call to add child, used during postCreate() and by the real addChild() call
			if(widget.open){
				dojo.deprecated("open parameter deprecated, use 'selected=true' instead will be removed in ", "0.5");
				dojo.debug(widget.widgetId + ": open == " + widget.open);
				widget.selected=true;
			}
			if (widget.widgetType != "AccordionPane") {
				var wrapper=dojo.widget.createWidget("AccordionPane",{label: widget.label, selected: widget.selected, labelNodeClass: this.labelNodeClass, containerNodeClass: this.containerNodeClass, allowCollapse: this.allowCollapse });
				wrapper.addChild(widget);
				this.addWidgetAsDirectChild(wrapper);
				this.registerChild(wrapper, this.children.length);
				return wrapper;	// Widget
			} else {
				dojo.html.addClass(widget.containerNode, this.containerNodeClass);
				dojo.html.addClass(widget.labelNode, this.labelNodeClass);
				this.addWidgetAsDirectChild(widget);
				this.registerChild(widget, this.children.length);	
				return widget;	// Widget
			}
		},
	
		postCreate: function() {
			var tmpChildren = this.children;
			this.children=[];
			dojo.html.removeChildren(this.domNode);
			dojo.lang.forEach(tmpChildren, dojo.lang.hitch(this,"_addChild"));
			this._setSizes();
		},
	
		removeChild: function(/*Widget*/ widget) {
			dojo.widget.AccordionContainer.superclass.removeChild.call(this, widget);
			this._setSizes();
		},
		
		onResized: function(){
			this._setSizes();
		},

		_setSizes: function() {
			// summary
			//	Set panes' size/position based on my size, and the current open node.

			// get cumulative height of all the title bars, and figure out which pane is open
			var totalCollapsedHeight = 0;
			var openIdx = 0;
			dojo.lang.forEach(this.children, function(child, idx){
				totalCollapsedHeight += child.getLabelHeight();
				if(child.selected){ openIdx=idx; }
			});

			// size and position each pane
			var mySize=dojo.html.getContentBox(this.domNode);
			var y = 0;
			dojo.lang.forEach(this.children, function(child, idx){
				var childCollapsedHeight = child.getLabelHeight();
				child.resizeTo(mySize.width, mySize.height-totalCollapsedHeight+childCollapsedHeight);
				child.domNode.style.zIndex=idx+1;
				child.domNode.style.position="absolute";
				child.domNode.style.top = y+"px";
				y += (idx==openIdx) ? dojo.html.getBorderBox(child.domNode).height : childCollapsedHeight;
			});
		},

		selectChild: function(/*Widget*/ page){
			// summary
			//	close the current page and select a new one
			dojo.lang.forEach(this.children, function(child){child.setSelected(child==page);});

			// slide each pane that needs to be moved
			var y = 0;
			var anims = [];
			dojo.lang.forEach(this.children, function(child, idx){
				if(child.domNode.style.top != (y+"px")){
					anims.push(dojo.lfx.html.slideTo(child.domNode, {top: y, left: 0}, this.duration));
				}
				y += child.selected ? dojo.html.getBorderBox(child.domNode).height : child.getLabelHeight();
			});
			dojo.lfx.combine(anims).play();
		}
	}
);

/**
 * summary
 *	AccordionPane is a box with a title that contains another widget (often a ContentPane).
 *	It's a widget used internally by AccordionContainer.
 */
dojo.widget.defineWidget(
	"dojo.widget.AccordionPane",
	dojo.widget.HtmlWidget,
{
	// parameters

	// String
	//	label to print on top of AccordionPane
	label: "",

	// String
	//	CSS class name for the AccordionPane's dom node
	"class": "dojoAccordionPane",

	// String
	//	CSS class name for the AccordionPane's label node
	labelNodeClass: "label",

	// String
	//	CSS class name for the AccordionPane's container node
	containerNodeClass: "accBody",
	
	// Boolean
	//	if true, this is the open pane
	selected: false,

	templatePath: dojo.uri.dojoUri("src/widget/templates/AccordionPane.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/AccordionPane.css"),

	isContainer: true,

    fillInTemplate: function() {
    	dojo.html.addClass(this.domNode, this["class"]);
		dojo.widget.AccordionPane.superclass.fillInTemplate.call(this);
		dojo.html.disableSelection(this.labelNode);
		this.setSelected(this.selected);
	},

	setLabel: function(/*String*/ label) {
		// summary: set the  title of the node
		this.labelNode.innerHTML=label;
	},
	
	resizeTo: function(width, height){
		dojo.html.setMarginBox(this.domNode, {width: width, height: height});
		var children = [
			{domNode: this.labelNode, layoutAlign: "top"},
			{domNode: this.containerNode, layoutAlign: "client"}
		];
		dojo.widget.html.layout(this.domNode, children);
		var childSize = dojo.html.getContentBox(this.containerNode);
		this.children[0].resizeTo(childSize.width, childSize.height);
	},

	getLabelHeight: function() {
		// summary: returns the height of the title dom node
		return dojo.html.getMarginBox(this.labelNode).height;	// Integer
	},

	onLabelClick: function() {
		// summary: callback when someone clicks my label
		this.parent.selectChild(this);
	},
	
	setSelected: function(/*Boolean*/ isSelected){
		this.selected=isSelected;
		(isSelected ? dojo.html.addClass : dojo.html.removeClass)(this.domNode, this["class"]+"-selected");

		// make sure child is showing (lazy load), and also that onShow()/onHide() is called
		var child = this.children[0];
		if(child){
			if(isSelected){
				if(!child.isShowing()){
					child.show();
				}else{
					child.onShow();
				}
			}else{
				child.onHide();
			}
		}
	}
});

// These arguments can be specified for the children of an AccordionContainer
// Since any widget can be specified as a child, mix them
// into the base widget class.  (This is a hack, but it's effective.)
dojo.lang.extend(dojo.widget.Widget, {
	// String
	//	is this the selected child?
	//	DEPRECATED: will be removed in 0.5.  Used "selected" attribute instead.
	open: false
});

__CPAN_FILE__ src/widget/TreeNode.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TreeNode");

dojo.require("dojo.html.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");

dojo.widget.defineWidget("dojo.widget.TreeNode", dojo.widget.HtmlWidget, function() {
	this.actionsDisabled = [];
},
{
	widgetType: "TreeNode",

	loadStates: {
		UNCHECKED: "UNCHECKED",
    	LOADING: "LOADING",
    	LOADED: "LOADED"
	},


	actions: {
		MOVE: "MOVE",
    	REMOVE: "REMOVE",
    	EDIT: "EDIT",
    	ADDCHILD: "ADDCHILD"
	},

	isContainer: true,

	lockLevel: 0, // lock ++ unlock --, so nested locking works fine


	templateString: ('<div class="dojoTreeNode"> '
		+ '<span treeNode="${this.widgetId}" class="dojoTreeNodeLabel" dojoAttachPoint="labelNode"> '
		+ '		<span dojoAttachPoint="titleNode" dojoAttachEvent="onClick: onTitleClick" class="dojoTreeNodeLabelTitle">${this.title}</span> '
		+ '</span> '
		+ '<span class="dojoTreeNodeAfterLabel" dojoAttachPoint="afterLabelNode">${this.afterLabel}</span> '
		+ '<div dojoAttachPoint="containerNode" style="display:none"></div> '
		+ '</div>').replace(/(>|<)\s+/g, '$1'), // strip whitespaces between nodes


	childIconSrc: "",
	childIconFolderSrc: dojo.uri.dojoUri("src/widget/templates/images/Tree/closed.gif"), // for under root parent item child icon,
	childIconDocumentSrc: dojo.uri.dojoUri("src/widget/templates/images/Tree/document.gif"), // for under root parent item child icon,

	childIcon: null,
	isTreeNode: true,

	objectId: "", // the widget represents an object

	afterLabel: "",
	afterLabelNode: null, // node to the left of labelNode

	// an icon left from childIcon: imgs[-2].
	// if +/- for folders, blank for leaves
	expandIcon: null,

	title: "",
	object: "", // node may have object attached, settable from HTML
	isFolder: false,

	labelNode: null, // the item label
	titleNode: null, // the item title
	imgs: null, // an array of icons imgs

	expandLevel: "", // expand to level

	tree: null,

	depth: 0,

	isExpanded: false,

	state: null,  // after creation will change to loadStates: "loaded/loading/unchecked"
	domNodeInitialized: false,  // domnode is initialized with icons etc


	isFirstChild: function() {
		return this.getParentIndex() == 0 ? true: false;
	},

	isLastChild: function() {
		return this.getParentIndex() == this.parent.children.length-1 ? true : false;
	},

	lock: function(){ return this.tree.lock.apply(this, arguments) },
	unlock: function(){ return this.tree.unlock.apply(this, arguments) },
	isLocked: function(){ return this.tree.isLocked.apply(this, arguments) },
	cleanLock: function(){ return this.tree.cleanLock.apply(this, arguments) },

	actionIsDisabled: function(action) {
		var _this = this;

		var disabled = false;

		if (this.tree.strictFolders && action == this.actions.ADDCHILD && !this.isFolder) {
			disabled = true;
		}

		if (dojo.lang.inArray(_this.actionsDisabled, action)) {
			disabled = true;
		}

		if (this.isLocked()) {
			disabled = true;
		}

		return disabled;
	},

	getInfo: function() {
		// No title here (title may be widget)
		var info = {
			widgetId: this.widgetId,
			objectId: this.objectId,
			index: this.getParentIndex(),
			isFolder: this.isFolder
		}

		return info;
	},

	initialize: function(args, frag){

		//dojo.debug(this.title)

		this.state = this.loadStates.UNCHECKED;

		for(var i=0; i<this.actionsDisabled.length; i++) {
			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
		}

		this.expandLevel = parseInt(this.expandLevel);

	},


	/**
	 * Change visible node depth by appending/prepending with blankImgs
	 * @param depthDiff Integer positive => move right, negative => move left
	*/
	adjustDepth: function(depthDiff) {

		for(var i=0; i<this.children.length; i++) {
			this.children[i].adjustDepth(depthDiff);
		}

		this.depth += depthDiff;

		if (depthDiff>0) {
			for(var i=0; i<depthDiff; i++) {
				var img = this.tree.makeBlankImg();
				this.imgs.unshift(img);
				//dojo.debugShallow(this.domNode);
				dojo.html.insertBefore(this.imgs[0], this.domNode.firstChild);

			}
		}
		if (depthDiff<0) {
			for(var i=0; i<-depthDiff;i++) {
				this.imgs.shift();
				dojo.html.removeNode(this.domNode.firstChild);
			}
		}

	},


	markLoading: function() {
		this._markLoadingSavedIcon = this.expandIcon.src;
		this.expandIcon.src = this.tree.expandIconSrcLoading;
	},

	// if icon is "Loading" then
	unMarkLoading: function() {
		if (!this._markLoadingSavedIcon) return;

		var im = new Image();
		im.src = this.tree.expandIconSrcLoading;

		//dojo.debug("Unmark "+this.expandIcon.src+" : "+im.src);
		if (this.expandIcon.src == im.src) {
			this.expandIcon.src = this._markLoadingSavedIcon;
		}
		this._markLoadingSavedIcon = null;
	},


	setFolder: function() {
		dojo.event.connect(this.expandIcon, 'onclick', this, 'onTreeClick');
		this.expandIcon.src = this.isExpanded ? this.tree.expandIconSrcMinus : this.tree.expandIconSrcPlus;
		this.isFolder = true;
	},


	createDOMNode: function(tree, depth){

		this.tree = tree;
		this.depth = depth;


		//
		// add the tree icons
		//

		this.imgs = [];

		for(var i=0; i<this.depth+1; i++){

			var img = this.tree.makeBlankImg();

			this.domNode.insertBefore(img, this.labelNode);

			this.imgs.push(img);
		}


		this.expandIcon = this.imgs[this.imgs.length-1];


		this.childIcon = this.tree.makeBlankImg();

		// add to images before the title
		this.imgs.push(this.childIcon);

		dojo.html.insertBefore(this.childIcon, this.titleNode);

		// node with children(from source html) becomes folder on build stage.
		if (this.children.length || this.isFolder) {
			this.setFolder();
		}
		else {
			// leaves are always loaded
			//dojo.debug("Set "+this+" state to loaded");
			this.state = this.loadStates.LOADED;
		}

		dojo.event.connect(this.childIcon, 'onclick', this, 'onIconClick');


		//
		// create the child rows
		//


		for(var i=0; i<this.children.length; i++){
			this.children[i].parent = this;

			var node = this.children[i].createDOMNode(this.tree, this.depth+1);

			this.containerNode.appendChild(node);
		}


		if (this.children.length) {
			this.state = this.loadStates.LOADED;
		}

		this.updateIcons();

		this.domNodeInitialized = true;

		dojo.event.topic.publish(this.tree.eventNames.createDOMNode, { source: this } );

		return this.domNode;
	},

	onTreeClick: function(e){
		dojo.event.topic.publish(this.tree.eventNames.treeClick, { source: this, event: e });
	},

	onIconClick: function(e){
		dojo.event.topic.publish(this.tree.eventNames.iconClick, { source: this, event: e });
	},

	onTitleClick: function(e){
		dojo.event.topic.publish(this.tree.eventNames.titleClick, { source: this, event: e });
	},

	markSelected: function() {
		dojo.html.addClass(this.titleNode, 'dojoTreeNodeLabelSelected');
	},


	unMarkSelected: function() {
		//dojo.debug('unmark')
		dojo.html.removeClass(this.titleNode, 'dojoTreeNodeLabelSelected');
	},

	updateExpandIcon: function() {
		if (this.isFolder){
			this.expandIcon.src = this.isExpanded ? this.tree.expandIconSrcMinus : this.tree.expandIconSrcPlus;
		} else {
			this.expandIcon.src = this.tree.blankIconSrc;
		}
	},

	/* set the grid under the expand icon */
	updateExpandGrid: function() {

		if (this.tree.showGrid){
			if (this.depth){
				this.setGridImage(-2, this.isLastChild() ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
			}else{
				if (this.isFirstChild()){
					this.setGridImage(-2, this.isLastChild() ? this.tree.gridIconSrcX : this.tree.gridIconSrcY);
				}else{
					this.setGridImage(-2, this.isLastChild() ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
				}
			}
		}else{
			this.setGridImage(-2, this.tree.blankIconSrc);
		}

	},

	/* set the grid under the child icon */
	updateChildGrid: function() {

		if ((this.depth || this.tree.showRootGrid) && this.tree.showGrid){
			this.setGridImage(-1, (this.children.length && this.isExpanded) ? this.tree.gridIconSrcP : this.tree.gridIconSrcC);
		}else{
			if (this.tree.showGrid && !this.tree.showRootGrid){
				this.setGridImage(-1, (this.children.length && this.isExpanded) ? this.tree.gridIconSrcZ : this.tree.blankIconSrc);
			}else{
				this.setGridImage(-1, this.tree.blankIconSrc);
			}
		}


	},

	updateParentGrid: function() {
		var parent = this.parent;

		//dojo.debug("updateParentGrid "+this);

		for(var i=0; i<this.depth; i++){

			//dojo.debug("Parent "+parent);

			var idx = this.imgs.length-(3+i);
			var img = (this.tree.showGrid && !parent.isLastChild()) ? this.tree.gridIconSrcV : this.tree.blankIconSrc;

			//dojo.debug("Image "+img+" for "+idx);

			this.setGridImage(idx, img);

			parent = parent.parent;
		}
	},

	updateExpandGridColumn: function() {
		if (!this.tree.showGrid) return;

		var _this = this;

		var icon = this.isLastChild() ? this.tree.blankIconSrc : this.tree.gridIconSrcV;

		dojo.lang.forEach(_this.getDescendants(),
			function(node) { node.setGridImage(_this.depth, icon); }
		);

		this.updateExpandGrid();
	},

	updateIcons: function(){


		//dojo.profile.start("updateIcons")

		//dojo.debug("Update icons for "+this)
		//dojo.debug(this.isFolder)

		this.imgs[0].style.display = this.tree.showRootGrid ? 'inline' : 'none';


		//
		// set the expand icon
		//


		//
		// set the child icon
		//
		this.buildChildIcon();

		this.updateExpandGrid();
		this.updateChildGrid();
		this.updateParentGrid();



		dojo.profile.stop("updateIcons")

	},

	buildChildIcon: function() {
		// IE (others?) tries to download whatever is on src attribute so setting "url()" like before isnt a good idea
		// Only results in a 404
		if(this.childIconSrc){
			this.childIcon.src = this.childIconSrc;
		}
		this.childIcon.style.display = this.childIconSrc ? 'inline' : 'none';
	},

	setGridImage: function(idx, src){

		if (idx < 0){
			idx = this.imgs.length + idx;
		}

		//if (idx >= this.imgs.length-2) return;
		this.imgs[idx].style.backgroundImage = 'url(' + src + ')';
	},


	updateIconTree: function(){
		this.tree.updateIconTree.call(this);
	},




	expand: function(){
		if (this.isExpanded) return;

		if (this.children.length) {
			this.showChildren();
		}

		this.isExpanded = true;

		this.updateExpandIcon();

		dojo.event.topic.publish(this.tree.eventNames.expand, {source: this} );
	},

	collapse: function(){
		if (!this.isExpanded) return;

		this.hideChildren();
		this.isExpanded = false;

		this.updateExpandIcon();

		dojo.event.topic.publish(this.tree.eventNames.collapse, {source: this} );
	},

	hideChildren: function(){
		this.tree.toggleObj.hide(
			this.containerNode, this.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onHide")
		);

		/* if dnd is in action, recalculate changed coordinates */
		if(dojo.exists(dojo, 'dnd.dragManager.dragObjects') && dojo.dnd.dragManager.dragObjects.length) {
			dojo.dnd.dragManager.cacheTargetLocations();
		}
	},

	showChildren: function(){
		this.tree.toggleObj.show(
			this.containerNode, this.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onShow")
		);

		/* if dnd is in action, recalculate changed coordinates */
		if(dojo.exists(dojo, 'dnd.dragManager.dragObjects') && dojo.dnd.dragManager.dragObjects.length) {
			dojo.dnd.dragManager.cacheTargetLocations();
		}
	},

	addChild: function(){
		return this.tree.addChild.apply(this, arguments);
	},

	doAddChild: function(){
		return this.tree.doAddChild.apply(this, arguments);
	},



	/* Edit current node : change properties and update contents */
	edit: function(props) {
		dojo.lang.mixin(this, props);
		if (props.title) {
			this.titleNode.innerHTML = this.title;
		}

		if (props.afterLabel) {
			this.afterLabelNode.innerHTML = this.afterLabel;
		}

		if (props.childIconSrc) {
			this.buildChildIcon();
		}


	},


	removeNode: function(){ return this.tree.removeNode.apply(this, arguments) },
	doRemoveNode: function(){ return this.tree.doRemoveNode.apply(this, arguments) },


	toString: function() {
		return "["+this.widgetType+" Tree:"+this.tree+" ID:"+this.widgetId+" Title:"+this.title+"]";

	}

});





__CPAN_FILE__ src/widget/TreeSelectorV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeSelectorV3");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeCommon");

dojo.widget.defineWidget(
	"dojo.widget.TreeSelectorV3",
	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
	function() {
		this.eventNames = {};
		this.listenedTrees = {};
		this.selectedNodes = [];		
	},
{
	// TODO: add multiselect

	listenTreeEvents: ["afterTreeCreate","afterCollapse","afterChangeTree", "afterDetach", "beforeTreeDestroy"],
	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget},	
	
	allowedMulti: true,
	
	eventNamesDefault: {
		select : "select",
		deselect : "deselect",
		dblselect: "dblselect" // select already selected node.. Edit or whatever
	},

	onAfterTreeCreate: function(message) {
		var tree = message.source;
		dojo.event.browser.addListener(tree.domNode, "onclick", dojo.lang.hitch(this, this.onTreeClick));
		if (dojo.render.html.ie) {
			dojo.event.browser.addListener(tree.domNode, "ondblclick", dojo.lang.hitch(this, this.onTreeDblClick));
		}
		dojo.event.browser.addListener(tree.domNode, "onKey", dojo.lang.hitch(this, this.onKey));
		
	},
	
	
	onKey: function(e) {
		if (!e.key || e.ctrkKey || e.altKey) { return; }
		
		switch(e.key) {
			case e.KEY_ENTER:
				var node = this.domElement2TreeNode(e.target);
				if (node) {
					this.processNode(node, e);
				}
		
		}
	},
	
	
		
	onAfterChangeTree: function(message) {
		
		if (!message.oldTree && message.node.selected) {
			this.select(message.node);
		}
		
		if (!message.newTree || !this.listenedTrees[message.newTree.widgetId]) {
			// moving from our trfee to new one that we don't listen
			
			if (this.selectedNode && message.node.children) {
				this.deselectIfAncestorMatch(message.node);
			}						
			
		}
		
		
	},
		
		
		
	initialize: function(args) {

		for(name in this.eventNamesDefault) {
			if (dojo.lang.isUndefined(this.eventNames[name])) {
				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
			}
		}
				
	},

	onBeforeTreeDestroy: function(message) {
		this.unlistenTree(message.source);
	},

	// deselect node if ancestor is collapsed
	onAfterCollapse: function(message) {		
		this.deselectIfAncestorMatch(message.source);		
	},

	// IE will throw select -> dblselect. Need to transform to select->select
	onTreeDblClick: function(event) {
		this.onTreeClick(event);			
	},		
		
	checkSpecialEvent: function(event) {		
		return event.shiftKey || event.ctrlKey;
	},
	
	
	onTreeClick: function(event) {
				
		var node = this.domElement2TreeNode(event.target);
		
		if (!node) {
			return;
		}
		
		var checkLabelClick = function(domElement) {
			return domElement === node.labelNode;
		}
		
		if (this.checkPathCondition(event.target, checkLabelClick)) {
			//dojo.debug("condition ok");
			this.processNode(node, event);			
		}
		
		
	},
	
	
	/**
	 * press on selected with ctrl => deselect it
	 * press on selected w/o ctrl => dblselect it and deselect all other
	 *
	 * press on unselected with ctrl => add it to selection
	 *
	 * event may be both mouse & keyboard enter
	 */
	processNode: function(node, event) {
		
		if (node.actionIsDisabled(node.actions.SELECT)) {
			return;
		}
		
		//dojo.debug("click "+node+ "special "+this.checkSpecialEvent(event));
		//dojo.html.setClass(event.target, "TreeLabel TreeNodeEmphased");
		
		if (dojo.lang.inArray(this.selectedNodes, node)) {			
			if(this.checkSpecialEvent(event)){				
				// If the node is currently selected, and they select it again while holding
				// down a meta key, it deselects it
				this.deselect(node);
				return;
			}
			
			var _this = this;
			var i=0;
			var selectedNode;
			while(this.selectedNodes.length > i) {
				selectedNode = this.selectedNodes[i];
				if (selectedNode !== node) {
					//dojo.debug("Deselect "+selectedNode);
					_this.deselect(selectedNode);
					continue;
				}
			
				i++; // skip the doubleclicked node
			}
		
			
			dojo.event.topic.publish(this.eventNames.dblselect, { node: node });
			return;
		}
		
		// if unselected node..
		
		this.deselectIfNoMulti(event);
		
		//dojo.debug("select");

		this.select(node);

	},
	
	// deselect all if no meta key or disallowed
	deselectIfNoMulti: function(event) {
		if (!this.checkSpecialEvent(event) || !this.allowedMulti) {
			//dojo.debug("deselect All");
			this.deselectAll();
		}
	},

	deselectIfAncestorMatch: function(ancestor) {
		/* deselect all nodes with this ancestor */
		var _this = this;
		dojo.lang.forEach(this.selectedNodes, function(node) {
			var selectedNode = node;
			node = node.parent
			while (node && node.isTreeNode) {
				//dojo.debug("ancestor try "+node);
				
				if (node === ancestor) {
					_this.deselect(selectedNode); 
					return;					
				}
				node = node.parent;
			}
		});
	},
	
			


	onAfterDetach: function(message) {
		this.deselectIfAncestorMatch(message.child);		
	},


	select: function(node) {

		var index = dojo.lang.find(this.selectedNodes, node, true);
		
		if (index >=0 ) {
			return; // already selected
		}
				
		//dojo.debug("select "+node);
		this.selectedNodes.push(node);
						
		dojo.event.topic.publish(this.eventNames.select, {node: node} );
	},


	deselect: function(node){
		var index = dojo.lang.find(this.selectedNodes, node, true);
		if (index < 0) {
			//dojo.debug("not selected");
			return; // not selected
		}
		
		//dojo.debug("deselect "+node);
		//dojo.debug((new Error()).stack);
		
		this.selectedNodes.splice(index, 1);
		dojo.event.topic.publish(this.eventNames.deselect, {node: node} );
		//dojo.debug("deselect");

	},
	
	deselectAll: function() {
		//dojo.debug("deselect all "+this.selectedNodes);
		while (this.selectedNodes.length) {
			this.deselect(this.selectedNodes[0]);
		}
	}

});




__CPAN_FILE__ src/widget/PageContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.PageContainer");

dojo.require("dojo.lang.func");
dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.html.selection");

// A PageContainer is a container that has multiple children, but shows only
// one child at a time (like looking at the pages in a book one by one).
//
// Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
//
// Can be base class for container, Wizard, Show, etc.
dojo.widget.defineWidget("dojo.widget.PageContainer", dojo.widget.HtmlWidget, {
	isContainer: true,

	// Boolean
	//  if true, change the size of my currently displayed child to match my size
	doLayout: true,

	templateString: "<div dojoAttachPoint='containerNode'></div>",

	// String
	//   id of the initially shown page
	selectedChild: "",

	fillInTemplate: function(args, frag) {
		// Copy style info from input node to output node
		var source = this.getFragNodeRef(frag);
		dojo.html.copyStyle(this.domNode, source);
		dojo.widget.PageContainer.superclass.fillInTemplate.apply(this, arguments);
	},

	postCreate: function(args, frag) {
		if(this.children.length){
			// Setup each page panel
			dojo.lang.forEach(this.children, this._setupChild, this);

			// Figure out which child to initially display
			var initialChild;
			if(this.selectedChild){
				this.selectChild(this.selectedChild);
			}else{
				for(var i=0; i<this.children.length; i++){
					if(this.children[i].selected){
						this.selectChild(this.children[i]);
						break;
					}
				}
				if(!this.selectedChildWidget){
					this.selectChild(this.children[0]);
				}
			}
		}
	},

	addChild: function(child){
		dojo.widget.PageContainer.superclass.addChild.apply(this, arguments);
		this._setupChild(child);

		// in case the page labels have overflowed from one line to two lines
		this.onResized();

		// if this is the first child, then select it
		if(!this.selectedChildWidget){
			this.selectChild(child);
		}
	},

	_setupChild: function(page){
		// Summary: Add the given child to this page container

		page.hide();

		// publish the addChild event for panes added via addChild(), and the original panes too
		dojo.event.topic.publish(this.widgetId+"-addChild", page);
	},

	removeChild: function(/* Widget */page){
		dojo.widget.PageContainer.superclass.removeChild.apply(this, arguments);

		// If we are being destroyed than don't run the code below (to select another page), because we are deleting
		// every page one by one
		if(this._beingDestroyed){ return; }

		// this will notify any tablists to remove a button; do this first because it may affect sizing
		dojo.event.topic.publish(this.widgetId+"-removeChild", page);

		if (this.selectedChildWidget === page) {
			this.selectedChildWidget = undefined;
			if (this.children.length > 0) {
				this.selectChild(this.children[0], true);
			}
		}
	},

	selectChild: function(/* Widget */ page, /* Widget */ callingWidget){
		// summary
		//	Show the given widget (which must be one of my children)
		page = dojo.widget.byId(page);
		this.correspondingPageButton = callingWidget;

		// Deselect old page and select new one
		if(this.selectedChildWidget){
			this._hideChild(this.selectedChildWidget);
		}
		this.selectedChildWidget = page;
		this._showChild(page);
		page.isFirstChild = (page == this.children[0]);
		page.isLastChild = (page == this.children[this.children.length-1]);
		dojo.event.topic.publish(this.widgetId+"-selectChild", page);
	},

	forward: function(){
		// Summary: advance to next page
		var index = dojo.lang.find(this.children, this.selectedChildWidget);
		this.selectChild(this.children[index+1]);
	},

	back: function(){
		// Summary: go back to previous page
		var index = dojo.lang.find(this.children, this.selectedChildWidget);
		this.selectChild(this.children[index-1]);
	},

	onResized: function(){
		// Summary: called when any page is shown, to make it fit the container correctly
		if(this.doLayout && this.selectedChildWidget){
			with(this.selectedChildWidget.domNode.style){
				top = dojo.html.getPixelValue(this.containerNode, "padding-top", true);
				left = dojo.html.getPixelValue(this.containerNode, "padding-left", true);
			}
			var content = dojo.html.getContentBox(this.containerNode);
			this.selectedChildWidget.resizeTo(content.width, content.height);
		}
	},

	_showChild: function(page) {
		// size the current page (in case this is the first time it's being shown, or I have been resized)
		if(this.doLayout){
			var content = dojo.html.getContentBox(this.containerNode);
			page.resizeTo(content.width, content.height);
		}

		page.selected=true;
		page.show();
	},

	_hideChild: function(page) {
		page.selected=false;
		page.hide();
	},

	closeChild: function(page) {
		// summary
		//	callback when user clicks the [X] to remove a page
		//	if onClose() returns true then remove and destroy the childd
		var remove = page.onClose(this, page);
		if(remove) {
			this.removeChild(page);
			// makes sure we can clean up executeScripts in ContentPane onUnLoad
			page.destroy();
		}
	},

	destroy: function(){
		this._beingDestroyed = true;
		dojo.event.topic.destroy(this.widgetId+"-addChild");
		dojo.event.topic.destroy(this.widgetId+"-removeChild");
		dojo.event.topic.destroy(this.widgetId+"-selectChild");
		dojo.widget.PageContainer.superclass.destroy.apply(this, arguments);
	}
});


// PageController - set of buttons to select the page in a page list
// When intialized, the PageController monitors the container, and whenever a page is
// added or deleted updates itself accordingly.
dojo.widget.defineWidget(
    "dojo.widget.PageController",
    dojo.widget.HtmlWidget,
	{
		templateString: "<span wairole='tablist' dojoAttachEvent='onKey'></span>",
		isContainer: true,

		// String
		//	the id of the page container that I point to
		containerId: "",

		// String
		//	the name of the button widget to create to correspond to each page
		buttonWidget: "PageButton",

		// String
		//	Class name to apply to the top dom node
		"class": "dojoPageController",

		fillInTemplate: function() {
			dojo.html.addClass(this.domNode, this["class"]);  // "class" is a reserved word in JS
			dojo.widget.wai.setAttr(this.domNode, "waiRole", "role", "tablist");
		},

		postCreate: function(){
			this.pane2button = {};		// mapping from panes to buttons

			// If children have already been added to the page container then create buttons for them
			var container = dojo.widget.byId(this.containerId);
			if(container){
				dojo.lang.forEach(container.children, this.onAddChild, this);
			}

			dojo.event.topic.subscribe(this.containerId+"-addChild", this, "onAddChild");
			dojo.event.topic.subscribe(this.containerId+"-removeChild", this, "onRemoveChild");
			dojo.event.topic.subscribe(this.containerId+"-selectChild", this, "onSelectChild");
		},

		destroy: function(){
			dojo.event.topic.unsubscribe(this.containerId+"-addChild", this, "onAddChild");
			dojo.event.topic.unsubscribe(this.containerId+"-removeChild", this, "onRemoveChild");
			dojo.event.topic.unsubscribe(this.containerId+"-selectChild", this, "onSelectChild");
			dojo.widget.PageController.superclass.destroy.apply(this, arguments);
		},

		onAddChild: function(/* Widget */ page){
			// summary
			//   Called whenever a page is added to the container.
			//   Create button corresponding to the page.
			var button = dojo.widget.createWidget(this.buttonWidget,
				{
					label: page.label,
					closeButton: page.closable
				});
			this.addChild(button);
			this.domNode.appendChild(button.domNode);
			this.pane2button[page]=button;
			page.controlButton = button;	// this value might be overwritten if two tabs point to same container

			var _this = this;
			dojo.event.connect(button, "onClick", function(){ _this.onButtonClick(page); });
			dojo.event.connect(button, "onCloseButtonClick", function(){ _this.onCloseButtonClick(page); });
		},

		onRemoveChild: function(/* Widget */ page){
			// summary
			//   Called whenever a page is removed from the container.
			//   Remove the button corresponding to the page.
			if(this._currentChild == page){ this._currentChild = null; }
			var button = this.pane2button[page];
			if(button){
				button.destroy();
			}
			this.pane2button[page] = null;
		},

		onSelectChild: function(/*Widget*/ page){
			// Summary
			//	Called when a page has been selected in the PageContainer, either by me or by another PageController
			if(this._currentChild){
				var oldButton=this.pane2button[this._currentChild];
				oldButton.clearSelected();
			}
			var newButton=this.pane2button[page];
			newButton.setSelected();
			this._currentChild=page;
		},

		onButtonClick: function(/*Widget*/ page){
			// summary
			//   Called whenever one of my child buttons is pressed in an attempt to select a page
			var container = dojo.widget.byId(this.containerId);	// TODO: do this via topics?
			container.selectChild(page, false, this);
		},

		onCloseButtonClick: function(/*Widget*/ page){
			// summary
			//   Called whenever one of my child buttons [X] is pressed in an attempt to close a page
			var container = dojo.widget.byId(this.containerId);
			container.closeChild(page);
		},

		onKey: function(evt){
			// summary:
			//   Handle keystrokes on the page list, for advancing to next/previous button

			if( (evt.keyCode == evt.KEY_RIGHT_ARROW)||
				(evt.keyCode == evt.KEY_LEFT_ARROW) ){
				var current = 0;
				var next = null;	// the next button to focus on
				
				// find currently focused button in children array
				var current = dojo.lang.find(this.children, this.pane2button[this._currentChild]);
				
				// pick next button to focus on
				if(evt.keyCode == evt.KEY_RIGHT_ARROW){
					next = this.children[ (current+1) % this.children.length ]; 
				}else{ // is LEFT_ARROW
					next = this.children[ (current+ (this.children.length-1)) % this.children.length ];
				}
				
				dojo.event.browser.stopEvent(evt);
				next.onClick();
			}
		}
	}
);

// PageButton (the thing you click to select or delete a page)
dojo.widget.defineWidget("dojo.widget.PageButton", dojo.widget.HtmlWidget,
{
	templateString: "<span class='item'>" +
						"<span dojoAttachEvent='onClick' dojoAttachPoint='titleNode' class='selectButton'>${this.label}</span>" +
						"<span dojoAttachEvent='onClick:onCloseButtonClick' class='closeButton'>[X]</span>" +
					"</span>",

	// String
	//  Name to print on the button
	label: "foo",
	
	// Boolean
	//	true iff we should also print a close icon to destroy corresponding page
	closeButton: false,

	onClick: function(){
		// summary
		//  Basically this is the attach point PageController listens to, to select the page
		this.focus();
	},

	onCloseButtonMouseOver: function(){
		// summary
		//	The close button changes color a bit when you mouse over	
		dojo.html.addClass(this.closeButtonNode, "closeHover");
	},

	onCloseButtonMouseOut: function(){
		// summary
		// 	Revert close button to normal color on mouse out
		dojo.html.removeClass(this.closeButtonNode, "closeHover");
	},

	onCloseButtonClick: function(evt){
		// summary
		//	Handle clicking the close button for this tab
	},
	
	setSelected: function(){
		// summary
		//	This is run whenever the page corresponding to this button has been selected
		dojo.html.addClass(this.domNode, "current");
		this.titleNode.setAttribute("tabIndex","0");
	},
	
	clearSelected: function(){
		// summary
		//	This function is run whenever the page corresponding to this button has been deselected (and another page has been shown)
		dojo.html.removeClass(this.domNode, "current");
		this.titleNode.setAttribute("tabIndex","-1");
	},

	focus: function(){
		// summary
		//	This will focus on the this button (for accessibility you need to do this when the button is selected)
		if(this.titleNode.focus){	// mozilla 1.7 doesn't have focus() func
			this.titleNode.focus();
		}
	}
});

// These arguments can be specified for the children of a PageContainer.
// Since any widget can be specified as a PageContainer child, mix them
// into the base widget class.  (This is a hack, but it's effective.)
dojo.lang.extend(dojo.widget.Widget, {
	label: "",
	selected: false,	// is this tab currently selected?
	closable: false,	// true if user can close this tab pane
	onClose: function(){ return true; }	// callback if someone tries to close the child, child will be closed if func returns true
});

__CPAN_FILE__ src/widget/TreeDeselectOnDblselect.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeDeselectOnDblselect");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeSelectorV3");

// selector extension to emphase node

dojo.widget.defineWidget(
	"dojo.widget.TreeDeselectOnDblselect",
	[dojo.widget.HtmlWidget],
{
	selector: "",
	
	initialize: function() {
		this.selector = dojo.widget.byId(this.selector);
		//dojo.debug("OK "+this.selector);
		dojo.event.topic.subscribe(this.selector.eventNames.dblselect, this, "onDblselect");		
	},

	onDblselect: function(message) {
		//dojo.debug("happen "+this.selector);
		//dojo.debug(message.node);
		this.selector.deselect(message.node);
	}
});

__CPAN_FILE__ src/widget/DebugConsole.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DebugConsole");
dojo.require("dojo.widget.Widget");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.FloatingPane");

dojo.widget.defineWidget(
	"dojo.widget.DebugConsole",
	dojo.widget.FloatingPane,
{
	fillInTemplate: function() {
		dojo.widget.DebugConsole.superclass.fillInTemplate.apply(this, arguments);
		this.containerNode.id = "debugConsoleClientPane";
		djConfig.isDebug = true;
		djConfig.debugContainerId = this.containerNode.id;
	}
});

__CPAN_FILE__ src/widget/HtmlWidget.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.DomWidget");
dojo.require("dojo.html.util");
dojo.require("dojo.html.display");
dojo.require("dojo.html.layout");
dojo.require("dojo.lang.extras");
dojo.require("dojo.lang.func");
dojo.require("dojo.lfx.toggle");

dojo.declare("dojo.widget.HtmlWidget", dojo.widget.DomWidget, {								 
	widgetType: "HtmlWidget",

	templateCssPath: null,
	templatePath: null,

	lang: "",
	// for displaying/hiding widget
	toggle: "plain",
	toggleDuration: 150,

	animationInProgress: false,

	initialize: function(args, frag){
	},

	postMixInProperties: function(args, frag){
		if(this.lang === ""){this.lang = null;}
		// now that we know the setting for toggle, get toggle object
		// (default to plain toggler if user specified toggler not present)
		this.toggleObj =
			dojo.lfx.toggle[this.toggle.toLowerCase()] || dojo.lfx.toggle.plain;
	},

	getContainerHeight: function(){
		// NOTE: container height must be returned as the INNER height
		dojo.unimplemented("dojo.widget.HtmlWidget.getContainerHeight");
	},

	getContainerWidth: function(){
		return this.parent.domNode.offsetWidth;
	},

	setNativeHeight: function(height){
		var ch = this.getContainerHeight();
	},

	createNodesFromText: function(txt, wrap){
		return dojo.html.createNodesFromText(txt, wrap);
	},

	destroyRendering: function(finalize){
		try{
			if(!finalize && this.domNode){
				dojo.event.browser.clean(this.domNode);
			}
			this.domNode.parentNode.removeChild(this.domNode);
			delete this.domNode;
		}catch(e){ /* squelch! */ }
	},

	/////////////////////////////////////////////////////////
	// Displaying/hiding the widget
	/////////////////////////////////////////////////////////
	isShowing: function(){
		return dojo.html.isShowing(this.domNode);
	},

	toggleShowing: function(){
		// dojo.html.toggleShowing(this.domNode);
		if(this.isHidden){
			this.show();
		}else{
			this.hide();
		}
	},

	show: function(){
		this.animationInProgress=true;
		this.isHidden = false;
		this.toggleObj.show(this.domNode, this.toggleDuration, null,
			dojo.lang.hitch(this, this.onShow), this.explodeSrc);
	},

	// called after the show() animation has completed
	onShow: function(){
		this.animationInProgress=false;
		this.checkSize();
	},

	hide: function(){
		this.animationInProgress = true;
		this.isHidden = true;
		this.toggleObj.hide(this.domNode, this.toggleDuration, null,
			dojo.lang.hitch(this, this.onHide), this.explodeSrc);
	},

	// called after the hide() animation has completed
	onHide: function(){
		this.animationInProgress=false;
	},

	//////////////////////////////////////////////////////////////////////////////
	// Sizing related methods
	//  If the parent changes size then for each child it should call either
	//   - resizeTo(): size the child explicitly
	//   - or checkSize(): notify the child the the parent has changed size
	//////////////////////////////////////////////////////////////////////////////

	// Test if my size has changed.
	// If width & height are specified then that's my new size; otherwise,
	// query outerWidth/outerHeight of my domNode
	_isResized: function(w, h){
		// If I'm not being displayed then disregard (show() must
		// check if the size has changed)
		if(!this.isShowing()){ return false; }

		// If my parent has been resized and I have style="height: 100%"
		// or something similar then my size has changed too.
		var wh = dojo.html.getMarginBox(this.domNode);
		var width=w||wh.width;
		var height=h||wh.height;
		if(this.width == width && this.height == height){ return false; }

		this.width=width;
		this.height=height;
		return true;
	},

	// Called when my parent has changed size, but my parent won't call resizeTo().
	// This is useful if my size is height:100% or something similar.
	// Also called whenever I am shown, because the first time I am shown I may need
	// to do size calculations.
	checkSize: function(){
		if(!this._isResized()){ return; }
		this.onResized();
	},

	// Explicitly set this widget's size (in pixels).
	resizeTo: function(w, h){
		dojo.html.setMarginBox(this.domNode, { width: w, height: h });
		
		// can't do sizing if widget is hidden because referencing node.offsetWidth/node.offsetHeight returns 0.
		// do sizing on show() instead.
		if(this.isShowing()){
			this.onResized();
		}
	},

	resizeSoon: function(){
		if(this.isShowing()){
			dojo.lang.setTimeout(this, this.onResized, 0);
		}
	},

	// Called when my size has changed.
	// Must notify children if their size has (possibly) changed
	onResized: function(){
		dojo.lang.forEach(this.children, function(child){ if(child.checkSize){child.checkSize();} });
	}
});

__CPAN_FILE__ src/widget/ShowAction.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ShowAction");
dojo.require("dojo.widget.*");

dojo.widget.defineWidget(
	"dojo.widget.ShowAction",
	dojo.widget.HtmlWidget,
{
	on: "",
	action: "fade",
	duration: 350,
	from: "",
	to: "",
	auto: "false"
});

__CPAN_FILE__ src/widget/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: ["dojo.xml.Parse", 
			 "dojo.widget.Widget", 
			 "dojo.widget.Parse", 
			 "dojo.widget.Manager"],
	browser: ["dojo.widget.DomWidget",
			  "dojo.widget.HtmlWidget"],
	dashboard: ["dojo.widget.DomWidget",
			  "dojo.widget.HtmlWidget"],
	svg: 	 ["dojo.widget.SvgWidget"],
	rhino: 	 ["dojo.widget.SwtWidget"]
});
dojo.provide("dojo.widget.*");

__CPAN_FILE__ src/widget/Menu2.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Menu2");

dojo.require("dojo.widget.PopupContainer");

// summary
//	provides a menu that can be used as a context menu (typically shown by right-click),
//	or as the drop down on a DropDownButton, ComboButton, etc.
dojo.widget.defineWidget(
	"dojo.widget.PopupMenu2",
	dojo.widget.PopupContainer,
	function(){
		this.targetNodeIds = []; // fill this with nodeIds upon widget creation and it becomes context menu for those nodes
	
		this.eventNames =  {
			open: ""
		};
	},
{
	snarfChildDomOutput: true,

	// String
	//	if "default" event names are based on widget id, otherwise user must define
	//	TODO: write real documentation about the events
	eventNaming: "default",

	templateString: '<table class="dojoPopupMenu2" border=0 cellspacing=0 cellpadding=0 style="display: none;"><tbody dojoAttachPoint="containerNode"></tbody></table>',
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Menu2.css"),
	templateCssString: "",

	// Integer
	//	number of milliseconds before hovering (without clicking) causes the submenu to automatically open
	submenuDelay: 500,
	
	// Integer
	//	a submenu usually appears to the right, but slightly overlapping, it's parent menu;
	//	this controls the number of pixels the two menus overlap.
	submenuOverlap: 5,
	
	// Boolean
	//	if true, right clicking anywhere on the window will cause this context menu to open;
	//	if false, must specify targetNodeIds
	contextMenuForWindow: false,

	// Array
	//	Array of dom node ids of nodes to attach to
	targetNodeIds: [],

	initialize: function(args, frag) {
		if (this.eventNaming == "default") {
			for (var eventName in this.eventNames) {
				this.eventNames[eventName] = this.widgetId+"/"+eventName;
			}
		}
	},

	postCreate: function(){
		if (this.contextMenuForWindow){
			var doc = dojo.body();
			this.bindDomNode(doc);
		} else if ( this.targetNodeIds.length > 0 ){
			dojo.lang.forEach(this.targetNodeIds, this.bindDomNode, this);
		}

		this._subscribeSubitemsOnOpen();
	},

	_subscribeSubitemsOnOpen: function() {
		var subItems = this.getChildrenOfType(dojo.widget.MenuItem2);

		for(var i=0; i<subItems.length; i++) {
			dojo.event.topic.subscribe(this.eventNames.open, subItems[i], "menuOpen")
		}
	},

	getTopOpenEvent: function() {
		// summary: get event that initially caused current chain of menus to open
		var menu = this;
		while (menu.parentPopup){ menu = menu.parentPopup; }
		return menu.openEvent;	// Event
	},

	bindDomNode: function(/*String|DomNode*/ node){
		// summary: attach menu to given node
		node = dojo.byId(node);

		var win = dojo.html.getElementWindow(node);
		if(dojo.html.isTag(node,'iframe') == 'iframe'){
			win = dojo.html.iframeContentWindow(node);
			node = dojo.withGlobal(win, dojo.body);
		}
		// fixes node so that it supports oncontextmenu if not natively supported, Konqueror, Opera more?
		dojo.widget.Menu2.OperaAndKonqFixer.fixNode(node);

		dojo.event.kwConnect({
			srcObj:     node,
			srcFunc:    "oncontextmenu",
			targetObj:  this,
			targetFunc: "onOpen",
			once:       true
		});

		//normal connect does not work if document.designMode is on in FF, use addListener instead
		if(dojo.render.html.moz && win.document.designMode.toLowerCase() == 'on'){
			dojo.event.browser.addListener(node, "contextmenu", dojo.lang.hitch(this, "onOpen"));
		}
		dojo.widget.PopupManager.registerWin(win);
	},

	unBindDomNode: function(/*String|DomNode*/ nodeName){
		// summary: detach menu from given node
		var node = dojo.byId(nodeName);
		dojo.event.kwDisconnect({
			srcObj:     node,
			srcFunc:    "oncontextmenu",
			targetObj:  this,
			targetFunc: "onOpen",
			once:       true
		});

		// cleans a fixed node, konqueror and opera
		dojo.widget.Menu2.OperaAndKonqFixer.cleanNode(node);
	},

	_moveToNext: function(/*Event*/ evt){
		this._highlightOption(1);
		return true; //do not pass to parent menu
	},

	_moveToPrevious: function(/*Event*/ evt){
		this._highlightOption(-1);
		return true; //do not pass to parent menu
	},

	_moveToParentMenu: function(/*Event*/ evt){
		if(this._highlighted_option && this.parentPopup){
			//only process event in the focused menu
			//and its immediate parentPopup to support
			//MenuBar2
			if(evt._menu2UpKeyProcessed){
				return true; //do not pass to parent menu
			}else{
				this._highlighted_option.onUnhover();
				this.closeSubpopup();
				evt._menu2UpKeyProcessed = true;
			}
		}
		return false;
	},

	_moveToChildMenu: function(/*Event*/ evt){
		if(this._highlighted_option && this._highlighted_option.submenuId){
			this._highlighted_option._onClick(true);
			return true; //do not pass to parent menu
		}
		return false;
	},

	_selectCurrentItem: function(/*Event*/ evt){
		if(this._highlighted_option){
			this._highlighted_option._onClick();
			return true;
		}
		return false;
	},

	processKey: function(/*Event*/ evt){
		// summary
		//	callback to process key strokes
		//	return true to stop the event being processed by the
		//	parent popupmenu

		if(evt.ctrlKey || evt.altKey || !evt.key){ return false; }

		var rval = false;
		switch(evt.key){
 			case evt.KEY_DOWN_ARROW:
				rval = this._moveToNext(evt);
				break;
			case evt.KEY_UP_ARROW:
				rval = this._moveToPrevious(evt);
				break;
			case evt.KEY_RIGHT_ARROW:
				rval = this._moveToChildMenu(evt);
				break;
			case evt.KEY_LEFT_ARROW:
				rval = this._moveToParentMenu(evt);
				break;
			case " ": //fall through
			case evt.KEY_ENTER: 
				if(rval = this._selectCurrentItem(evt)){
					break;
				}
				//fall through
			case evt.KEY_ESCAPE:
				dojo.widget.PopupManager.currentMenu.close();
				rval = true;
				break;
		}

		return rval;
	},

	_findValidItem: function(dir, curItem){
		if(curItem){
			curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
		}

		for(var i=0; i < this.children.length; ++i){
			if(!curItem){
				curItem = dir>0 ? this.children[0] : this.children[this.children.length-1];
			}
			//find next/previous visible menu item, not including separators
			if(curItem.onHover && curItem.isShowing()){
				return curItem;
			}
			curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
		}
	},
	
	_highlightOption: function(dir){
		var item;
		// || !this._highlighted_option.parentNode
		if((!this._highlighted_option)){
			item = this._findValidItem(dir);
		}else{
			item = this._findValidItem(dir, this._highlighted_option);
		}
		if(item){
			if(this._highlighted_option) {
				this._highlighted_option.onUnhover();
			}
			item.onHover();
			dojo.html.scrollIntoView(item.domNode);
			// navigate into the item table and select the first caption tag
			try {
				var node = dojo.html.getElementsByClass("dojoMenuItem2Label", item.domNode)[0];
				node.focus();
			} catch(e) { }
		}
	},

	onItemClick: function(/*Widget*/ item) {
		// summary: user defined function to handle clicks on an item
	},

	close: function(/*Boolean*/ force){
		// summary: close the menu
		if(this.animationInProgress){
			dojo.widget.PopupMenu2.superclass.close.apply(this, arguments);
			return;
		}

		if(this._highlighted_option){
			this._highlighted_option.onUnhover();
		}

		dojo.widget.PopupMenu2.superclass.close.apply(this, arguments);
	},

	closeSubpopup: function(force){
		// summary: close the currently displayed submenu
		if (this.currentSubpopup == null){ return; }

		this.currentSubpopup.close(force);
		this.currentSubpopup = null;

		this.currentSubmenuTrigger.is_open = false;
		this.currentSubmenuTrigger._closedSubmenu(force);
		this.currentSubmenuTrigger = null;
	},

	_openSubmenu: function(submenu, from_item){
		// summary: open the menu to the right of the current menu item
		var fromPos = dojo.html.getAbsolutePosition(from_item.domNode, true);
		var our_w = dojo.html.getMarginBox(this.domNode).width;
		var x = fromPos.x + our_w - this.submenuOverlap;
		var y = fromPos.y;

		//the following is set in open, so we do not need it
		//this.currentSubpopup = submenu;
		submenu.open(x, y, this, from_item.domNode);

		this.currentSubmenuTrigger = from_item;
		this.currentSubmenuTrigger.is_open = true;
	},

	onOpen: function(/*Event*/ e){
		// summary: callback when menu is opened
		this.openEvent = e;
		if(e["target"]){
			this.openedForWindow = dojo.html.getElementWindow(e.target);
		}else{
			this.openedForWindow = null;
		}
		var x = e.pageX, y = e.pageY;

		var win = dojo.html.getElementWindow(e.target);
		var iframe = win._frameElement || win.frameElement;
		if(iframe){
			var cood = dojo.html.abs(iframe, true);
			x += cood.x - dojo.withGlobal(win, dojo.html.getScroll).left;
			y += cood.y - dojo.withGlobal(win, dojo.html.getScroll).top;
		}
		this.open(x, y, null, [x, y]);

		e.preventDefault();
		e.stopPropagation();
	}
});

// summary
//	A line item in a Menu2
dojo.widget.defineWidget(
	"dojo.widget.MenuItem2",
	dojo.widget.HtmlWidget,
	function(){
		this.eventNames = {
			engage: ""
		};
	},
{
	// Make 4 columns
	//   icon, label, accelerator-key, and right-arrow indicating sub-menu
	templateString:
		 '<tr class="dojoMenuItem2" dojoAttachEvent="onMouseOver: onHover; onMouseOut: onUnhover; onClick: _onClick; onKey:onKey;">'
		+'<td><div class="${this.iconClass}" style="${this.iconStyle}"></div></td>'
		+'<td tabIndex="-1" class="dojoMenuItem2Label">${this.caption}</td>'
		+'<td class="dojoMenuItem2Accel">${this.accelKey}</td>'
		+'<td><div class="dojoMenuItem2Submenu" style="display:${this.arrowDisplay};"></div></td>'
		+'</tr>',

	//
	// internal settings
	//

	is_hovering: false,
	hover_timer: null,
	is_open: false,
	topPosition: 0,

	//
	// options
	//

	// String
	//	text of the menu item
	caption: 'Untitled',
	
	// String
	//	accelerator key (not supported yet!)
	accelKey: '',
	
	// String
	//	path to icon to display to the left of the menu text
	iconSrc: '',
	
	// String
	//	CSS class name to use for menu item (if CSS class specifies a background image then iconSrc is not necessary)
	iconClass: 'dojoMenuItem2Icon',
	
	// String
	//	widget ID of Menu2 widget to open when this menu item is clicked
	submenuId: '',
	
	// Boolean
	//	if true, this menu item cannot be selected
	disabled: false,
	
	// String
	//	event names for announcing when menu item is clicked.
	//	if "default", then use the default name, based on the widget ID
	eventNaming: "default",
	
	// String
	//	CSS class for menu item when it's hovered over
	highlightClass: 'dojoMenuItem2Hover',

	postMixInProperties: function(){
		this.iconStyle="";
		if (this.iconSrc){
			if ((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4) == ".png") && (dojo.render.html.ie55 || dojo.render.html.ie60)){
				this.iconStyle="filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='image')";
			}else{
				this.iconStyle="background-image: url("+this.iconSrc+")";
			}
		}
		this.arrowDisplay = this.submenuId ? 'block' : 'none';
		dojo.widget.MenuItem2.superclass.postMixInProperties.apply(this, arguments);
	},

	fillInTemplate: function(){
		dojo.html.disableSelection(this.domNode);

		if (this.disabled){
			this.setDisabled(true);
		}

		if (this.eventNaming == "default") {
			for (var eventName in this.eventNames) {
				this.eventNames[eventName] = this.widgetId+"/"+eventName;
			}
		}
	},

	onHover: function(){
		// summary: callback when mouse is moved onto menu item

		//this is to prevent some annoying behavior when both mouse and keyboard are used
		this.onUnhover();

		if (this.is_hovering){ return; }
		if (this.is_open){ return; }

		if(this.parent._highlighted_option){
			this.parent._highlighted_option.onUnhover();
		}
		this.parent.closeSubpopup();
		this.parent._highlighted_option = this;
		dojo.widget.PopupManager.setFocusedMenu(this.parent);

		this._highlightItem();

		if (this.is_hovering){ this._stopSubmenuTimer(); }
		this.is_hovering = true;
		this._startSubmenuTimer();
	},

	onUnhover: function(){
		// summary: callback when mouse is moved off of menu item
		if(!this.is_open){ this._unhighlightItem(); }

		this.is_hovering = false;

		this.parent._highlighted_option = null;

		if(this.parent.parentPopup){
			dojo.widget.PopupManager.setFocusedMenu(this.parent.parentPopup);
		}

		this._stopSubmenuTimer();
	},

	_onClick: function(focus){
		// summary: internal function for clicks
		var displayingSubMenu = false;
		if (this.disabled){ return false; }

		if (this.submenuId){
			if (!this.is_open){
				this._stopSubmenuTimer();
				this._openSubmenu();
			}
			displayingSubMenu = true;
		}else{
			// for some browsers the onMouseOut doesn't get called (?), so call it manually
			this.onUnhover(); //only onUnhover when no submenu is available
			this.parent.closeAll(true);
		}

		// user defined handler for click
		this.onClick();

		dojo.event.topic.publish(this.eventNames.engage, this);

		if(displayingSubMenu && focus){
			dojo.widget.getWidgetById(this.submenuId)._highlightOption(1);
		}
		return;
	},

	onClick: function() {
		// summary
		//	User defined function to handle clicks
		//	this default function call the parent
		//	menu's onItemClick
		this.parent.onItemClick(this);
	},

	_highlightItem: function(){
		dojo.html.addClass(this.domNode, this.highlightClass);
	},

	_unhighlightItem: function(){
		dojo.html.removeClass(this.domNode, this.highlightClass);
	},

	_startSubmenuTimer: function(){
		this._stopSubmenuTimer();

		if (this.disabled){ return; }

		var self = this;
		var closure = function(){ return function(){ self._openSubmenu(); } }();

		this.hover_timer = dojo.lang.setTimeout(closure, this.parent.submenuDelay);
	},

	_stopSubmenuTimer: function(){
		if (this.hover_timer){
			dojo.lang.clearTimeout(this.hover_timer);
			this.hover_timer = null;
		}
	},

	_openSubmenu: function(){
		if (this.disabled){ return; }

		// first close any other open submenu
		this.parent.closeSubpopup();

		var submenu = dojo.widget.getWidgetById(this.submenuId);
		if (submenu){
			this.parent._openSubmenu(submenu, this);
		}
	},

	_closedSubmenu: function(){
		this.onUnhover();
	},

	setDisabled: function(/*Boolean*/ value){
		// summary: enable or disable this menu item
		this.disabled = value;

		if (this.disabled){
			dojo.html.addClass(this.domNode, 'dojoMenuItem2Disabled');
		}else{
			dojo.html.removeClass(this.domNode, 'dojoMenuItem2Disabled');
		}
	},

	enable: function(){
		// summary: enable this menu item so user can click it
		this.setDisabled(false);
	},

	disable: function(){
		// summary: disable this menu item so user can't click it
		this.setDisabled(true);
	},

	menuOpen: function(message) {
		// summary: callback when menu is opened
		// TODO: I don't see anyone calling this menu item
	}

});

// summary
//	A line between two menu items
dojo.widget.defineWidget(
	"dojo.widget.MenuSeparator2",
	dojo.widget.HtmlWidget,
{
	templateString: '<tr class="dojoMenuSeparator2"><td colspan=4>'
			+'<div class="dojoMenuSeparator2Top"></div>'
			+'<div class="dojoMenuSeparator2Bottom"></div>'
			+'</td></tr>',

	postCreate: function(){
		dojo.html.disableSelection(this.domNode);
	}
});

// summary
//	A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications
dojo.widget.defineWidget(
	"dojo.widget.MenuBar2",
	dojo.widget.PopupMenu2,
{
	menuOverlap: 2,

	templateString: '<div class="dojoMenuBar2" tabIndex="0"><table class="dojoMenuBar2Client"><tr dojoAttachPoint="containerNode"></tr></table></div>',

	close: function(force){
		if(this._highlighted_option){
			this._highlighted_option.onUnhover();
		}

		this.closeSubpopup(force);
	},

	processKey: function(/*Event*/ evt){
		if(evt.ctrlKey || evt.altKey){ return false; }

		if (!dojo.html.hasClass(evt.target,"dojoMenuBar2")) { return false; }
		var rval = false;

		switch(evt.key){
 			case evt.KEY_DOWN_ARROW:
				rval = this._moveToChildMenu(evt);
				break;
			case evt.KEY_UP_ARROW:
				rval = this._moveToParentMenu(evt);
				break;
			case evt.KEY_RIGHT_ARROW:
				rval = this._moveToNext(evt);
				break;
			case evt.KEY_LEFT_ARROW:
				rval = this._moveToPrevious(evt);
				break;
			default:
				rval = 	dojo.widget.MenuBar2.superclass.processKey.apply(this, arguments);
				break;
		}

		return rval;
	},

	postCreate: function(){
		dojo.widget.MenuBar2.superclass.postCreate.apply(this, arguments);
		dojo.widget.PopupManager.opened(this);
		this.isShowingNow = true;
	},

	/*
	 * override PopupMenu2 to open the submenu below us rather than to our right
	 */
	_openSubmenu: function(submenu, from_item){
		var fromPos = dojo.html.getAbsolutePosition(from_item.domNode, true);
		var ourPos = dojo.html.getAbsolutePosition(this.domNode, true);
		var our_h = dojo.html.getBorderBox(this.domNode).height;
		var x = fromPos.x;
		var y = ourPos.y + our_h - this.menuOverlap;

		submenu.open(x, y, this, from_item.domNode);

		this.currentSubmenuTrigger = from_item;
		this.currentSubmenuTrigger.is_open = true;
	}
});

// summary
//	Item in a Menu2Bar
dojo.widget.defineWidget(
	"dojo.widget.MenuBarItem2",
	dojo.widget.MenuItem2,
{
	templateString:
		 '<td class="dojoMenuBarItem2" dojoAttachEvent="onMouseOver: onHover; onMouseOut: onUnhover; onClick: _onClick;">'
		+'<span>${this.caption}</span>'
		+'</td>',

	highlightClass: 'dojoMenuBarItem2Hover',

	setDisabled: function(value){
		this.disabled = value;
		if (this.disabled){
			dojo.html.addClass(this.domNode, 'dojoMenuBarItem2Disabled');
		}else{
			dojo.html.removeClass(this.domNode, 'dojoMenuBarItem2Disabled');
		}
	}
});


// ************************** make contextmenu work in konqueror and opera *********************
dojo.widget.Menu2.OperaAndKonqFixer = new function(){
 	var implement = true;
 	var delfunc = false;

 	/** 	dom event check
 	*
 	*	make a event and dispatch it and se if it calls function below,
 	*	if it indeed is supported and we dont need to implement our own
 	*/

 	// gets called if we have support for oncontextmenu
 	if (!dojo.lang.isFunction(dojo.doc().oncontextmenu)){
 		dojo.doc().oncontextmenu = function(){
 			implement = false;
 			delfunc = true;
 		}
 	}

 	if (dojo.doc().createEvent){ // moz, safari has contextmenu event, need to do livecheck on this env.
 		try {
 			var e = dojo.doc().createEvent("MouseEvents");
 			e.initMouseEvent("contextmenu", 1, 1, dojo.global(), 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
 			dojo.doc().dispatchEvent(e);
 		} catch (e) {/* assume not supported */}
 	} else {
 		// IE no need to implement custom contextmenu
 		implement = false;
 	}

 	// clear this one if it wasn't there before
 	if (delfunc){
 		delete dojo.doc().oncontextmenu;
 	}
 	/***** end dom event check *****/


 	/**
 	*	this fixes a dom node by attaching a custom oncontextmenu function that gets called when apropriate
 	*	@param	node	a dom node
 	*
 	*	no returns
 	*/
 	this.fixNode = function(node){
 		if (implement){
 			// attach stub oncontextmenu function
 			if (!dojo.lang.isFunction(node.oncontextmenu)){
 				node.oncontextmenu = function(e){/*stub*/}
 			}

 			// attach control function for oncontextmenu
 			if (dojo.render.html.opera){
 				// opera
 				// listen to ctrl-click events
 				node._menufixer_opera = function(e){
 					if (e.ctrlKey){
 						this.oncontextmenu(e);
 					}
 				};

 				dojo.event.connect(node, "onclick", node, "_menufixer_opera");

 			} else {
 				// konqueror
 				// rightclick, listen to mousedown events
 				node._menufixer_konq = function(e){
 					if (e.button==2 ){
 						e.preventDefault(); // need to prevent browsers menu
 						this.oncontextmenu(e);
 					}
 				};

 				dojo.event.connect(node, "onmousedown", node, "_menufixer_konq");
 			}
 		}
 	}

 	/**
 	*	this cleans up a fixed node, prevent memoryleak?
 	*	@param node	node to clean
 	*
 	*	no returns
 	*/
 	this.cleanNode = function(node){
 		if (implement){
 			// checks needed if we gets a non fixed node
 			if (node._menufixer_opera){
 				dojo.event.disconnect(node, "onclick", node, "_menufixer_opera");
 				delete node._menufixer_opera;
 			} else if(node._menufixer_konq){
 				dojo.event.disconnect(node, "onmousedown", node, "_menufixer_konq");
 				delete node._menufixer_konq;
 			}
 			if (node.oncontextmenu){
 				delete node.oncontextmenu;
 			}
 		}
 	}
};
__CPAN_FILE__ src/widget/FilteringTable.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.FilteringTable");

dojo.require("dojo.date.format");
dojo.require("dojo.collections.Store");
dojo.require("dojo.html.*");
dojo.require("dojo.html.util");
dojo.require("dojo.html.style");
dojo.require("dojo.html.selection");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget(
	"dojo.widget.FilteringTable", 
	dojo.widget.HtmlWidget, 
	function(){
		//	summary
		//	Initializes all properties for the widget.
		this.store=new dojo.collections.Store();

		//declare per instance changeable widget properties
		this.valueField="Id";
		this.multiple=false;
		this.maxSelect=0;
		this.maxSortable=1;  // how many columns can be sorted at once.
		this.minRows=0;
		this.defaultDateFormat = "%D";
		this.isInitialized=false;
		this.alternateRows=false;

		this.columns=[];
		this.sortInformation=[{
			index:0,
			direction:0
		}];

		// CSS definitions
		this.headClass="";
		this.tbodyClass="";
		this.headerClass="";
		this.headerUpClass="selectedUp";
		this.headerDownClass="selectedDown";
		this.rowClass="";
		this.rowAlternateClass="alt";
		this.rowSelectedClass="selected";
		this.columnSelected="sorted-column";
	},
{
	//	dojo widget properties
	isContainer: false,
	templatePath: null,
	templateCssPath: null,

	//	methods.
	getTypeFromString: function(/* string */s){
		//	summary
		//	Gets a function based on the passed string.
		var parts = s.split("."), i = 0, obj = dj_global; 
		do{ 
			obj = obj[parts[i++]]; 
		} while (i < parts.length && obj); 
		return (obj != dj_global) ? obj : null;	//	function
	},

	//	custom data access.
	getByRow: function(/*HTMLTableRow*/row){
		//	summary
		//	Returns the data object based on the passed row.
		return this.store.getByKey(dojo.html.getAttribute(row, "value"));	//	object
	},
	getDataByRow: function(/*HTMLTableRow*/row){
		//	summary
		//	Returns the source data object based on the passed row.
		return this.store.getDataByKey(dojo.html.getAttribute(row, "value")); // object
	},

	getRow: function(/* Object */ obj){
		//	summary
		//	Finds the row in the table based on the passed data object.
		var rows = this.domNode.tBodies[0].rows;
		for(var i=0; i<rows.length; i++){
			if(this.store.getDataByKey(dojo.html.getAttribute(rows[i], "value")) == obj){
				return rows[i];	//	HTMLTableRow
			}
		}
		return null;	//	HTMLTableRow
	},
	getColumnIndex: function(/* string */fieldPath){
		//	summary
		//	Returns index of the column that represents the passed field path.
		for(var i=0; i<this.columns.length; i++){
			if(this.columns[i].getField() == fieldPath){
				return i;	//	integer
			}
		}
		return -1;	//	integer
	},

	getSelectedData: function(){
		//	summary
		//	returns all objects that are selected.
		var data=this.store.get();
		var a=[];
		for(var i=0; i<data.length; i++){
			if(data[i].isSelected){
				a.push(data[i].src);
			}
		}
		if(this.multiple){
			return a;		//	array
		} else {
			return a[0];	//	object
		}
	},
	
	isSelected: function(/* object */obj){
		//	summary
		//	Returns whether the passed object is currently selected.
		var data = this.store.get();
		for(var i=0; i<data.length; i++){
			if(data[i].src == obj){
				return true;	//	boolean
			}
		}
		return false;	//	boolean
	},
	isValueSelected: function(/* string */val){
		//	summary
		//	Returns the object represented by key "val" is selected.
		var v = this.store.getByKey(val);
		if(v){
			return v.isSelected;	//	boolean
		}
		return false;	//	boolean
	},
	isIndexSelected: function(/* number */idx){
		//	summary
		//	Returns the object represented by integer "idx" is selected.
		var v = this.store.getByIndex(idx);
		if(v){
			return v.isSelected;	//	boolean
		}
		return false;	//	boolean
	},
	isRowSelected: function(/* HTMLTableRow */row){
		//	summary
		//	Returns if the passed row is selected.
		var v = this.getByRow(row);
		if(v){
			return v.isSelected;	//	boolean
		}
		return false;	//	boolean
	},

	reset: function(){
		//	summary
		//	Resets the widget to its initial internal state.
		this.store.clearData();
		this.columns = [];
		this.sortInformation = [ {index:0, direction:0} ];
		this.resetSelections();
		this.isInitialized = false;
		this.onReset();
	},
	resetSelections: function(){
		//	summary
		//	Unselects all data objects.
		this.store.forEach(function(element){
			element.isSelected = false;
		});
	},
	onReset:function(){ 
		//	summary
		//	Stub for onReset event.
	},

	//	selection and toggle functions
	select: function(/*object*/ obj){
		//	summary
		//	selects the passed object.
		var data = this.store.get();
		for(var i=0; i<data.length; i++){
			if(data[i].src == obj){
				data[i].isSelected = true;
				break;
			}
		}
		this.onDataSelect(obj);
	},
	selectByValue: function(/*string*/ val){
		//	summary
		//	selects the object represented by key "val".
		this.select(this.store.getDataByKey(val));
	},
	selectByIndex: function(/*number*/ idx){
		//	summary
		//	selects the object represented at index "idx".
		this.select(this.store.getDataByIndex(idx));
	},
	selectByRow: function(/*HTMLTableRow*/ row){
		//	summary
		//	selects the object represented by HTMLTableRow row.
		this.select(this.getDataByRow(row));
	},
	selectAll: function(){
		//	summary
		//	selects all objects.
		this.store.forEach(function(element){
			element.isSelected = true;
		});
	},
	onDataSelect: function(/* object */obj){ 
		//	summary
		//	Stub for onDataSelect event.
	},

	toggleSelection: function(/*object*/obj){
		//	summary
		//	Flips the selection state of passed obj.
		var data = this.store.get();
		for(var i=0; i<data.length; i++){
			if(data[i].src == obj){
				data[i].isSelected = !data[i].isSelected;
				break;
			}
		}
		this.onDataToggle(obj);
	},
	toggleSelectionByValue: function(/*string*/val){
		//	summary
		//	Flips the selection state of object represented by val.
		this.toggleSelection(this.store.getDataByKey(val));
	},
	toggleSelectionByIndex: function(/*number*/idx){
		//	summary
		//	Flips the selection state of object at index idx.
		this.toggleSelection(this.store.getDataByIndex(idx));
	},
	toggleSelectionByRow: function(/*HTMLTableRow*/row){
		//	summary
		//	Flips the selection state of object represented by row.
		this.toggleSelection(this.getDataByRow(row));
	},
	toggleAll: function(){
		//	summary
		//	Flips the selection state of all objects.
		this.store.forEach(function(element){
			element.isSelected = !element.isSelected;
		});
	},
	onDataToggle: function(/* object */obj){ 
		//	summary
		//	Stub for onDataToggle event.
	},

	//	parsing functions, from HTML to metadata/SimpleStore
	_meta:{
		field:null,
		format:null,
		filterer:null,
		noSort:false,
		sortType:"String",
		dataType:String,
		sortFunction:null,
		filterFunction:null,
		label:null,
		align:"left",
		valign:"middle",
		getField:function(){ 
			return this.field || this.label; 
		},
		getType:function(){ 
			return this.dataType; 
		}
	},
	createMetaData: function(/* object */obj){
		//	summary
		//	Take a JSON-type structure and make it into a ducktyped metadata object.
		for(var p in this._meta){
			//	rudimentary mixin
			if(!obj[p]){
				obj[p] = this._meta[p];
			}
		}
		if(!obj.label){
			obj.label=obj.field;
		}
		if(!obj.filterFunction){
			obj.filterFunction=this._defaultFilter;
		}
		return obj;	//	object
	},
	parseMetadata: function(/* HTMLTableHead */head){
		//	summary
		//	Parses the passed HTMLTableHead element to create meta data.
		this.columns=[];
		this.sortInformation=[];
		var row = head.getElementsByTagName("tr")[0];
		var cells = row.getElementsByTagName("td");
		if (cells.length == 0){
			cells = row.getElementsByTagName("th");
		}
		for(var i=0; i<cells.length; i++){
			var o = this.createMetaData({ });
			
			//	presentation attributes
			if(dojo.html.hasAttribute(cells[i], "align")){
				o.align = dojo.html.getAttribute(cells[i],"align");
			}
			if(dojo.html.hasAttribute(cells[i], "valign")){
				o.valign = dojo.html.getAttribute(cells[i],"valign");
			}
			if(dojo.html.hasAttribute(cells[i], "nosort")){
				o.noSort = (dojo.html.getAttribute(cells[i],"nosort")=="true");
			}
			if(dojo.html.hasAttribute(cells[i], "sortusing")){
				var trans = dojo.html.getAttribute(cells[i],"sortusing");
				var f = this.getTypeFromString(trans);
				if (f != null && f != window && typeof(f)=="function"){
					o.sortFunction=f;
				}
			}
			o.label = dojo.html.renderedTextContent(cells[i]);
			if(dojo.html.hasAttribute(cells[i], "field")){
				o.field=dojo.html.getAttribute(cells[i],"field");
			} else if(o.label.length > 0){
				o.field=o.label;
			} else {
				o.field = "field" + i;
			}
			if(dojo.html.hasAttribute(cells[i], "format")){
				o.format=dojo.html.getAttribute(cells[i],"format");
			}
			if(dojo.html.hasAttribute(cells[i], "dataType")){
				var sortType = dojo.html.getAttribute(cells[i],"dataType");
				if(sortType.toLowerCase()=="html" || sortType.toLowerCase()=="markup"){
					o.sortType = "__markup__";	//	always convert to "__markup__"
				}else{
					var type = this.getTypeFromString(sortType);
					if(type){
						o.sortType = sortType;
						o.dataType = type;
					}
				}
			}

			//	TODO: set up filtering mechanisms here.
			if(dojo.html.hasAttribute(cells[i], "filterusing")){
				var trans = dojo.html.getAttribute(cells[i],"filterusing");
				var f = this.getTypeFromString(trans);
				if (f != null && f != window && typeof(f)=="function"){
					o.filterFunction=f;
				}
			}
			
			this.columns.push(o);

			//	check to see if there's a default sort, and set the properties necessary
			if(dojo.html.hasAttribute(cells[i], "sort")){
				var info = {
					index:i,
					direction:0
				};
				var dir = dojo.html.getAttribute(cells[i], "sort");
				if(!isNaN(parseInt(dir))){
					dir = parseInt(dir);
					info.direction = (dir != 0) ? 1 : 0;
				}else{
					info.direction = (dir.toLowerCase() == "desc") ? 1 : 0;
				}
				this.sortInformation.push(info);
			}
		}
		if(this.sortInformation.length == 0){
			this.sortInformation.push({
				index:0,
				direction:0
			});
		} else if (this.sortInformation.length > this.maxSortable){
			this.sortInformation.length = this.maxSortable;
		}
	},
	parseData: function(/* HTMLTableBody */body){
		//	summary
		//	Parse HTML data into native JSON structure for the store.
		if(body.rows.length == 0 && this.columns.length == 0){
			return;	//	there's no data, ignore me.
		}

		//	create a data constructor based on what we've got for the fields.
		var self=this;
		this["__selected__"] = [];
		var arr = this.store.getFromHtml(this.columns, body, function(obj, row){
			obj[self.valueField] = dojo.html.getAttribute(row, "value");
			if(dojo.html.getAttribute(row, "selected")=="true"){
				self["__selected__"].push(obj);
			}
		});
		this.store.setData(arr);
		for(var i=0; i<this["__selected__"].length; i++){
			this.select(this["__selected__"][i]);
		}
		this.renderSelections();

		delete this["__selected__"];

		//	say that we are already initialized so that we don't kill anything
		this.isInitialized=true;
	},

	//	standard events
	onSelect: function(/* HTMLEvent */e){
		//	summary
		//	Handles the onclick event of any element.
		var row = dojo.html.getParentByType(e.target,"tr");
		if(dojo.html.hasAttribute(row,"emptyRow")){
			return;
		}
		var body = dojo.html.getParentByType(row,"tbody");
		if(this.multiple){
			if(e.shiftKey){
				var startRow;
				var rows=body.rows;
				for(var i=0;i<rows.length;i++){
					if(rows[i]==row){
						break;
					}
					if(this.isRowSelected(rows[i])){
						startRow=rows[i];
					}
				}
				if(!startRow){
					startRow = row;
					for(; i<rows.length; i++){
						if(this.isRowSelected(rows[i])){
							row = rows[i];
							break;
						}
					}
				}
				this.resetSelections();
				if(startRow == row){
					this.toggleSelectionByRow(row);
				} else {
					var doSelect = false;
					for(var i=0; i<rows.length; i++){
						if(rows[i] == startRow){
							doSelect=true;
						}
						if(doSelect){
							this.selectByRow(rows[i]);
						}
						if(rows[i] == row){
							doSelect = false;
						}
					}
				}
			} else {
				this.toggleSelectionByRow(row);
			}
		} else {
			this.resetSelections();
			this.toggleSelectionByRow(row);
		}
		this.renderSelections();
	},
	onSort: function(/* HTMLEvent */e){
		//	summary
		//	Sort the table based on the column selected.
		var oldIndex=this.sortIndex;
		var oldDirection=this.sortDirection;
		
		var source=e.target;
		var row=dojo.html.getParentByType(source,"tr");
		var cellTag="td";
		if(row.getElementsByTagName(cellTag).length==0){
			cellTag="th";
		}

		var headers=row.getElementsByTagName(cellTag);
		var header=dojo.html.getParentByType(source,cellTag);
		
		for(var i=0; i<headers.length; i++){
			dojo.html.setClass(headers[i], this.headerClass);
			if(headers[i]==header){
				if(this.sortInformation[0].index != i){
					this.sortInformation.unshift({ 
						index:i, 
						direction:0
					});
				} else {
					this.sortInformation[0] = {
						index:i,
						direction:(~this.sortInformation[0].direction)&1
					};
				}
			}
		}

		this.sortInformation.length = Math.min(this.sortInformation.length, this.maxSortable);
		for(var i=0; i<this.sortInformation.length; i++){
			var idx=this.sortInformation[i].index;
			var dir=(~this.sortInformation[i].direction)&1;
			dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass);
		}
		this.render();
	},
	onFilter: function(){
		//	summary
		//	show or hide rows based on the parameters of the passed filter.
	},

	//	Filtering methods
	_defaultFilter: function(/* Object */obj){
		//	summary
		//	Always return true as the result of the default filter.
		return true;
	},
	setFilter: function(/* string */field, /* function */fn){
		//	summary
		//	set a filtering function on the passed field.
		for(var i=0; i<this.columns.length; i++){
			if(this.columns[i].getField() == field){
				this.columns[i].filterFunction=fn;
				break;
			}
		}
		this.applyFilters();
	},
	setFilterByIndex: function(/* number */idx, /* function */fn){
		//	summary
		//	set a filtering function on the passed column index.
		this.columns[idx].filterFunction=fn;
		this.applyFilters();
	},
	clearFilter: function(/* string */field){
		//	summary
		//	clear a filtering function on the passed field.
		for(var i=0; i<this.columns.length; i++){
			if(this.columns[i].getField() == field){
				this.columns[i].filterFunction=this._defaultFilter;
				break;
			}
		}
		this.applyFilters();
	}, 
	clearFilterByIndex: function(/* number */idx){
		//	summary
		//	clear a filtering function on the passed column index.
		this.columns[idx].filterFunction=this._defaultFilter;
		this.applyFilters();
	}, 
	clearFilters: function(){
		//	summary
		//	clears all filters.
		for(var i=0; i<this.columns.length; i++){
			this.columns[i].filterFunction=this._defaultFilter;
		}
		//	we'll do the clear manually, it will be faster.
		var rows=this.domNode.tBodies[0].rows;
		for(var i=0; i<rows.length; i++){
			rows[i].style.display="";
			if(this.alternateRows){
				dojo.html[((i % 2 == 1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass);
			}
		}
		this.onFilter();
	},
	applyFilters: function(){
		//	summary
		//	apply all filters to the table.
		var alt=0;
		var rows=this.domNode.tBodies[0].rows;
		for(var i=0; i<rows.length; i++){
			var b=true;
			var row=rows[i];
			for(var j=0; j<this.columns.length; j++){
				var value = this.store.getField(this.getDataByRow(row), this.columns[j].getField());
				if(this.columns[j].getType() == Date && value != null && !value.getYear){
					value = new Date(value);
				}
				if(!this.columns[j].filterFunction(value)){
					b=false;
					break;
				}
			}
			row.style.display=(b?"":"none");
			if(b && this.alternateRows){
				dojo.html[((alt++ % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass);
			}
		}
		this.onFilter();
	},

	//	sorting functionality
	createSorter: function(/* array */info){
		//	summary
		//	creates a custom function to be used for sorting.
		var self=this;
		var sortFunctions=[];	//	our function stack.
	
		function createSortFunction(fieldIndex, dir){
			var meta=self.columns[fieldIndex];
			var field=meta.getField();
			return function(rowA, rowB){
				if(dojo.html.hasAttribute(rowA,"emptyRow") || dojo.html.hasAttribute(rowB,"emptyRow")){
					return -1;
				}
				//	TODO: check for markup and compare by rendered text.
				var a = self.store.getField(self.getDataByRow(rowA), field);
				var b = self.store.getField(self.getDataByRow(rowB), field);
				var ret = 0;
				if(a > b) ret = 1;
				if(a < b) ret = -1;
				return dir * ret;
			}
		}

		var current=0;
		var max = Math.min(info.length, this.maxSortable, this.columns.length);
		while(current < max){
			var direction = (info[current].direction == 0) ? 1 : -1;
			sortFunctions.push(
				createSortFunction(info[current].index, direction)
			);
			current++;
		}

		return function(rowA, rowB){
			var idx=0;
			while(idx < sortFunctions.length){
				var ret = sortFunctions[idx++](rowA, rowB);
				if(ret != 0) return ret;
			}
			//	if we got here then we must be equal.
			return 0; 	
		};	//	function
	},

	//	rendering
	createRow: function(/* object */obj){
		//	summary
		//	Create an HTML row based on the passed object
		var row=document.createElement("tr");
		dojo.html.disableSelection(row);
		if(obj.key != null){
			row.setAttribute("value", obj.key);
		}
		for(var j=0; j<this.columns.length; j++){
			var cell=document.createElement("td");
			cell.setAttribute("align", this.columns[j].align);
			cell.setAttribute("valign", this.columns[j].valign);
			dojo.html.disableSelection(cell);
			var val = this.store.getField(obj.src, this.columns[j].getField());
			if(typeof(val)=="undefined"){
				val="";
			}
			this.fillCell(cell, this.columns[j], val);
			row.appendChild(cell);
		}
		return row;	//	HTMLTableRow
	},
	fillCell: function(/* HTMLTableCell */cell, /* object */meta, /* object */val){
		//	summary
		//	Fill the passed cell with value, based on the passed meta object.
		if(meta.sortType=="__markup__"){
			cell.innerHTML=val;
		} else {
			if(meta.getType()==Date) {
				val=new Date(val);
				if(!isNaN(val)){
					var format = this.defaultDateFormat;
					if(meta.format){
						format = meta.format;
					}
					cell.innerHTML = dojo.date.strftime(val, format);
				} else {
					cell.innerHTML = val;
				}
			} else if ("Number number int Integer float Float".indexOf(meta.getType())>-1){
				//	TODO: number formatting
				if(val.length == 0){
					val="0";
				}
				var n = parseFloat(val, 10) + "";
				//	TODO: numeric formatting + rounding :)
				if(n.indexOf(".")>-1){
					n = dojo.math.round(parseFloat(val,10),2);
				}
				cell.innerHTML = n;
			}else{
				cell.innerHTML = val;
			}
		}
	},
	prefill: function(){
		//	summary
		//	if there's no data in the table, then prefill it with this.minRows.
		this.isInitialized = false;
		var body = this.domNode.tBodies[0];
		while (body.childNodes.length > 0){
			body.removeChild(body.childNodes[0]);
		}
		
		if(this.minRows>0){
			for(var i=0; i < this.minRows; i++){
				var row = document.createElement("tr");
				if(this.alternateRows){
					dojo.html[((i % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass);
				}
				row.setAttribute("emptyRow","true");
				for(var j=0; j<this.columns.length; j++){
					var cell = document.createElement("td");
					cell.innerHTML = "&nbsp;";
					row.appendChild(cell);
				}
				body.appendChild(row);
			}
		}
	},
	init: function(){
		//	summary
		//	initializes the table of data
		this.isInitialized=false;

		//	if there is no thead, create it now.
		var head=this.domNode.getElementsByTagName("thead")[0];
		if(head.getElementsByTagName("tr").length == 0){
			//	render the column code.
			var row=document.createElement("tr");
			for(var i=0; i<this.columns.length; i++){
				var cell=document.createElement("td");
				cell.setAttribute("align", this.columns[i].align);
				cell.setAttribute("valign", this.columns[i].valign);
				dojo.html.disableSelection(cell);
				cell.innerHTML=this.columns[i].label;
				row.appendChild(cell);

				//	attach the events.
				if(!this.columns[i].noSort){
					dojo.event.connect(cell, "onclick", this, "onSort");
				}
			}
			dojo.html.prependChild(row, head);
		}
		
		if(this.store.get().length == 0){
			return false;
		}

		var idx=this.domNode.tBodies[0].rows.length;
		if(!idx || idx==0 || this.domNode.tBodies[0].rows[0].getAttribute("emptyRow")=="true"){
			idx = 0;
			var body = this.domNode.tBodies[0];
			while(body.childNodes.length>0){
				body.removeChild(body.childNodes[0]);
			}

			var data = this.store.get();
			for(var i=0; i<data.length; i++){
				var row = this.createRow(data[i]);
				dojo.event.connect(row, "onclick", this, "onSelect");
				body.appendChild(row);
				idx++;
			}
		}

		//	add empty rows
		if(this.minRows > 0 && idx < this.minRows){
			idx = this.minRows - idx;
			for(var i=0; i<idx; i++){
				row=document.createElement("tr");
				row.setAttribute("emptyRow","true");
				for(var j=0; j<this.columns.length; j++){
					cell=document.createElement("td");
					cell.innerHTML="&nbsp;";
					row.appendChild(cell);
				}
				body.appendChild(row);
			}
		}

		//	last but not least, show any columns that have sorting already on them.
		var row=this.domNode.getElementsByTagName("thead")[0].rows[0];
		var cellTag="td";
		if(row.getElementsByTagName(cellTag).length==0) cellTag="th";
		var headers=row.getElementsByTagName(cellTag);
		for(var i=0; i<headers.length; i++){
			dojo.html.setClass(headers[i], this.headerClass);
		}
		for(var i=0; i<this.sortInformation.length; i++){
			var idx=this.sortInformation[i].index;
			var dir=(~this.sortInformation[i].direction)&1;
			dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass);
		}

		this.isInitialized=true;
		return this.isInitialized;
	},
	render: function(){
		//	summary
		//	Renders the actual table data.

	/*	The method that should be called once underlying changes
	 *	are made, including sorting, filtering, data changes.
	 *	Rendering the selections themselves are a different method,
	 *	which render() will call as the last step.
	 ****************************************************************/
		if(!this.isInitialized){
			var b = this.init();
			if(!b){
				this.prefill();
				return;
			}
		}
		
		//	do the sort
		var rows=[];
		var body=this.domNode.tBodies[0];
		var emptyRowIdx=-1;
		for(var i=0; i<body.rows.length; i++){
			rows.push(body.rows[i]);
		}

		//	build the sorting function, and do the sorting.
		var sortFunction = this.createSorter(this.sortInformation);
		if(sortFunction){
			rows.sort(sortFunction);
		}

		//	append the rows without killing them, this should help with the HTML problems.
		for(var i=0; i<rows.length; i++){
			if(this.alternateRows){
				dojo.html[((i%2==1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass);
			}
			dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass);
			body.appendChild(rows[i]);
		}
	},
	renderSelections: function(){
		//	summary
		//	Render all selected objects using CSS.
		var body=this.domNode.tBodies[0];
		for(var i=0; i<body.rows.length; i++){
			dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass);
		}
	},

	//	widget lifetime handlers
	initialize: function(){ 
		//	summary
		//	Initializes the widget.
		var self=this;
		//	connect up binding listeners here.
		dojo.event.connect(this.store, "onSetData", function(){
			self.store.forEach(function(element){
				element.isSelected = false;
			});
			self.isInitialized=false;
			var body = self.domNode.tBodies[0];
			if(body){
				while(body.childNodes.length>0){
					body.removeChild(body.childNodes[0]);
				}
			}
			self.render();
		});
		dojo.event.connect(this.store, "onClearData", function(){
			self.render();
		});
		dojo.event.connect(this.store, "onAddData", function(addedObject){
			var row=self.createRow(addedObject);
			dojo.event.connect(row, "onclick", self, "onSelect");
			self.domNode.tBodies[0].appendChild(row);
			self.render();
		});
		dojo.event.connect(this.store, "onAddDataRange", function(arr){
			for(var i=0; i<arr.length; i++){
				arr[i].isSelected=false;
				var row=self.createRow(arr[i]);
				dojo.event.connect(row, "onclick", self, "onSelect");
				self.domNode.tBodies[0].appendChild(row);
			};
			self.render();
		});
		dojo.event.connect(this.store, "onRemoveData", function(removedObject){
			var rows = self.domNode.tBodies[0].rows;
			for(var i=0; i<rows.length; i++){
				if(self.getDataByRow(rows[i]) == removedObject.src){
					rows[i].parentNode.removeChild(rows[i]);
					break;
				}
			}
			self.render();
		});
		dojo.event.connect(this.store, "onUpdateField", function(obj, fieldPath, val){
			var row = self.getRow(obj);
			var idx = self.getColumnIndex(fieldPath);
			if(row && row.cells[idx] && self.columns[idx]){
				self.fillCell(row.cells[idx], self.columns[idx], val);
			}
		});
	},
	postCreate: function(){
		//	summary
		//	finish widget initialization.
		this.store.keyField = this.valueField;

		if(this.domNode){
			//	start by making sure domNode is a table element;
			if(this.domNode.nodeName.toLowerCase() != "table"){
			}

			//	see if there is columns set up already
			if(this.domNode.getElementsByTagName("thead")[0]){
				var head=this.domNode.getElementsByTagName("thead")[0];
				if(this.headClass.length > 0){
					head.className = this.headClass;
				}
				dojo.html.disableSelection(this.domNode);
				this.parseMetadata(head);

				var header="td";
				if(head.getElementsByTagName(header).length==0){
					header="th";
				}
				var headers = head.getElementsByTagName(header);
				for(var i=0; i<headers.length; i++){
					if(!this.columns[i].noSort){
						dojo.event.connect(headers[i], "onclick", this, "onSort");
					}
				}
			} else {
				this.domNode.appendChild(document.createElement("thead"));
			}

			// if the table doesn't have a tbody already, add one and grab a reference to it
			if (this.domNode.tBodies.length < 1) {
				var body = document.createElement("tbody");
				this.domNode.appendChild(body);
			} else {
				var body = this.domNode.tBodies[0];
			}

			if (this.tbodyClass.length > 0){
				body.className = this.tbodyClass;
			}
			this.parseData(body);
		}
	}
});

__CPAN_FILE__ src/widget/Manager.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Manager");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.func");
dojo.require("dojo.event.*");

// Manager class
dojo.widget.manager = new function(){
	this.widgets = [];
	this.widgetIds = [];
	
	// map of widgetId-->widget for widgets without parents (top level widgets)
	this.topWidgets = {};

	var widgetTypeCtr = {};
	var renderPrefixCache = [];

	this.getUniqueId = function (widgetType) {
		var widgetId;
		do{
			widgetId = widgetType + "_" + (widgetTypeCtr[widgetType] != undefined ?
			++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0);
		}while(this.getWidgetById(widgetId));
		return widgetId;
	}

	this.add = function(widget){
		//dojo.profile.start("dojo.widget.manager.add");
		this.widgets.push(widget);
		// Opera9 uses ID (caps)
		if(!widget.extraArgs["id"]){
			widget.extraArgs["id"] = widget.extraArgs["ID"];
		}
		// FIXME: the rest of this method is very slow!
		if(widget.widgetId == ""){
			if(widget["id"]){
				widget.widgetId = widget["id"];
			}else if(widget.extraArgs["id"]){
				widget.widgetId = widget.extraArgs["id"];
			}else{
				widget.widgetId = this.getUniqueId(widget.widgetType);
			}
		}
		if(this.widgetIds[widget.widgetId]){
			dojo.debug("widget ID collision on ID: "+widget.widgetId);
		}
		this.widgetIds[widget.widgetId] = widget;
		// Widget.destroy already calls removeById(), so we don't need to
		// connect() it here
		//dojo.profile.end("dojo.widget.manager.add");
	}

	this.destroyAll = function(){
		for(var x=this.widgets.length-1; x>=0; x--){
			try{
				// this.widgets[x].destroyChildren();
				this.widgets[x].destroy(true);
				delete this.widgets[x];
			}catch(e){ }
		}
	}

	// FIXME: we should never allow removal of the root widget until all others
	// are removed!
	this.remove = function(widgetIndex){
		if(dojo.lang.isNumber(widgetIndex)){
			var tw = this.widgets[widgetIndex].widgetId;
			delete this.widgetIds[tw];
			this.widgets.splice(widgetIndex, 1);
		}else{
			this.removeById(widgetIndex);
		}
	}
	
	// FIXME: suboptimal performance
	this.removeById = function(id) {
		if(!dojo.lang.isString(id)){
			id = id["widgetId"];
			if(!id){ dojo.debug("invalid widget or id passed to removeById"); return; }
		}
		for (var i=0; i<this.widgets.length; i++){
			if(this.widgets[i].widgetId == id){
				this.remove(i);
				break;
			}
		}
	}

	this.getWidgetById = function(id){
		if(dojo.lang.isString(id)){
			return this.widgetIds[id];
		}
		return id;
	}

	this.getWidgetsByType = function(type){
		var lt = type.toLowerCase();
		var getType = (type.indexOf(":") < 0 ? 
			function(x) { return x.widgetType.toLowerCase(); } :
			function(x) { return x.getNamespacedType(); }
		);
		var ret = [];
		dojo.lang.forEach(this.widgets, function(x){
			if(getType(x) == lt){ret.push(x);}
		});
		return ret;
	}

	this.getWidgetsByFilter = function(unaryFunc, onlyOne){
		var ret = [];
		dojo.lang.every(this.widgets, function(x){
			if(unaryFunc(x)){
				ret.push(x);
				if(onlyOne){return false;}
			}
			return true;
		});
		return (onlyOne ? ret[0] : ret);
	}

	this.getAllWidgets = function() {
		return this.widgets.concat();
	}

	//	added, trt 2006-01-20
	this.getWidgetByNode = function(/* DOMNode */ node){
		var w=this.getAllWidgets();
		node = dojo.byId(node);
		for(var i=0; i<w.length; i++){
			if(w[i].domNode==node){
				return w[i];
			}
		}
		return null;
	}

	// shortcuts, baby
	this.byId = this.getWidgetById;
	this.byType = this.getWidgetsByType;
	this.byFilter = this.getWidgetsByFilter;
	this.byNode = this.getWidgetByNode;

	// map of previousally discovered implementation names to constructors
	var knownWidgetImplementations = {};

	// support manually registered widget packages
	var widgetPackages = ["dojo.widget"];
	for (var i=0; i<widgetPackages.length; i++) {
		// convenience for checking if a package exists (reverse lookup)
		widgetPackages[widgetPackages[i]] = true;
	}

	this.registerWidgetPackage = function(pname) {
		if(!widgetPackages[pname]){
			widgetPackages[pname] = true;
			widgetPackages.push(pname);
		}
	}
	
	this.getWidgetPackageList = function() {
		return dojo.lang.map(widgetPackages, function(elt) { return(elt!==true ? elt : undefined); });
	}
	
	this.getImplementation = function(widgetName, ctorObject, mixins, ns){
		// try and find a name for the widget
		var impl = this.getImplementationName(widgetName, ns);
		if(impl){ 
			// var tic = new Date();
			var ret = ctorObject ? new impl(ctorObject) : new impl();
			// dojo.debug(new Date() - tic);
			return ret;
		}
	}

	function buildPrefixCache() {
		for(var renderer in dojo.render){
			if(dojo.render[renderer]["capable"] === true){
				var prefixes = dojo.render[renderer].prefixes;
				for(var i=0; i<prefixes.length; i++){
					renderPrefixCache.push(prefixes[i].toLowerCase());
				}
			}
		}
		// make sure we don't HAVE to prefix widget implementation names
		// with anything to get them to render
		//renderPrefixCache.push("");
		// empty prefix is included automatically
	}
	
	var findImplementationInModule = function(lowerCaseWidgetName, module){
		if(!module){return null;}
		for(var i=0, l=renderPrefixCache.length, widgetModule; i<=l; i++){
			widgetModule = (i<l ? module[renderPrefixCache[i]] : module);
			if(!widgetModule){continue;}
			for(var name in widgetModule){
				if(name.toLowerCase() == lowerCaseWidgetName){
					return widgetModule[name];
				}
			}
		}
		return null;
	}

	var findImplementation = function(lowerCaseWidgetName, moduleName){
		// locate registered widget module
		var module = dojo.evalObjPath(moduleName, false);
		// locate a widget implementation in the registered module for our current rendering environment
		return (module ? findImplementationInModule(lowerCaseWidgetName, module) : null);
	}

	this.getImplementationName = function(widgetName, ns){
		/*
		 * Locate an implementation (constructor) for 'widgetName' in namespace 'ns' 
		 * widgetNames are case INSENSITIVE
		 * 
		 * 1. Return value from implementation cache, if available, for quick turnaround.
		 * 2. Locate a namespace registration for 'ns'
		 * 3. If no namespace found, register the conventional one (ns.widget)
		 * 4. Allow the namespace resolver (if any) to load a module for this widget.
		 * 5. Permute the widget name and capable rendering prefixes to locate, cache, and return 
		 *    an appropriate widget implementation.
		 * 6. If no implementation is found, attempt to load the namespace manifest,
		 *    and then look again for an implementation to cache and return.
		 * 7. Use the deprecated widgetPackages registration system to attempt to locate the widget
		 * 8. Fail
		 */
		var lowerCaseWidgetName = widgetName.toLowerCase();

		// default to dojo namespace
		ns=ns||"dojo";
		// use cache if available
		var imps = knownWidgetImplementations[ns] || (knownWidgetImplementations[ns]={});
		//if(!knownWidgetImplementations[ns]){knownWidgetImplementations[ns]={};}
		var impl = imps[lowerCaseWidgetName];
		if(impl){
			return impl;
		}
		
		// (one time) store a list of the render prefixes we are capable of rendering
		if(!renderPrefixCache.length){
			buildPrefixCache();
		}

		// lookup namespace
		var nsObj = dojo.ns.get(ns);
		if(!nsObj){
			// default to <ns>.widget by convention
			dojo.ns.register(ns, ns + '.widget');
			nsObj = dojo.ns.get(ns);
		}
		
		// allow the namespace to resolve the widget module
		if(nsObj){nsObj.resolve(widgetName);}

		// locate a widget implementation in the registered module for our current rendering environment
		impl = findImplementation(lowerCaseWidgetName, nsObj.module);
		if(impl){return(imps[lowerCaseWidgetName] = impl)};

		// try to load a manifest to resolve this implemenation
		nsObj = dojo.ns.require(ns);
		if((nsObj)&&(nsObj.resolver)){
			nsObj.resolve(widgetName);
			impl = findImplementation(lowerCaseWidgetName, nsObj.module);
			if(impl){return(imps[lowerCaseWidgetName] = impl)};
		}
	
		// this is an error condition under new rules
		dojo.deprecated('dojo.widget.Manager.getImplementationName', 
			'Could not locate widget implementation for "' + widgetName + '" in "' + nsObj.module + '" registered to namespace "' + nsObj.name + '". '										
			+ "Developers must specify correct namespaces for all non-Dojo widgets", "0.5");

		// backward compat: if the user has not specified any namespace and their widget is not in dojo.widget.*
		// search registered widget packages [sic]
		// note: registerWidgetPackage itself is now deprecated 
		for(var i=0; i<widgetPackages.length; i++){
			impl = findImplementation(lowerCaseWidgetName, widgetPackages[i]);
			if(impl){return(imps[lowerCaseWidgetName] = impl)};
		}
		
		throw new Error('Could not locate widget implementation for "' + widgetName + '" in "' + nsObj.module + '" registered to namespace "' + nsObj.name + '"');
	}

	// FIXME: does it even belong in this module?
	// NOTE: this method is implemented by DomWidget.js since not all
	// hostenv's would have an implementation.
	/*this.getWidgetFromPrimitive = function(baseRenderType){
		dojo.unimplemented("dojo.widget.manager.getWidgetFromPrimitive");
	}

	this.getWidgetFromEvent = function(nativeEvt){
		dojo.unimplemented("dojo.widget.manager.getWidgetFromEvent");
	}*/

	// Catch window resize events and notify top level widgets
	this.resizing=false;
	this.onWindowResized = function(){
		if(this.resizing){
			return;	// duplicate event
		}
		try{
			this.resizing=true;
			for(var id in this.topWidgets){
				var child = this.topWidgets[id];
				if(child.checkSize ){
					child.checkSize();
				}
			}
		}catch(e){
		}finally{
			this.resizing=false;
		}
	}
	if(typeof window != "undefined") {
		dojo.addOnLoad(this, 'onWindowResized');							// initial sizing
		dojo.event.connect(window, 'onresize', this, 'onWindowResized');	// window resize
	}

	// FIXME: what else?
};

(function(){
	var dw = dojo.widget;
	var dwm = dw.manager;
	var h = dojo.lang.curry(dojo.lang, "hitch", dwm);
	var g = function(oldName, newName){
		dw[(newName||oldName)] = h(oldName);
	}
	// copy the methods from the default manager (this) to the widget namespace
	g("add", "addWidget");
	g("destroyAll", "destroyAllWidgets");
	g("remove", "removeWidget");
	g("removeById", "removeWidgetById");
	g("getWidgetById");
	g("getWidgetById", "byId");
	g("getWidgetsByType");
	g("getWidgetsByFilter");
	g("getWidgetsByType", "byType");
	g("getWidgetsByFilter", "byFilter");
	g("getWidgetByNode", "byNode");
	dw.all = function(n){
		var widgets = dwm.getAllWidgets.apply(dwm, arguments);
		if(arguments.length > 0) {
			return widgets[n];
		}
		return widgets;
	}
	g("registerWidgetPackage");
	g("getImplementation", "getWidgetImplementation");
	g("getImplementationName", "getWidgetImplementationName");

	dw.widgets = dwm.widgets;
	dw.widgetIds = dwm.widgetIds;
	dw.root = dwm.root;
})();

__CPAN_FILE__ src/widget/DatePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

	dojo.provide("dojo.widget.DatePicker");
dojo.require("dojo.date.common");
dojo.require("dojo.date.format");
dojo.require("dojo.date.serialize");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.event.*");
dojo.require("dojo.dom");
dojo.require("dojo.html.style");

dojo.widget.defineWidget(
	"dojo.widget.DatePicker",
	dojo.widget.HtmlWidget,
	{	
		/*
		summary: 
	 	              Base class for a stand-alone DatePicker widget 
	 	              which makes it easy to select a date, or switch by month and/or year. 
	 	description: 
	 	              A stand-alone DatePicker widget that makes it  
	 	              easy to select a date, or increment by week, month, and/or year. 
	 	              It is designed to be used on its own, or inside of other widgets to  
	 	              (see dojo.widget.DropdownDatePicker) or other similar combination widgets. 
	 	              
	 	              Dates attributes passed in the `RFC 3339` format:
	 	              http://www.faqs.org/rfcs/rfc3339.html (2005-06-30T08:05:00-07:00)
	 	              so that they are serializable and locale-independent.

	 	 usage: 
	 	              var datePicker = dojo.widget.createWidget("DatePicker", {},   
	 	              dojo.byId("datePickerNode")); 
	 	 
	 	              <div dojoType="DatePicker"></div> 
		*/

		//start attributes
		
		//String|Date
		//	form value property if =='today' will default to todays date
		value: "", 
		//String
		// 	name of the form element
		name: "",
		//Integer
		//	total weeks to display default 
		displayWeeks: 6, 
		//Boolean
		//	if true, weekly size of calendar changes to acomodate the month if false, 42 day format is used
		adjustWeeks: false,
		//String|Date
		//	first available date in the calendar set
		startDate: "1492-10-12",
		//String|Date
		//	last available date in the calendar set
		endDate: "2941-10-12",
		//Integer
		//	adjusts the first day of the week 0==Sunday..6==Saturday
		weekStartsOn: "",
		//String
		//	deprecated use value instead
		storedDate: "",
		//Boolean
		//d	isable all incremental controls, must pick a date in the current display
		staticDisplay: false,
		
		//how to render the names of the days in the header.  see dojo.date.getDayNames
		dayWidth: 'narrow',
		classNames: {
		// summary:
		//              stores a list of class names that may be overriden 
			previous: "previousMonth",
			disabledPrevious: "previousMonthDisabled",
			current: "currentMonth",
			disabledCurrent: "currentMonthDisabled",
			next: "nextMonth",
			disabledNext: "nextMonthDisabled",
			currentDate: "currentDate",
			selectedDate: "selectedItem"
		},
		templatePath:  dojo.uri.dojoUri("src/widget/templates/DatePicker.html"),
		templateCssPath:  dojo.uri.dojoUri("src/widget/templates/DatePicker.css"),

		postMixInProperties: function(){
			// summary: see dojo.widget.DomWidget

			dojo.widget.DatePicker.superclass.postMixInProperties.apply(this, arguments);
			if(this.storedDate){
				dojo.deprecated("dojo.widget.DatePicker", "use 'value' instead of 'storedDate'", "0.5");
				this.value=this.storedDate;
			}
			this.startDate = dojo.date.fromRfc3339(this.startDate);
			this.endDate = dojo.date.fromRfc3339(this.endDate);
			this.startDate.setHours(0,0,0,0); //adjust startDate to be exactly midnight
			this.endDate.setHours(24,0,0,-1); //adjusting endDate to be a fraction of a second before  midnight
			if(!this.weekStartsOn){
				this.weekStartsOn=dojo.date.getFirstDayOfWeek(this.lang);
			}
			this.today = new Date();
			this.today.setHours(0,0,0,0);
			if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
				this.value = new Date();
			}else if(this.value && (typeof this.value=="string") && (this.value.split("-").length > 2)) {
				this.value = dojo.date.fromRfc3339(this.value);
				this.value.setHours(0,0,0,0);
			}
		},

		fillInTemplate: function(args, frag) {
			// summary: see dojo.widget.DomWidget

			dojo.widget.DatePicker.superclass.fillInTemplate.apply(this, arguments);

			// Copy style info from input node to output node
			var source = this.getFragNodeRef(frag);
			dojo.html.copyStyle(this.domNode, source);

			this.weekTemplate = dojo.dom.removeNode(this.calendarWeekTemplate);
			this._preInitUI(this.value ? this.value : this.today, false, true); //init UI with date selected ONLY if user supplies one

			// Insert localized day names in the template
			var dayLabels = dojo.lang.unnest(dojo.date.getNames('days', this.dayWidth, 'standAlone', this.lang)); //if we dont use unnest, we risk modifying the dayLabels array inside of dojo.date and screwing up other calendars on the page
			if(this.weekStartsOn > 0){
				//adjust dayLabels for different first day of week. ie: Monday or Thursday instead of Sunday
				for(var i=0;i<this.weekStartsOn;i++){
					dayLabels.push(dayLabels.shift());
				}
			}
			var dayLabelNodes = this.dayLabelsRow.getElementsByTagName("td");
 			for(i=0; i<7; i++) {
				dayLabelNodes.item(i).innerHTML = dayLabels[i];
			}

			if(this.value){
				this.setValue(this.value);
			}

		},
		
		getValue: function() {
			// summary: return current date in RFC 3339 format
			return dojo.date.toRfc3339(new Date(this.value),'dateOnly'); /*String*/
		},

		getDate: function() {
			// summary: return current date as a Date object
			return this.value; /*Date*/
		},

		setValue: function(/*Date|String*/rfcDate) {
			//summary: set the current date from RFC 3339 formatted string or a date object, synonymous with setDate
			this.setDate(rfcDate);
		},			

		setDate: function(/*Date|String*/dateObj) {
			//summary: set the current date and update the UI
			if(typeof dateObj=="string"){
				this.value = dojo.date.fromRfc3339(dateObj);
			}else{
				this.value = new Date(dateObj);
			}
			this.value.setHours(0,0,0,0);
			if(this.selectedNode!=null){
				dojo.html.removeClass(this.selectedNode,this.classNames.selectedDate);
			}
			if(this.clickedNode!=null){
				dojo.html.addClass(this.clickedNode,this.classNames.selectedDate);
				this.selectedNode = this.clickedNode;
			}else{
				//only call this if setDate was called by means other than clicking a date
				this._preInitUI(this.value,false,true);
			}
			this.clickedNode=null;
			this.onValueChanged(this.value);
		},

		_preInitUI: function(dateObj,initFirst,initUI) {
			/*
	 	              To get a sense of what month to highlight, we initialize on 
	 	              the first Saturday of each month, since that will be either the first  
	 	              of two or the second of three months being partially displayed, and  
	 	              then work forwards and backwards from that point.
			*/

			//initFirst is to tell _initFirstDay if you want first day of the displayed calendar, or first day of the week for dateObj
			//initUI tells preInitUI to go ahead and run initUI if set to true
			if(dateObj<this.startDate||dateObj>this.endDate){
				dateObj = new Date((dateObj<this.startDate)?this.startDate:this.endDate);
			}
			this.firstDay = this._initFirstDay(dateObj,initFirst);
			this.selectedIsUsed = false;
			this.currentIsUsed = false;
			var nextDate = new Date(this.firstDay);
			var tmpMonth = nextDate.getMonth();
			this.curMonth = new Date(nextDate);
			this.curMonth.setDate(nextDate.getDate()+6); //first saturday gives us the current Month
			this.curMonth.setDate(1);
			if(this.displayWeeks=="" || this.adjustWeeks){
				this.adjustWeeks = true;
				this.displayWeeks = Math.ceil((dojo.date.getDaysInMonth(this.curMonth) + this._getAdjustedDay(this.curMonth))/7);
			}
			var days = this.displayWeeks*7; //init total days to display
			if(dojo.date.diff(this.startDate,this.endDate, dojo.date.dateParts.DAY) < days){
				this.staticDisplay = true;
				if(dojo.date.diff(nextDate,this.endDate, dojo.date.dateParts.DAY) > days){
					this._preInitUI(this.startDate,true,false);
					nextDate = new Date(this.firstDay);
				}
				this.curMonth = new Date(nextDate);
				this.curMonth.setDate(nextDate.getDate()+6);
				this.curMonth.setDate(1);
				var curClass = (nextDate.getMonth() == this.curMonth.getMonth())?'current':'previous';
			}
			if(initUI){
				this._initUI(days);
			}
		},
		_initUI: function(days) {
			dojo.dom.removeChildren(this.calendarDatesContainerNode);
			for(var i=0;i<this.displayWeeks;i++){
				this.calendarDatesContainerNode.appendChild(this.weekTemplate.cloneNode(true));
			}

			var nextDate = new Date(this.firstDay);
			this._setMonthLabel(this.curMonth.getMonth());
			this._setYearLabels(this.curMonth.getFullYear());
			var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
			var calendarRows = this.calendarDatesContainerNode.getElementsByTagName("tr");
			var currentCalendarNode;
			for(i=0;i<days;i++){
				//this is our new UI loop... one loop to rule them all, and in the datepicker bind them
				currentCalendarNode = calendarNodes.item(i);
				currentCalendarNode.innerHTML = nextDate.getDate();
				var curClass = (nextDate.getMonth()<this.curMonth.getMonth())?'previous':(nextDate.getMonth()==this.curMonth.getMonth())?'current':'next';
				var mappedClass = curClass;
				if(this._isDisabledDate(nextDate)){
					var classMap={previous:"disabledPrevious",current:"disabledCurrent",next:"disabledNext"};
					mappedClass=classMap[curClass];
				}
				dojo.html.setClass(currentCalendarNode, this._getDateClassName(nextDate, mappedClass));
				if(dojo.html.hasClass(currentCalendarNode,this.classNames.selectedDate)){
					this.selectedNode = currentCalendarNode;
				}
				nextDate = dojo.date.add(nextDate, dojo.date.dateParts.DAY, 1);
			}
			this.lastDay = dojo.date.add(nextDate,dojo.date.dateParts.DAY,-1);
			this._initControls();
		},
		_initControls: function(){
			var d = this.firstDay;
			var d2 = this.lastDay;
			var decWeek, incWeek, decMonth, incMonth, decYear, incYear;
			decWeek = incWeek = decMonth = incMonth = decYear = incYear = !this.staticDisplay;
			with(dojo.date.dateParts){
				var add = dojo.date.add;
				if(decWeek && add(d,DAY,(-1*(this._getAdjustedDay(d)+1)))<this.startDate){
					decWeek = decMonth = decYear = false;
				}
				if(incWeek && d2>this.endDate){
					incWeek = incMonth = incYear = false;
				}
				if(decMonth && add(d,DAY,-1)<this.startDate){
					decMonth = decYear = false;
				}
				if(incMonth && add(d2,DAY,1)>this.endDate){
					incMonth = incYear = false;
				}
				if(decYear && add(d2,YEAR,-1)<this.startDate){
					decYear = false;
				}
				if(incYear && add(d,YEAR,1)>this.endDate){
					incYear = false;
				}
			}

			function enableControl(node, enabled){
				dojo.html.setVisibility(node, enabled ? '' : 'hidden');
			}
			enableControl(this.decreaseWeekNode,decWeek);
			enableControl(this.increaseWeekNode,incWeek);
			enableControl(this.decreaseMonthNode,decMonth);
			enableControl(this.increaseMonthNode,incMonth);
			enableControl(this.previousYearLabelNode,decYear);
			enableControl(this.nextYearLabelNode,incYear);
		},
		
		_incrementWeek: function(evt) {
			var d = new Date(this.firstDay);
			switch(evt.target) {
				case this.increaseWeekNode.getElementsByTagName("img").item(0): 
				case this.increaseWeekNode:
					var tmpDate = dojo.date.add(d, dojo.date.dateParts.WEEK, 1);
					if(tmpDate < this.endDate){
						d = dojo.date.add(d, dojo.date.dateParts.WEEK, 1);
					}
					break;
				case this.decreaseWeekNode.getElementsByTagName("img").item(0):
				case this.decreaseWeekNode:
					if(d >= this.startDate){
						d = dojo.date.add(d, dojo.date.dateParts.WEEK, -1);
					}
					break;
			}
			this._preInitUI(d,true,true);
		},
	
		_incrementMonth: function(evt) {
			var d = new Date(this.curMonth);
			var tmpDate = new Date(this.firstDay);
			switch(evt.currentTarget) {
				case this.increaseMonthNode.getElementsByTagName("img").item(0):
				case this.increaseMonthNode:
					tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.DAY, this.displayWeeks*7);
					if(tmpDate < this.endDate){
						d = dojo.date.add(d, dojo.date.dateParts.MONTH, 1);
					}else{
						var revertToEndDate = true;
					}
					break;
				case this.decreaseMonthNode.getElementsByTagName("img").item(0):
				case this.decreaseMonthNode:
					if(tmpDate > this.startDate){
						d = dojo.date.add(d, dojo.date.dateParts.MONTH, -1);
					}else{
						var revertToStartDate = true;
					}
					break;
			}
			if(revertToStartDate){
				d = new Date(this.startDate);
			}else if(revertToEndDate){
				d = new Date(this.endDate);
			}
			this._preInitUI(d,false,true);
		},
	
		_incrementYear: function(evt) {
			var year = this.curMonth.getFullYear();
			var tmpDate = new Date(this.firstDay);
			switch(evt.target) {
				case this.nextYearLabelNode:
					tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.YEAR, 1);
					if(tmpDate<this.endDate){
						year++;
					}else{
						var revertToEndDate = true;
					}
					break;
				case this.previousYearLabelNode:
					tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.YEAR, -1);
					if(tmpDate>this.startDate){
						year--;
					}else{
						var revertToStartDate = true;
					}
					break;
			}
			var d;
			if(revertToStartDate){
				d = new Date(this.startDate);
			}else if(revertToEndDate){
				d = new Date(this.endDate);
			}else{
				d = new Date(year, this.curMonth.getMonth(), 1);
			}
			this._preInitUI(d,false,true);
		},
	
		onIncrementWeek: function(/*Event*/evt) {
			// summary: handler for increment week event
			evt.stopPropagation();
			if(!this.staticDisplay){
				this._incrementWeek(evt);
			}
		},
	
		onIncrementMonth: function(/*Event*/evt) {
			// summary: handler for increment month event
			evt.stopPropagation();
			if(!this.staticDisplay){
				this._incrementMonth(evt);
			}
		},
		
		onIncrementYear: function(/*Event*/evt) {
			// summary: handler for increment year event
			evt.stopPropagation();
			if(!this.staticDisplay){
				this._incrementYear(evt);
			}
		},
	
		_setMonthLabel: function(monthIndex) {
			this.monthLabelNode.innerHTML = dojo.date.getNames('months', 'wide', 'standAlone', this.lang)[monthIndex];
		},
		
		_setYearLabels: function(year) {
			var y = year - 1;
			var that = this;
			function f(n){
				that[n+"YearLabelNode"].innerHTML =
					dojo.date.format(new Date(y++, 0), {formatLength:'yearOnly', locale:that.lang});
			}
			f("previous");
			f("current");
			f("next");
		},
		
		_getDateClassName: function(date, monthState) {
			var currentClassName = this.classNames[monthState];
			//we use Number comparisons because 2 dateObjects never seem to equal each other otherwise
			if ((!this.selectedIsUsed && this.value) && (Number(date) == Number(this.value))) {
				currentClassName = this.classNames.selectedDate + " " + currentClassName;
				this.selectedIsUsed = true;
			}
			if((!this.currentIsUsed) && (Number(date) == Number(this.today))) {
				currentClassName = currentClassName + " "  + this.classNames.currentDate;
				this.currentIsUsed = true;
			}
			return currentClassName;
		},
	
		onClick: function(/*Event*/evt) {
			//summary: the click event handler
			dojo.event.browser.stopEvent(evt);
		},

		_handleUiClick: function(/*Event*/evt) {
			var eventTarget = evt.target;
			if(eventTarget.nodeType != dojo.dom.ELEMENT_NODE){eventTarget = eventTarget.parentNode;}
			dojo.event.browser.stopEvent(evt);
			this.selectedIsUsed = this.todayIsUsed = false;
			var month = this.curMonth.getMonth();
			var year = this.curMonth.getFullYear();
			if(dojo.html.hasClass(eventTarget, this.classNames["disabledPrevious"])||dojo.html.hasClass(eventTarget, this.classNames["disabledCurrent"])||dojo.html.hasClass(eventTarget, this.classNames["disabledNext"])){
				return; //this date is disabled... ignore it
			}else if (dojo.html.hasClass(eventTarget, this.classNames["next"])) {
				month = ++month % 12;
				if(month===0){++year;}
			} else if (dojo.html.hasClass(eventTarget, this.classNames["previous"])) {
				month = --month % 12;
				if(month==11){--year;}
			}
			this.clickedNode = eventTarget;
			this.setDate(new Date(year, month, eventTarget.innerHTML));
		},
		
		onValueChanged: function(/*Date*/date) {
			//summary: the set date event handler
		},
		
		_isDisabledDate: function(dateObj){
			if(dateObj<this.startDate||dateObj>this.endDate){
				return true;
			}

			return this.isDisabledDate(dateObj, this.lang);
		},

		isDisabledDate: function(/*Date*/dateObj, /*String?*/locale){
		// summary:
		//	May be overridden to disable certain dates in the calendar e.g. isDisabledDate=dojo.date.isWeekend

			return false; // Boolean
		},

		_initFirstDay: function(/*Date*/dateObj, /*Boolean*/adj){
			//adj: false for first day of month, true for first day of week adjusted by startOfWeek
			var d = new Date(dateObj);
			if(!adj){d.setDate(1);}
			d.setDate(d.getDate()-this._getAdjustedDay(d,this.weekStartsOn));
			d.setHours(0,0,0,0);
			return d; // Date
		},

		_getAdjustedDay: function(/*Date*/dateObj){
			//summary: used to adjust date.getDay() values to the new values based on the current first day of the week value
			var days = [0,1,2,3,4,5,6];
			if(this.weekStartsOn>0){
				for(var i=0;i<this.weekStartsOn;i++){
					days.unshift(days.pop());
				}
			}
			return days[dateObj.getDay()]; // Number: 0..6 where 0=Sunday
		}
	}
);

__CPAN_FILE__ src/widget/RichText.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

 /* -*- tab-width: 4 -*- */
dojo.provide("dojo.widget.RichText");

dojo.require("dojo.widget.*");
dojo.require("dojo.html.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.event.*");
dojo.require("dojo.string.extras");
dojo.require("dojo.uri.Uri");

// used to save content
if(dojo.hostenv.post_load_){
	(function(){
		var savetextarea = dojo.doc().createElement('textarea');
		savetextarea.id = "dojo.widget.RichText.savedContent";
		savetextarea.style = "display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;";
		dojo.body().appendChild(savetextarea);
	})();
}else{
	//dojo.body() is not available before onLoad is fired
	try {
		dojo.doc().write('<textarea id="dojo.widget.RichText.savedContent" ' +
			'style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>');
	}catch(e){ }
}

// summary:
//		dojo.widget.RichText is the core of the WYSIWYG editor in dojo, which
//		provides the basic editing features. It also encapsulates the differences
//		of different js engines for various browsers
dojo.widget.defineWidget(
	"dojo.widget.RichText",
	dojo.widget.HtmlWidget,
	{
		// Boolean:
		//		whether to inherit the parent's width or simply use 100%
		inheritWidth: false,

		// Boolean:
		//		whether focusing into this instance of richtext when page onload
		focusOnLoad: true,

		// String:
		//		If a save name is specified the content is saved and restored if the
		//		editor is not properly closed after editing has started.
		saveName: "",

		// String:
		//		temporary content storage
		_content: "",

		// String:
		//		set height to fix the editor at a specific height, with scrolling
		height: "",

		// String:
		//		The minimum height that the editor should have
		minHeight: "1em",

		// Boolean:
		isClosed: true,
		// Boolean:
		isLoaded: false,

		// Boolean:
		//		whether to use the active-x object in IE
		useActiveX: false,

		// Boolean:
		//		whether to use relative URLs for images - if this is enabled
		//		images will be given absolute URLs when inside the editor but
		//		will be changed to use relative URLs (to the current page) on save
		relativeImageUrls: false,

		// String:
		//		used to concat contents from multiple textareas into a single string
		_SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",

	/* Init
	 *******/

		fillInTemplate: function(){
			// summary: see dojo.widget.DomWidget
			dojo.event.topic.publish("dojo.widget.RichText::init", this);
			this.open();

			// backwards compatibility, needs to be removed
			dojo.event.connect(this, "onKeyPressed", this, "afterKeyPress");
			dojo.event.connect(this, "onKeyPress", this, "keyPress");
			dojo.event.connect(this, "onKeyDown", this, "keyDown");
			dojo.event.connect(this, "onKeyUp", this, "keyUp");

			// add default some key handlers
			var ctrl = this.KEY_CTRL;
			var exec = function (cmd, arg) {
				return arguments.length == 1 ? function () { this.execCommand(cmd); } :
					function () { this.execCommand(cmd, arg); }
			}

			this.addKeyHandler("b", ctrl, exec("bold"));
			this.addKeyHandler("i", ctrl, exec("italic"));
			this.addKeyHandler("u", ctrl, exec("underline"));
			this.addKeyHandler("a", ctrl, exec("selectall"));
			//this.addKeyHandler("k", ctrl, exec("createlink", ""));
			//this.addKeyHandler("K", ctrl, exec("unlink"));
			this.addKeyHandler("s", ctrl, function () { this.save(true); });

			this.addKeyHandler("1", ctrl, exec("formatblock", "h1"));
			this.addKeyHandler("2", ctrl, exec("formatblock", "h2"));
			this.addKeyHandler("3", ctrl, exec("formatblock", "h3"));
			this.addKeyHandler("4", ctrl, exec("formatblock", "h4"));

			this.addKeyHandler("\\", ctrl, exec("insertunorderedlist"));
			if(!dojo.render.html.ie){
				this.addKeyHandler("Z", ctrl, exec("redo"));
			}
		},


		// Array: events which should be connected to the underlying editing area
		events: ["onBlur", "onFocus", "onKeyPress", "onKeyDown", "onKeyUp", "onClick"],

		/**
		 * Transforms the node referenced in this.domNode into a rich text editing
		 * node. This can result in the creation and replacement with an <iframe> if
		 * designMode is used, an <object> and active-x component if inside of IE or
		 * a reguler element if contentEditable is available.
		 */
		open: function (/*DomNode, optional*/element) {
			// summary:
			//		Transforms the node referenced in this.domNode into a rich text editing
			//		node. This can result in the creation and replacement with an <iframe> if
			//		designMode is used, an <object> and active-x component if inside of IE or
			//		a reguler element if contentEditable is available.
			var h = dojo.render.html;
			dojo.event.topic.publish("dojo.widget.RichText::open", this);

			if (!this.isClosed) { this.close(); }
			this._content = "";
			if((arguments.length == 1)&&(element["nodeName"])){ this.domNode = element; } // else unchanged

			if(	(this.domNode["nodeName"])&&
				(this.domNode.nodeName.toLowerCase() == "textarea")){
				this.textarea = this.domNode;
				var html = dojo.string.trim(this.textarea.value);
				if(html == ""){ html = "&nbsp;"; }
				this.domNode = dojo.doc().createElement("div");
				dojo.html.copyStyle(this.domNode, this.textarea);
				var tmpFunc = dojo.lang.hitch(this, function(){
					//some browsers refuse to submit display=none textarea, so
					//move the textarea out of screen instead
					with(this.textarea.style){
						display = "block";
						position = "absolute";
						left = top = "-1000px";

						if(h.ie){ //nasty IE bug: abnormal formatting if overflow is not hidden
							this.__overflow = overflow;
							overflow = "hidden";
						}
					}
				});
				if(h.ie){
					setTimeout(tmpFunc, 10);
				}else{
					tmpFunc();
				}
				if(!h.safari){
					// FIXME: VERY STRANGE safari 2.0.4 behavior here caused by
					// moving the textarea. Often crashed the browser!!! Seems
					// fixed on webkit nightlies.
					dojo.html.insertBefore(this.domNode, this.textarea);
				}
				// this.domNode.innerHTML = html;

				if(this.textarea.form){
					dojo.event.connect(this.textarea.form, "onsubmit",
						// FIXME: should we be calling close() here instead?
						dojo.lang.hitch(this, function(){
							this.textarea.value = this.getEditorContent();
						})
					);
				}

				// dojo plucks our original domNode from the document so we need
				// to go back and put ourselves back in
				var editor = this;
				dojo.event.connect(this, "postCreate", function (){
					dojo.html.insertAfter(editor.textarea, editor.domNode);
				});
			}else{
				var html = this._preFilterContent(dojo.string.trim(this.domNode.innerHTML));
				if(html == ""){ html = "&nbsp;"; }
			}

			var content = dojo.html.getContentBox(this.domNode);
			this._oldHeight = content.height;
			this._oldWidth = content.width;

			this._firstChildContributingMargin = this._getContributingMargin(this.domNode, "top");
			this._lastChildContributingMargin = this._getContributingMargin(this.domNode, "bottom");

			this.savedContent = dojo.doc().createElement("div");
			while (this.domNode.hasChildNodes()) {
				this.savedContent.appendChild(this.domNode.firstChild);
			}

			this.editingArea = dojo.doc().createElement("div");
			this.domNode.appendChild(this.editingArea);

			// If we're a list item we have to put in a blank line to force the
			// bullet to nicely align at the top of text
			if(	(this.domNode["nodeName"])&&
				(this.domNode.nodeName == "LI")){
				this.domNode.innerHTML = " <br>";
			}

			if(this.saveName != ""){
				var saveTextarea = dojo.doc().getElementById("dojo.widget.RichText.savedContent");
				if (saveTextarea.value != "") {
					var datas = saveTextarea.value.split(this._SEPARATOR);
					for (var i = 0; i < datas.length; i++) {
						var data = datas[i].split(":");
						if (data[0] == this.saveName) {
							html = data[1];
							datas.splice(i, 1);
							break;
						}
					}
				}
				dojo.event.connect("before", window, "onunload", this, "_saveContent");
				// dojo.event.connect(window, "onunload", this, "_saveContent");
			}

			if(h.ie70 && this.useActiveX){
				dojo.debug("activeX in ie70 is not currently supported, useActiveX is ignored for now.");
				this.useActiveX = false;
			}
			// Safari's selections go all out of whack if we do it inline,
			// so for now IE is our only hero
			//if (typeof document.body.contentEditable != "undefined") {
			if(this.useActiveX && h.ie){ // active-x
				var self = this;
				//if call _drawObject directly here, textarea replacement
				//won't work: no content is shown. However, add a delay
				//can workaround this. No clue why.
				setTimeout(function(){self._drawObject(html);}, 0);
			}else if(h.ie){ // contentEditable, easy
				this.iframe = dojo.doc().createElement( 'iframe' ) ;
				this.iframe.src = 'javascript:void(0)';
				this.editorObject = this.iframe;
				with(this.iframe.style){
					border = '0';
					width = "100%";
				}
				this.iframe.frameBorder = 0;
				this.editingArea.appendChild(this.iframe)
				this.window = this.iframe.contentWindow;
				this.document = this.window.document;
				this.document.open();
				this.document.write("<html><head></head><body style='margin: 0; padding: 0;border: 0; overflow: hidden;'><div></div></body></html>");
				this.document.close();
				this.editNode = this.document.body.firstChild;//document.createElement("div");
				this.editNode.contentEditable = true;
				with (this.iframe.style) {
					if(h.ie70){
						if(this.height){
							height = this.height;
						}
						if(this.minHeight){
							minHeight = this.minHeight;
						}
					}else{
						height = this.height ? this.height : this.minHeight;
					}
				}

				// FIXME: setting contentEditable on switches this element to
				// IE's hasLayout mode, triggering weird margin collapsing
				// behavior. It's particularly bad if the element you're editing
				// contains childnodes that don't have margin: defined in local
				// css rules. It would be nice if it was possible to hack around
				// this. Sadly _firstChildContributingMargin and
				// _lastChildContributingMargin don't work on IE unless all
				// elements have margins set in CSS :-(

				//if the normal way fails, we try the hard way to get the list
				if(!this._cacheLocalBlockFormatNames()){
					//in the array below, ul can not come directly after ol, otherwise the queryCommandValue returns Normal for it
					var formats = ['p', 'pre', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'div', 'ul'];
					var localhtml = "";
					for(var i in formats){
						if(formats[i].charAt(1) != 'l'){
							localhtml += "<"+formats[i]+"><span>content</span></"+formats[i]+">";
						}else{
							localhtml += "<"+formats[i]+"><li>content</li></"+formats[i]+">";
						}
					}
					//queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
					with(this.editNode.style){
						position = "absolute";
						left = "-2000px";
						top = "-2000px";
					}
					this.editNode.innerHTML = localhtml;
					var node = this.editNode.firstChild;
					while(node){
						dojo.withGlobal(this.window, "selectElement", dojo.html.selection, [node.firstChild]);
						var nativename = node.tagName.toLowerCase();
						this._local2NativeFormatNames[nativename] = this.queryCommandValue("formatblock");
//						dojo.debug([nativename,this._local2NativeFormatNames[nativename]]);
						this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
						node = node.nextSibling;
					}
					with(this.editNode.style){
						position = "";
						left = "";
						top = "";
					}
				}

				this.editNode.innerHTML = html;
				if(this.height){ this.document.body.style.overflowY="scroll"; }

				dojo.lang.forEach(this.events, function(e){
					dojo.event.connect(this.editNode, e.toLowerCase(), this, e);
				}, this);

				this.onLoad();
			} else { // designMode in iframe
				this._drawIframe(html);
				this.editorObject = this.iframe;
			}

			// TODO: this is a guess at the default line-height, kinda works
			if (this.domNode.nodeName == "LI") { this.domNode.lastChild.style.marginTop = "-1.2em"; }
			dojo.html.addClass(this.domNode, "RichTextEditable");

			this.isClosed = false;
		},

		_hasCollapseableMargin: function(/*DomNode*/element, /*String*/side) {
			// summary:
			//		check if an element has padding or borders on the given side
			//		which would prevent it from collapsing margins
			if (dojo.html.getPixelValue(element,
										 'border-'+side+'-width',
										 false)) {
				return false;
			} else if (dojo.html.getPixelValue(element,
												'padding-'+side,
												false)) {
				return false;
			} else {
				return true;
			}
		},

		_getContributingMargin:	function(/*DomNode*/element, /*String*/topOrBottom) {
			// summary:
			//		calculate how much margin this element and its first or last
			//		child are contributing to the total margin between this element
			//		and the adjacent node. CSS border collapsing makes this
			//		necessary.

			if (topOrBottom == "top") {
				var siblingAttr = "previousSibling";
				var childSiblingAttr = "nextSibling";
				var childAttr = "firstChild";
				var marginProp = "margin-top";
				var siblingMarginProp = "margin-bottom";
			} else {
				var siblingAttr = "nextSibling";
				var childSiblingAttr = "previousSibling";
				var childAttr = "lastChild";
				var marginProp = "margin-bottom";
				var siblingMarginProp = "margin-top";
			}

			var elementMargin = dojo.html.getPixelValue(element, marginProp, false);

			function isSignificantNode(element) {
				// see if an node is significant in the current context
				// for calulating margins
				return !(element.nodeType==3 && dojo.string.isBlank(element.data))
					&& dojo.html.getStyle(element, "display") != "none"
					&& !dojo.html.isPositionAbsolute(element);
			}

			// walk throuh first/last children to find total collapsed margin size
			var childMargin = 0;
			var child = element[childAttr];
			while (child) {
				// skip over insignificant elements (whitespace, etc)
				while ((!isSignificantNode(child)) && child[childSiblingAttr]) {
					child = child[childSiblingAttr];
				}

				childMargin = Math.max(childMargin, dojo.html.getPixelValue(child, marginProp, false));
				// stop if we hit a bordered/padded element
				if (!this._hasCollapseableMargin(child, topOrBottom)) break;
				child = child[childAttr];
			}

			// if this element has a border, return full child margin immediately
			// as there won't be any margin collapsing
			if (!this._hasCollapseableMargin(element, topOrBottom)){ return parseInt(childMargin); }

			// find margin supplied by nearest sibling
			var contextMargin = 0;
			var sibling = element[siblingAttr];
			while (sibling) {
				if (isSignificantNode(sibling)) {
					contextMargin = dojo.html.getPixelValue(sibling,
															 siblingMarginProp,
															 false);
					break;
				}
				sibling = sibling[siblingAttr];
			}
			if (!sibling) { // no sibling, look at parent's margin instead
				contextMargin = dojo.html.getPixelValue(element.parentNode,
												marginProp, false);
			}

			if (childMargin > elementMargin) {
				return parseInt(Math.max((childMargin-elementMargin)-contextMargin, 0));
			} else {
				return 0;
			}

		},

		_drawIframe: function (/*String*/html){
			// summary:
			//		Draws an iFrame using the existing one if one exists.
			//		Used by Mozilla, Safari, and Opera

			// detect firefox < 1.5, which has some iframe loading issues
			var oldMoz = Boolean(dojo.render.html.moz && (
									typeof window.XML == 'undefined'))

			if(!this.iframe){
				var currentDomain = (new dojo.uri.Uri(dojo.doc().location)).host;
				this.iframe = dojo.doc().createElement("iframe");
				// dojo.body().appendChild(this.iframe);
				with(this.iframe){
					style.border = "none";
					style.lineHeight = "0"; // squash line height
					style.verticalAlign = "bottom";
					scrolling = this.height ? "auto" : "no";
				}
			}
			// opera likes this to be outside the with block
			this.iframe.src = dojo.uri.dojoUri("src/widget/templates/richtextframe.html") + ((dojo.doc().domain != currentDomain) ? ("#"+dojo.doc().domain) : "");
			this.iframe.width = this.inheritWidth ? this._oldWidth : "100%";
			if(this.height){
				this.iframe.style.height = this.height;
			}else{
				var height = this._oldHeight;
				if(this._hasCollapseableMargin(this.domNode, 'top')){
					height += this._firstChildContributingMargin;
				}
				if(this._hasCollapseableMargin(this.domNode, 'bottom')){
					height += this._lastChildContributingMargin;
				}
				this.iframe.height = height;
			}

			var tmpContent = dojo.doc().createElement('div');
			tmpContent.innerHTML = html;

			// make relative image urls absolute
			if(this.relativeImageUrls){
				var imgs = tmpContent.getElementsByTagName('img');
				for(var i=0; i<imgs.length; i++){
					imgs[i].src = (new dojo.uri.Uri(dojo.global().location, imgs[i].src)).toString();
				}
				html = tmpContent.innerHTML;
			}

			// fix margins on tmpContent
			var firstChild = dojo.html.firstElement(tmpContent);
			var lastChild = dojo.html.lastElement(tmpContent);
			if(firstChild){
				firstChild.style.marginTop = this._firstChildContributingMargin+"px";
			}
			if(lastChild){
				lastChild.style.marginBottom = this._lastChildContributingMargin+"px";
			}

			// show existing content behind iframe for now
			tmpContent.style.position = "absolute";
			this.editingArea.appendChild(tmpContent);
			this.editingArea.appendChild(this.iframe);
			if(dojo.render.html.safari){
				this.iframe.src = this.iframe.src;
			}

			var _iframeInitialized = false;

			// now we wait for onload. Janky hack!
			var ifrFunc = dojo.lang.hitch(this, function(){
				if(!_iframeInitialized){
					_iframeInitialized = true;
				}else{ return; }
				if(!this.editNode){
					if(this.iframe.contentWindow){
						this.window = this.iframe.contentWindow;
						this.document = this.iframe.contentWindow.document
					}else if(this.iframe.contentDocument){
						// for opera
						this.window = this.iframe.contentDocument.window;
						this.document = this.iframe.contentDocument;
					}

					// curry the getStyle function
					var getStyle = (function (domNode) { return function (style) {
						return dojo.html.getStyle(domNode, style);
					}; })(this.domNode);

					var font =
						getStyle('font-weight') + " " +
						getStyle('font-size') + " " +
						getStyle('font-family');

					// line height is tricky - applying a units value will mess things up.
					// if we can't get a non-units value, bail out.
					var lineHeight = "1.0";
					var lineHeightStyle = dojo.html.getUnitValue(this.domNode, 'line-height');
					if (lineHeightStyle.value && lineHeightStyle.units=="") {
						lineHeight = lineHeightStyle.value;
					}

					dojo.html.insertCssText(
						'    body,html { background: transparent; padding: 0; margin: 0; }\n' +
						// TODO: left positioning will case contents to disappear out of view
						//       if it gets too wide for the visible area
						'    body { top: 0; left: 0; right: 0;' +
						(((this.height)||(dojo.render.html.opera)) ? '' : ' position: fixed; ') +
						'        font: ' + font + ';\n' +
						'        min-height: ' + this.minHeight + '; \n' +
						'        line-height: ' + lineHeight + '} \n' +
						'    p { margin: 1em 0 !important; }\n' +
						'    body > *:first-child { padding-top: 0 !important; margin-top: ' + this._firstChildContributingMargin + 'px !important; }\n' + // FIXME: test firstChild nodeType
						'    body > *:last-child { padding-bottom: 0 !important; margin-bottom: ' + this._lastChildContributingMargin + 'px !important; }\n' +
						'    li > ul:-moz-first-node, li > ol:-moz-first-node { padding-top: 1.2em; }\n' +
						'    li { min-height: 1.2em; }\n' +
						//'    p,ul,li { padding-top: 0; padding-bottom: 0; margin-top:0; margin-bottom: 0; }\n' +
						'', this.document);

					tmpContent.parentNode.removeChild(tmpContent);
					this.document.body.innerHTML = html;
					if(oldMoz||dojo.render.html.safari){
						this.document.designMode = "on";
					}
					this.onLoad();
				}else{
					tmpContent.parentNode.removeChild(tmpContent);
					this.editNode.innerHTML = html;
					this.onDisplayChanged();
				}
			});

			if(this.editNode){
				ifrFunc(); // iframe already exists, just set content
			}else if(dojo.render.html.moz){
				// FIXME: if we put this on a delay, we get a height of 20px.
				// Otherwise we get the correctly specified minHeight value.
				this.iframe.onload = function(){
					setTimeout(ifrFunc, 250);
				}
			}else{ // new mozillas, opera, safari
				this.iframe.onload = ifrFunc;
			}
		},

		_applyEditingAreaStyleSheets: function(){
			// summary:
			//		apply the specified css files in styleSheets
			var files = [];
			if(this.styleSheets){
				files = this.styleSheets.split(';');
			}

			//empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
			files = files.concat(this.editingAreaStyleSheets);
			this.editingAreaStyleSheets = [];

			if(files.length>0){
				for(var i=0;i<files.length;i++){
					var url = files[i];
					if(url){
						this.addStyleSheet(new dojo.uri.Uri(url));
	 				}
	 			}
			}
		},

		addStyleSheet: function(/*dojo.uri.Uri*/uri) {
			// summary:
			//		add an external stylesheet for the editing area
			// uri:	a dojo.uri.Uri pointing to the url of the external css file
			var url=uri.toString();
			if(dojo.lang.find(this.editingAreaStyleSheets, url) > -1){
				dojo.debug("dojo.widget.RichText.addStyleSheet: Style sheet "+url+" is already applied to the editing area!");
				return;
			}

			//if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
			if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
				url = (new dojo.uri.Uri(dojo.global().location, url)).toString();
			}

			this.editingAreaStyleSheets.push(url);
			if(this.document.createStyleSheet){ //IE
				this.document.createStyleSheet(url);
			}else{ //other browser
				var head = this.document.getElementsByTagName("head")[0];
				var stylesheet = this.document.createElement("link");
				with(stylesheet){
					rel="stylesheet";
					type="text/css";
					href=url;
				}
				head.appendChild(stylesheet);
			}
		},

		removeStyleSheet: function (/*dojo.uri.Uri*/uri) {
			// summary:
			//		remove an external stylesheet for the editing area
			var url=uri.toString();
			var index = dojo.lang.find(this.editingAreaStyleSheets, url);
			if(index == -1){
				dojo.debug("dojo.widget.RichText.removeStyleSheet: Style sheet "+url+" is not applied to the editing area so it can not be removed!");
				return;
			}
			delete this.editingAreaStyleSheets[index];

			var links = this.document.getElementsByTagName("link");
			for(var i=0;i<links.length;i++){
				if(links[i].href == url){
					if(dojo.render.html.ie){//we need to empty the href first, to get IE to remove the rendered styles
						links[i].href="";
					}
					dojo.html.removeNode(links[i]);
					break;
				}
			}
		},

		_drawObject: function (/*String*/html) {
			// summary:
			//		Draws an active x object, used by IE
			this.object = dojo.html.createExternalElement(dojo.doc(), "object");

			with (this.object) {
				classid = "clsid:2D360201-FFF5-11D1-8D03-00A0C959BC0A";
				width = this.inheritWidth ? this._oldWidth : "100%";
				style.height = this.height ? this.height : (this._oldHeight+"px");
				Scrollbars = this.height ? true : false;
				Appearance = this._activeX.appearance.flat;
			}
			this.editorObject = this.object;
			this.editingArea.appendChild(this.object);

			this.object.attachEvent("DocumentComplete", dojo.lang.hitch(this, "onLoad"));
			//DisplayChanged is fired too often even no change is made, so we ignore it
			//and call onDisplayChanged manually in execCommand instead
//			this.object.attachEvent("DisplayChanged", dojo.lang.hitch(this, "onDisplayChanged"));

			dojo.lang.forEach(this.events, function(e){
				this.object.attachEvent(e.toLowerCase(), dojo.lang.hitch(this, e));
			}, this);

			this.object.DocumentHTML = '<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' +
				'<html><title></title>' +
				'<style type="text/css">' +
				'    body,html { padding: 0; margin: 0; }' + //font: ' + font + '; }' +
				(this.height ? '' : '    body,  { overflow: hidden; }') +
				'</style>' +
				//'<base href="' + dojo.global().location + '">' +
				'<body><div>' + html + '<div></body></html>';

			this._cacheLocalBlockFormatNames();
		},

		//static cache variables shared among all instance of this class
		_local2NativeFormatNames: {},
		_native2LocalFormatNames: {},
		//in IE, names for blockformat is locale dependent, so we cache the values here
		//we use activeX to obtain the list, if success or the names are already cached,
		//return true
		_cacheLocalBlockFormatNames: function(){
			// summary:
			//		in IE, names for blockformat is locale dependent, so we cache the values here
			//		we use activeX to obtain the list, if success or the names are already cached,
			//		return true
			if(!this._native2LocalFormatNames['p']){
				var obj = this.object;
				if(!obj){
					//create obj temporarily
					try{
						obj = dojo.html.createExternalElement(dojo.doc(), "object");
						obj.classid = "clsid:2D360201-FFF5-11D1-8D03-00A0C959BC0A";
						dojo.body().appendChild(obj);
						obj.DocumentHTML = "<html><head></head><body></body></html>";
					}catch(e){
						return false;
					}
				}
				var oNamesParm = new ActiveXObject("DEGetBlockFmtNamesParam.DEGetBlockFmtNamesParam");
				obj.ExecCommand(this._activeX.command['getblockformatnames'], 0, oNamesParm);
				var vbNamesArray = new VBArray(oNamesParm.Names);
				var localFormats = vbNamesArray.toArray();
				var nativeFormats = ['p', 'pre', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', '', '', '','','div'];
				for(var i=0;i<nativeFormats.length;++i){
					if(nativeFormats[i].length>0){
						this._local2NativeFormatNames[localFormats[i]] = nativeFormats[i];
						this._native2LocalFormatNames[nativeFormats[i]] = localFormats[i];
					}
				}
				if(!this.object){
					//delete the temporary obj
					dojo.body().removeChild(obj);
				}
			}
			return true;
		},
	/* Event handlers
	 *****************/

		_isResized: function(){ return false; },

		onLoad: function(e){
			// summary: handler after the content of the document finishes loading
			this.isLoaded = true;
			if (this.object){
				this.document = this.object.DOM;
				this.window = this.document.parentWindow;
				this.editNode = this.document.body.firstChild;
				this.editingArea.style.height = this.height ? this.height : this.minHeight;
				this.connect(this, "onDisplayChanged", "_updateHeight");
				//pretend the object as an iframe, so that the context menu for the
				//editor can be placed correctly when shown
				this.window._frameElement = this.object;
			}else if (this.iframe && !dojo.render.html.ie){
				this.editNode = this.document.body;
				this.connect(this, "onDisplayChanged", "_updateHeight");

				try { // sanity check for Mozilla
					this.document.execCommand("useCSS", false, true); // old moz call
					this.document.execCommand("styleWithCSS", false, false); // new moz call
					//this.document.execCommand("insertBrOnReturn", false, false); // new moz call
				}catch(e2){ }

				if (dojo.render.html.safari) {
					/*
					this.iframe.style.visiblity = "visible";
					this.iframe.style.border = "1px solid black";
					this.editNode.style.visiblity = "visible";
					this.editNode.style.border = "1px solid black";
					*/
					// this.onDisplayChanged();
					this.connect(this.editNode, "onblur", "onBlur");
					this.connect(this.editNode, "onfocus", "onFocus");
					this.connect(this.editNode, "onclick", "onFocus");

					this.interval = setInterval(dojo.lang.hitch(this, "onDisplayChanged"), 750);
					// dojo.raise("onload");
					// dojo.debug(this.editNode.parentNode.parentNode.parentNode.nodeName);
				} else if (dojo.render.html.mozilla || dojo.render.html.opera) {
					var doc = this.document;
					var addListener = dojo.event.browser.addListener;
					var self = this;
					dojo.lang.forEach(this.events, function(e){
						var l = addListener(self.document, e.substr(2).toLowerCase(), dojo.lang.hitch(self, e));
						if(e=="onBlur"){
							// We need to unhook the blur event listener on close as we
							// can encounter a garunteed crash in FF if another event is
							// also fired
							var unBlur = { unBlur: function(e){
									dojo.event.browser.removeListener(doc, "blur", l);
							} };
							dojo.event.connect("before", self, "close", unBlur, "unBlur");
						}
					});
				}
				// FIXME: when scrollbars appear/disappear this needs to be fired
			}else if(dojo.render.html.ie){
				// IE contentEditable
				this.connect(this, "onDisplayChanged", "_updateHeight");
				this.editNode.style.zoom = 1.0;
			}

			this._applyEditingAreaStyleSheets();

			if(this.focusOnLoad){
				this.focus();
			}
			this.onDisplayChanged(e);
		},

		onKeyDown: function(e){
			// summary: Fired on keydown
			if((!e)&&(this.object)){
				e = dojo.event.browser.fixEvent(this.window.event);
			}
			// dojo.debug("onkeydown:", e.keyCode);
			// we need this event at the moment to get the events from control keys
			// such as the backspace. It might be possible to add this to Dojo, so that
			// keyPress events can be emulated by the keyDown and keyUp detection.
			if((dojo.render.html.ie)&&(e.keyCode == e.KEY_TAB)){
				e.preventDefault();
				e.stopPropagation();
				// FIXME: this is a poor-man's indent/outdent. It would be
				// better if it added 4 "&nbsp;" chars in an undoable way.
				// Unfortuantly pasteHTML does not prove to be undoable
				this.execCommand((e.shiftKey ? "outdent" : "indent"));
			}else if(dojo.render.html.ie){
				if((65 <= e.keyCode)&&(e.keyCode <= 90)){
					e.charCode = e.keyCode;
					this.onKeyPress(e);
				}
				// dojo.debug(e.ctrlKey);
				// dojo.debug(e.keyCode);
				// dojo.debug(e.charCode);
				// this.onKeyPress(e);
			}
		},

		onKeyUp: function(e){
			// summary: Fired on keyup
			return;
		},

		KEY_CTRL: 1,

		onKeyPress: function(e){
			// summary: Fired on keypress
			if((!e)&&(this.object)){
				e = dojo.event.browser.fixEvent(this.window.event);
			}
			// handle the various key events

			var modifiers = e.ctrlKey ? this.KEY_CTRL : 0;

			if (this._keyHandlers[e.key]) {
				// dojo.debug("char:", e.key);
				var handlers = this._keyHandlers[e.key], i = 0, handler;
				while (handler = handlers[i++]) {
					if (modifiers == handler.modifiers) {
						handler.handler.call(this);
						e.preventDefault();
						break;
					}
				}
			}

			// function call after the character has been inserted
			dojo.lang.setTimeout(this, this.onKeyPressed, 1, e);
		},

		addKeyHandler: function (/*String*/key, /*Int*/modifiers, /*Function*/handler) {
			// summary: add a handler for a keyboard shortcut
			if (!(this._keyHandlers[key] instanceof Array)) { this._keyHandlers[key] = []; }
			this._keyHandlers[key].push({
				modifiers: modifiers || 0,
				handler: handler
			});
		},

		onKeyPressed: function (e) {
			// summary:
			//		Fired after a keypress event has occured and it's action taken. This
		 	//		is useful if action needs to be taken after text operations have finished

			// Mozilla adds a single <p> with an embedded <br> when you hit enter once:
			//   <p><br>\n</p>
			// when you hit enter again it adds another <br> inside your enter
			//   <p><br>\n<br>\n</p>
			// and if you hit enter again it splits the <br>s over 2 <p>s
			//   <p><br>\n</p>\n<p><br>\n</p>
			// now this assumes that <p>s have double the line-height of <br>s to work
			// and so we need to remove the <p>s to ensure the position of the cursor
			// changes from the users perspective when they hit enter, as the second two
			// html snippets render the same when margins are set to 0.

			// TODO: doesn't really work; is this really needed?
			//if (dojo.render.html.moz) {
			//	for (var i = 0; i < this.document.getElementsByTagName("p").length; i++) {
			//		var p = this.document.getElementsByTagName("p")[i];
			//		if (p.innerHTML.match(/^<br>\s$/m)) {
			//			while (p.hasChildNodes()) { p.parentNode.insertBefore(p.firstChild, p); }
			//			p.parentNode.removeChild(p);
			//		}
			//	}
			//}
			this.onDisplayChanged(/*e*/); // can't pass in e
		},

		onClick: function(e){ this.onDisplayChanged(e); },
		onBlur: function(e){ },
		_initialFocus: true,
		onFocus: function(e){
			// summary: Fired on focus
			if( (dojo.render.html.mozilla)&&(this._initialFocus) ){
				this._initialFocus = false;
				if(dojo.string.trim(this.editNode.innerHTML) == "&nbsp;"){
					this.placeCursorAtStart();
//					this.execCommand("selectall");
//					this.window.getSelection().collapseToStart();
				}
			}
		},

		blur: function () {
			// summary: remove focus from this instance
			if(this.iframe) { this.window.blur(); }
			else if(this.object) { this.document.body.blur(); }
			else if(this.editNode) { this.editNode.blur(); }
		},

		focus: function () {
			// summary: move focus to this instance
			if(this.iframe && !dojo.render.html.ie) { this.window.focus(); }
			else if(this.object) { this.document.focus(); }
			// editNode may be hidden in display:none div, lets just punt in this case
			else if(this.editNode && this.editNode.focus) { this.editNode.focus(); }
			else{
				dojo.debug("Have no idea how to focus into the editor!");
			}
		},

		/** this event will be fired everytime the display context changes and the
		 result needs to be reflected in the UI */
		onDisplayChanged: function (e){ },


	/* Formatting commands
	 **********************/

		// Object: IE's Active X codes: see http://www.computerbytesman.com/js/activex/dhtmledit.htm
		_activeX: {
			command: {
				bold: 5000,
				italic: 5023,
				underline: 5048,

				justifycenter: 5024,
				justifyleft: 5025,
				justifyright: 5026,

				cut: 5003,
				copy: 5002,
				paste: 5032,
				"delete": 5004,

				undo: 5049,
				redo: 5033,

				removeformat: 5034,
				selectall: 5035,
				unlink: 5050,

				indent: 5018,
				outdent: 5031,

				insertorderedlist: 5030,
				insertunorderedlist: 5051,

				// table commands
				inserttable: 5022,
				insertcell: 5019,
				insertcol: 5020,
				insertrow: 5021,
				deletecells: 5005,
				deletecols: 5006,
				deleterows: 5007,
				mergecells: 5029,
				splitcell: 5047,

				// the command need mapping, they don't translate directly
				// to the contentEditable commands
				setblockformat: 5043,
				getblockformat: 5011,
				getblockformatnames: 5012,
				setfontname: 5044,
				getfontname: 5013,
				setfontsize: 5045,
				getfontsize: 5014,
				setbackcolor: 5042,
				getbackcolor: 5010,
				setforecolor: 5046,
				getforecolor: 5015,

				findtext: 5008,
				font: 5009,
				hyperlink: 5016,
				image: 5017,

				lockelement: 5027,
				makeabsolute: 5028,
				sendbackward: 5036,
				bringforward: 5037,
				sendbelowtext: 5038,
				bringabovetext: 5039,
				sendtoback: 5040,
				bringtofront: 5041,

				properties: 5052
			},

			ui: {
				"default": 0,
				prompt: 1,
				noprompt: 2
			},

			status: {
				notsupported: 0,
				disabled: 1,
				enabled: 3,
				latched: 7,
				ninched: 11
			},

			appearance: {
				flat: 0,
				inset: 1
			},

			state: {
				unchecked: 0,
				checked: 1,
				gray: 2
			}
		},

		_normalizeCommand: function (/*String*/cmd){
			// summary:
			//		Used as the advice function by dojo.event.connect to map our
		 	//		normalized set of commands to those supported by the target
		 	//		browser
			var drh = dojo.render.html;

			var command = cmd.toLowerCase();
			if(command == "formatblock"){
				if(drh.safari){ command = "heading"; }
			}else if(this.object){
				switch(command){
					case "createlink":
						command = "hyperlink";
						break;
					case "insertimage":
						command = "image";
						break;
				}
			}else if(command == "hilitecolor" && !drh.mozilla){
				command = "backcolor";
			}

			return command;
		},

		queryCommandAvailable: function (/*String*/command) {
			// summary:
			//		Tests whether a command is supported by the host. Clients SHOULD check
			//		whether a command is supported before attempting to use it, behaviour
			//		for unsupported commands is undefined.
			// command: The command to test for
			var ie = 1;
			var mozilla = 1 << 1;
			var safari = 1 << 2;
			var opera = 1 << 3;
			var safari420 = 1 << 4;

			var gt420 = false;
			if(dojo.render.html.safari){
				var tmp = dojo.render.html.UA.split("AppleWebKit/")[1];
				var ver = parseFloat(tmp.split(" ")[0]);
				if(ver >= 420){ gt420 = true; }
			}

			function isSupportedBy (browsers) {
				return {
					ie: Boolean(browsers & ie),
					mozilla: Boolean(browsers & mozilla),
					safari: Boolean(browsers & safari),
					safari420: Boolean(browsers & safari420),
					opera: Boolean(browsers & opera)
				}
			}

			var supportedBy = null;

			switch (command.toLowerCase()) {
				case "bold": case "italic": case "underline":
				case "subscript": case "superscript":
				case "fontname": case "fontsize":
				case "forecolor": case "hilitecolor":
				case "justifycenter": case "justifyfull": case "justifyleft":
				case "justifyright": case "delete": case "selectall":
					supportedBy = isSupportedBy(mozilla | ie | safari | opera);
					break;

				case "createlink": case "unlink": case "removeformat":
				case "inserthorizontalrule": case "insertimage":
				case "insertorderedlist": case "insertunorderedlist":
				case "indent": case "outdent": case "formatblock":
				case "inserthtml": case "undo": case "redo": case "strikethrough":
					supportedBy = isSupportedBy(mozilla | ie | opera | safari420);
					break;

				case "blockdirltr": case "blockdirrtl":
				case "dirltr": case "dirrtl":
				case "inlinedirltr": case "inlinedirrtl":
					supportedBy = isSupportedBy(ie);
					break;
				case "cut": case "copy": case "paste":
					supportedBy = isSupportedBy( ie | mozilla | safari420);
					break;

				case "inserttable":
					supportedBy = isSupportedBy(mozilla | (this.object ? ie : 0));
					break;

				case "insertcell": case "insertcol": case "insertrow":
				case "deletecells": case "deletecols": case "deleterows":
				case "mergecells": case "splitcell":
					supportedBy = isSupportedBy(this.object ? ie : 0);
					break;

				default: return false;
			}

			return (dojo.render.html.ie && supportedBy.ie) ||
				(dojo.render.html.mozilla && supportedBy.mozilla) ||
				(dojo.render.html.safari && supportedBy.safari) ||
				(gt420 && supportedBy.safari420) ||
				(dojo.render.html.opera && supportedBy.opera);  // Boolean: return true if the command is supported, false otherwise
		},

		execCommand: function (/*String*/command, argument){
			// summary: Executes a command in the Rich Text area
			// command: The command to execute
			// argument: An optional argument to the command
			var returnValue;

			//focus() is required for IE (none-activeX mode) to work
			//In addition, focus() makes sure after the execution of
			//the command, the editor receives the focus as expected
			this.focus();

			command = this._normalizeCommand(command);
			if (argument != undefined) {
				if(command == "heading") { throw new Error("unimplemented"); }
				else if(command == "formatblock"){
					if(this.object){ //IE activeX mode
						argument = this._native2LocalFormatNames[argument];
					}
					else if(drh.ie){ argument = '<'+argument+'>'; }
				}
			}
			if(this.object){
				switch (command) {
					case "hilitecolor":
						command = "setbackcolor";
						break;
					case "forecolor":
					case "backcolor":
					case "fontsize":
					case "fontname":
						command = "set" + command;
						break;
					case "formatblock":
						command = "setblockformat";
				}

				if(command == "strikethrough"){
					command = "inserthtml";
					var range = this.document.selection.createRange();
					if(!range.htmlText){
						return;
					}
					argument=range.htmlText.strike();
				}else if(command == "inserthorizontalrule"){
					command = "inserthtml";
					argument="<hr>";
				}

				if(command == "inserthtml"){
					var range = this.document.selection.createRange();
					if(this.document.selection.type.toUpperCase() == "CONTROL"){
						//if selection is controlrange, no pasteHTML is available,
						//we replace the outerHTML directly
						for(var i=0;i<range.length;i++){
							range.item(i).outerHTML = argument;
						}
					}else{
						// on IE, we can use the pasteHTML method of the textRange object
						// to get an undo-able innerHTML modification
						range.pasteHTML(argument);
						range.select();
					}
					returnValue = true;
				}else if(arguments.length == 1){
					returnValue = this.object.ExecCommand(this._activeX.command[command],
						this._activeX.ui.noprompt);
				}else{
					returnValue = this.object.ExecCommand(this._activeX.command[command],
						this._activeX.ui.noprompt, argument);
				}
			}else if(command == "inserthtml"){
				if(dojo.render.html.ie){
					//dojo.debug("inserthtml breaks the undo stack when not using the ActiveX version of the control!");
					var insertRange = this.document.selection.createRange();
					insertRange.pasteHTML(argument);
					insertRange.select();
					//insertRange.collapse(true);
					return true;
				}else{
					return this.document.execCommand(command, false, argument);
				}
			/* */
			// fix up unlink in Mozilla to unlink the link and not just the selection
			}else if((command == "unlink")&&
				(this.queryCommandEnabled("unlink"))&&
				(dojo.render.html.mozilla)){
				// grab selection
				// Mozilla gets upset if we just store the range so we have to
				// get the basic properties and recreate to save the selection
				var selection = this.window.getSelection();
				var selectionRange = selection.getRangeAt(0);
				var selectionStartContainer = selectionRange.startContainer;
				var selectionStartOffset = selectionRange.startOffset;
				var selectionEndContainer = selectionRange.endContainer;
				var selectionEndOffset = selectionRange.endOffset;

				// select our link and unlink
				var a = dojo.withGlobal(this.window, "getAncestorElement", dojo.html.selection, ['a']);
				dojo.withGlobal(this.window, "selectElement", dojo.html.selection, [a]);

				returnValue = this.document.execCommand("unlink", false, null);

				// restore original selection
				var selectionRange = this.document.createRange();
				selectionRange.setStart(selectionStartContainer, selectionStartOffset);
				selectionRange.setEnd(selectionEndContainer, selectionEndOffset);
				selection.removeAllRanges();
				selection.addRange(selectionRange);

				return returnValue;
			}else if((command == "hilitecolor")&&(dojo.render.html.mozilla)){
				// mozilla doesn't support hilitecolor properly when useCSS is
				// set to false (bugzilla #279330)

				this.document.execCommand("useCSS", false, false);
				returnValue = this.document.execCommand(command, false, argument);
				this.document.execCommand("useCSS", false, true);

			}else if((dojo.render.html.ie)&&( (command == "backcolor")||(command == "forecolor") )){
				// Tested under IE 6 XP2, no problem here, comment out
				// IE weirdly collapses ranges when we exec these commands, so prevent it
//				var tr = this.document.selection.createRange();
				argument = arguments.length > 1 ? argument : null;
				returnValue = this.document.execCommand(command, false, argument);

				// timeout is workaround for weird IE behavior were the text
				// selection gets correctly re-created, but subsequent input
				// apparently isn't bound to it
//				setTimeout(function(){tr.select();}, 1);
			}else{
				// dojo.debug("command:", command, "arg:", argument);

				argument = arguments.length > 1 ? argument : null;
//				if(dojo.render.html.moz){
//					this.document = this.iframe.contentWindow.document
//				}

				if(argument || command!="createlink") {
					returnValue = this.document.execCommand(command, false, argument);
				}
			}

			this.onDisplayChanged();
			return returnValue;
		},

		queryCommandEnabled: function(/*String*/command){
			// summary: check whether a command is enabled or not
			command = this._normalizeCommand(command);
			if(this.object){
				switch (command) {
					case "hilitecolor":
						command = "setbackcolor";
						break;
					case "forecolor":
					case "backcolor":
					case "fontsize":
					case "fontname":
						command = "set" + command;
						break;
					case "formatblock":
						command = "setblockformat";
						break;
					//below are not natively supported commands, we fake them
					case "strikethrough":
						command = "bold"; //whenever bold is enabled, strikethrough should be so as well
						break;
					case "inserthorizontalrule":
						return true;
				}

				if(typeof this._activeX.command[command] == "undefined"){ return false; }
				var status = this.object.QueryStatus(this._activeX.command[command]);
				return ((status != this._activeX.status.notsupported)&&
					(status != this._activeX.status.disabled));
			}else{
				if(dojo.render.html.mozilla){
					if(command == "unlink"){ // mozilla returns true always
						return dojo.withGlobal(this.window, "hasAncestorElement", dojo.html.selection, ['a']);
					} else if (command == "inserttable") {
						return true;
					}
				}

				// return this.document.queryCommandEnabled(command);
				var elem = (dojo.render.html.ie) ? this.document.selection.createRange() : this.document;
				return elem.queryCommandEnabled(command);
			}
		},

		queryCommandState: function(command){
			// summary: check the state of a given command
			command = this._normalizeCommand(command);
			if(this.object){
				if(command == "forecolor"){
					command = "setforecolor";
				}else if(command == "backcolor"){
					command = "setbackcolor";
				}else if(command == "strikethrough"){
					//check whether we are under a <strike>
					return dojo.withGlobal(this.window, "hasAncestorElement", dojo.html.selection, ['strike']);
				}else if(command == "inserthorizontalrule"){
					return false;
				}

				if(typeof this._activeX.command[command] == "undefined"){ return null; }
				var status = this.object.QueryStatus(this._activeX.command[command]);
				return ((status == this._activeX.status.latched)||
					(status == this._activeX.status.ninched));
			}else{
				return this.document.queryCommandState(command);
			}
		},

		queryCommandValue: function (command) {
			// summary: check the value of a given command
			command = this._normalizeCommand(command);
			if (this.object) {
				switch (command) {
					case "forecolor":
					case "backcolor":
					case "fontsize":
					case "fontname":
						command = "get" + command;
						return this.object.execCommand(
							this._activeX.command[command],
							this._activeX.ui.noprompt);
					case "formatblock":
						var retvalue = this.object.execCommand(
							this._activeX.command["getblockformat"],
							this._activeX.ui.noprompt);
						if(retvalue){
							return this._local2NativeFormatNames[retvalue];
						}
				}
			} else {
				if(dojo.render.html.ie && command == "formatblock"){
					return this._local2NativeFormatNames[this.document.queryCommandValue(command)] || this.document.queryCommandValue(command);
				}
				return this.document.queryCommandValue(command);
			}
		},


	/* Misc.
	 ********/

		placeCursorAtStart: function(){
			// summary:
			//		place the cursor at the start of the editing area
			this.focus();
			//see comments in placeCursorAtEnd
			if(dojo.render.html.moz && this.editNode.firstChild &&
				this.editNode.firstChild.nodeType != dojo.dom.TEXT_NODE){
				dojo.withGlobal(this.window, "selectElementChildren", dojo.html.selection, [this.editNode.firstChild]);
			}else{
				dojo.withGlobal(this.window, "selectElementChildren", dojo.html.selection, [this.editNode]);
			}
			dojo.withGlobal(this.window, "collapse", dojo.html.selection, [true]);
		},

		placeCursorAtEnd: function(){
			// summary:
			//		place the cursor at the end of the editing area
			this.focus();
			//In mozilla, if last child is not a text node, we have to use selectElementChildren on this.editNode.lastChild
			//otherwise the cursor would be placed at the end of the closing tag of this.editNode.lastChild
			if(dojo.render.html.moz && this.editNode.lastChild &&
				this.editNode.lastChild.nodeType != dojo.dom.TEXT_NODE){
				dojo.withGlobal(this.window, "selectElementChildren", dojo.html.selection, [this.editNode.lastChild]);
			}else{
				dojo.withGlobal(this.window, "selectElementChildren", dojo.html.selection, [this.editNode]);
			}
			dojo.withGlobal(this.window, "collapse", dojo.html.selection, [false]);
		},

		replaceEditorContent: function(/*String*/html){
			// summary:
			//		this function set the content while trying to maintain the undo stack
			html = this._preFilterContent(html);
			if(this.isClosed){
				this.domNode.innerHTML = html;
			}else if(this.window && this.window.getSelection && !dojo.render.html.moz){ // Safari
				// look ma! it's a totally f'd browser!
				this.editNode.innerHTML = html;
			}else if((this.window && this.window.getSelection) || (this.document && this.document.selection)){ // Moz/IE
				this.execCommand("selectall");
				this.execCommand("inserthtml", html);
			}
		},

		_preFilterContent: function(/*String*/html){
			// summary:
			//		filter the input before setting the content of the editing area
			var ec = html;
			dojo.lang.forEach(this.contentPreFilters, function(ef){
				ec = ef(ec);
			});
			if(this.contentDomPreFilters.length>0){
				var dom = dojo.doc().createElement('div');
				dom.style.display = "none";
				dojo.body().appendChild(dom);
				dom.innerHTML = ec;
				dojo.lang.forEach(this.contentDomPreFilters, function(ef){
					dom = ef(dom);
				});
				ec = dom.innerHTML;
				dojo.body().removeChild(dom);
			}
			return ec;
		},
		_postFilterContent: function(/*String*/html){
			// summary:
			//		filter the output after getting the content of the editing area
			var ec = html;
			if(this.contentDomPostFilters.length>0){
				var dom = this.document.createElement('div');
				dom.innerHTML = ec;
				dojo.lang.forEach(this.contentDomPostFilters, function(ef){
					dom = ef(dom);
				});
				ec = dom.innerHTML;
			}
			dojo.lang.forEach(this.contentPostFilters, function(ef){
				ec = ef(ec);
			});
			return ec;
		},

		//Int: stored last time height
		_lastHeight: 0,

		_updateHeight: function(){
			// summary:
			//		Updates the height of the editor area to fit the contents.
			if(!this.isLoaded){ return; }
			if(this.height){ return; }

			var height = dojo.html.getBorderBox(this.editNode).height;
			//height maybe zero in some cases even though the content is not empty,
			//we try the height of body instead
			if(!height){
				height = dojo.html.getBorderBox(this.document.body).height;
			}
			if(height == 0){
				dojo.debug("Can not figure out the height of the editing area!");
				return; //prevent setting height to 0
			}
			this._lastHeight = height;
			this.editorObject.style.height = this._lastHeight + "px";
			this.window.scrollTo(0, 0);
		},

		_saveContent: function(e){
			// summary:
			//		Saves the content in an onunload event if the editor has not been closed
			var saveTextarea = dojo.doc().getElementById("dojo.widget.RichText.savedContent");
			saveTextarea.value += this._SEPARATOR + this.saveName + ":" + this.getEditorContent();
		},

		getEditorContent: function(){
			// summary:
			//		return the current content of the editing area (post filters are applied)
			var ec = "";
			try{
				ec = (this._content.length > 0) ? this._content : this.editNode.innerHTML;
				if(dojo.string.trim(ec) == "&nbsp;"){ ec = ""; }
			}catch(e){ /* squelch */ }

			if(dojo.render.html.ie && !this.object){
				//removing appended <P>&nbsp;</P> for IE in none-activeX mode
				var re = new RegExp("(?:<p>&nbsp;</p>[\n\r]*)+$", "i");
				ec = ec.replace(re,"");
			}

			ec = this._postFilterContent(ec);

			if (this.relativeImageUrls) {
				// why use a regexp instead of dom? because IE is stupid
				// and won't let us set img.src to a relative URL
				// this comes after contentPostFilters because once content
				// gets innerHTML'd img urls will be fully qualified
				var siteBase = dojo.global().location.protocol + "//" + dojo.global().location.host;
				var pathBase = dojo.global().location.pathname;
				if (pathBase.match(/\/$/)) {
					// ends with slash, match full path
				} else {
					// match parent path to find siblings
					var pathParts = pathBase.split("/");
					if (pathParts.length) {
						pathParts.pop();
					}
					pathBase = pathParts.join("/") + "/";

				}

				var sameSite = new RegExp("(<img[^>]*\ src=[\"'])("+siteBase+"("+pathBase+")?)", "ig");
				ec = ec.replace(sameSite, "$1");
			}
			return ec;
		},

		close: function(/*Boolean*/save, /*Boolean*/force){
			// summery:
			//		Kills the editor and optionally writes back the modified contents to the
			//		element from which it originated.
			// save:
			//		Whether or not to save the changes. If false, the changes are discarded.
			// force:
			if(this.isClosed){return false; }

			if (arguments.length == 0) { save = true; }
			this._content = this._postFilterContent(this.editNode.innerHTML);
			var changed = (this.savedContent.innerHTML != this._content);

			// line height is squashed for iframes
			// FIXME: why was this here? if (this.iframe){ this.domNode.style.lineHeight = null; }

			if(this.interval){ clearInterval(this.interval); }

			if(dojo.render.html.ie && !this.object){
				dojo.event.browser.clean(this.editNode);
			}

			if (this.iframe) {
				// FIXME: should keep iframe around for later re-use
				delete this.iframe;
			}

			if(this.textarea){
				with(this.textarea.style){
					position = "";
					left = top = "";
					if(dojo.render.html.ie){
						overflow = this.__overflow;
						this.__overflow = null;
					}
				}

				this.domNode.parentNode.removeChild(this.domNode);
				this.domNode = this.textarea;
			}else{
				this.domNode.innerHTML = "";
			}

			if(save){
				// kill listeners on the saved content
				dojo.event.browser.clean(this.savedContent);
				if(dojo.render.html.moz){
					var nc = dojo.doc().createElement("span");
					this.domNode.appendChild(nc);
					nc.innerHTML = this.editNode.innerHTML;
				}else{
					this.domNode.innerHTML = this._content;
				}
			} else {
				while (this.savedContent.hasChildNodes()) {
					this.domNode.appendChild(this.savedContent.firstChild);
				}
			}
			delete this.savedContent;

			dojo.html.removeClass(this.domNode, "RichTextEditable");
			this.isClosed = true;
			this.isLoaded = false;
			// FIXME: is this always the right thing to do?
			delete this.editNode;

			if(this.window._frameElement){
				this.window._frameElement = null;
			}

			this.window = null;
			this.document = null;
			this.object = null;
			this.editingArea = null;
			this.editorObject = null;

			return changed; // Boolean: whether the content has been modified
		},

		destroyRendering: function(){}, // stub!

		destroy: function (){
			this.destroyRendering();
			if(!this.isClosed){ this.close(false); }

			dojo.widget.RichText.superclass.destroy.call(this);
		},

		connect: function (targetObj, targetFunc, thisFunc) {
			// summary: convenient method for dojo.event.connect
			dojo.event.connect(targetObj, targetFunc, this, thisFunc);
		},

		disconnect: function (targetObj, targetFunc, thisFunc) {
			// summary: convenient method for dojo.event.disconnect
			dojo.event.disconnect(targetObj, targetFunc, this, thisFunc);
		},

		disconnectAllWithRoot: function (targetObj) {
			dojo.deprecated("disconnectAllWithRoot", "is deprecated. No need to disconnect manually", "0.5");
		},

		_fixContentForMoz: function(html){
			// summary:
			//		Moz can not handle strong/em tags correctly, correct them here
			html = html.replace(/<strong([ \>])/gi, '<b$1' );
			html = html.replace(/<\/strong>/gi, '<\/b>' );
			html = html.replace(/<em([ \>])/gi, '<i$1' );
			html = html.replace(/<\/em>/gi, '<\/i>' );
			return html;
		}
	},
	"html",
	function(){
		// summary:
		//		Constructor for this widget, initialize per-instance variables

		// Array: pre content filter function register array
		this.contentPreFilters = [];
		// Array: post content filter function register array
		this.contentPostFilters = [];
		// Array: pre content dom filter function register array
		this.contentDomPreFilters = [];
		// Array: post content dom filter function register array
		this.contentDomPostFilters = [];
		// String: semicolon (";") separated list of css files for the editing area
		this.styleSheets = "";
		// Array: array to store all the stylesheets applied to the editing area
		this.editingAreaStyleSheets=[];
		if(dojo.render.html.moz){
			this.contentPreFilters.push(this._fixContentForMoz);
		}

		this._keyHandlers = {};
	}
);

__CPAN_FILE__ src/widget/TreeContextMenu.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/



dojo.provide("dojo.widget.TreeContextMenu");

dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.Menu2");


dojo.widget.defineWidget("dojo.widget.TreeContextMenu", dojo.widget.PopupMenu2, function() {
	this.listenedTrees = [];
},
{
	open: function(x, y, parentMenu, explodeSrc){

		var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);

		/* publish many events here about structural changes */
		dojo.event.topic.publish(this.eventNames.open, { menu:this });

		return result;
	},

	listenTree: function(tree) {
		/* add context menu to all nodes that exist already */
		var nodes = tree.getDescendants();

		for(var i=0; i<nodes.length; i++) {
			if (!nodes[i].isTreeNode) continue;
			this.bindDomNode(nodes[i].labelNode);
		}


		/* bind context menu to all nodes that will be created in the future (e.g loaded from server)*/
		var _this = this;
		dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
		dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
		dojo.event.topic.subscribe(tree.eventNames.moveTo, this, "onMoveTo");
		dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
		dojo.event.topic.subscribe(tree.eventNames.addChild, this, "onAddChild");
		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");

		this.listenedTrees.push(tree);

	},

	unlistenTree: function(tree) {
		/* clear event listeners */

		dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
		dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
		dojo.event.topic.unsubscribe(tree.eventNames.moveTo, this, "onMoveTo");
		dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
		dojo.event.topic.unsubscribe(tree.eventNames.addChild, this, "onAddChild");
		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");

		for(var i=0; i<this.listenedTrees.length; i++){
           if(this.listenedTrees[i] === tree){
                   this.listenedTrees.splice(i, 1);
                   break;
           }
		}
	},

	onTreeDestroy: function(message) {
		this.unlistenTree(message.source);
	},

	bindTreeNode: function(node) {
		var _this = this;
		//dojo.debug("bind to "+node);
		dojo.lang.forEach(node.getDescendants(),
			function(e) {_this.bindDomNode(e.labelNode); }
		);
	},


	unBindTreeNode: function(node) {
		var _this = this;
		//dojo.debug("Unbind from "+node);
		dojo.lang.forEach(node.getDescendants(),
			function(e) {_this.unBindDomNode(e.labelNode); }
		);
	},

	onCreateDOMNode: function(message) {
		this.bindTreeNode(message.source);
	},


	onMoveFrom: function(message) {
		if (!dojo.lang.inArray(this.listenedTrees, message.newTree)) {
			this.unBindTreeNode(message.child);
		}
	},

	onMoveTo: function(message) {
		if (dojo.lang.inArray(this.listenedTrees, message.newTree)) {
			this.bindTreeNode(message.child);
		}
	},

	onRemoveNode: function(message) {
		this.unBindTreeNode(message.child);
	},

	onAddChild: function(message) {
		if (message.domNodeInitialized) {
			// dom node was there already => I did not process onNodeDomCreate
			this.bindTreeNode(message.child);
		}
	}


});

dojo.widget.defineWidget("dojo.widget.TreeMenuItem", dojo.widget.MenuItem2, {
	// treeActions menu item performs following actions (to be checked for permissions)
	treeActions: "",

	initialize: function(args, frag) {

		this.treeActions = this.treeActions.split(",");
		for(var i=0; i<this.treeActions.length; i++) {
			this.treeActions[i] = this.treeActions[i].toUpperCase();
		}

	},

	getTreeNode: function() {
		var menu = this;

		while (! (menu instanceof dojo.widget.TreeContextMenu) ) {
			menu = menu.parent;
		}

		var source = menu.getTopOpenEvent().target;

		while (!source.getAttribute('treeNode') && source.tagName != 'body') {
			source = source.parentNode;
		}
		if (source.tagName == 'body') {
			dojo.raise("treeNode not detected");
		}
		var treeNode = dojo.widget.manager.getWidgetById(source.getAttribute('treeNode'));

		return treeNode;
	},


	menuOpen: function(message) {
		var treeNode = this.getTreeNode();

		this.setDisabled(false); // enable by default

		var _this = this;
		dojo.lang.forEach(_this.treeActions,
			function(action) {
				_this.setDisabled( treeNode.actionIsDisabled(action) );
			}
		);

	},

	toString: function() {
		return "["+this.widgetType+" node "+this.getTreeNode()+"]";
	}

});



__CPAN_FILE__ src/widget/Rounded.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Rounded");
dojo.widget.tags.addParseTreeHandler("dojo:rounded");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.html.style");
dojo.require("dojo.html.display");
dojo.require("dojo.gfx.color");

dojo.deprecated("dojo.widget.Rounded will be removed in version 0.5; you can now apply rounded corners to any block element using dojo.lfx.rounded.", "0.5");

/*
 *	The following script is derived (with permission) from curvyCorners,
 *	written by Cameron Cooke (CLA on file) and was adapted to Dojo by Brian
 *	Lucas (CLA on file)
 */

dojo.widget.defineWidget(
	"dojo.widget.Rounded",
	dojo.widget.ContentPane,
{
	isSafari: dojo.render.html.safari,

	boxMargin: "50px", // margin outside rounded corner box
	radius: 14, // radius of corners
	domNode: "",
	corners: "TR,TL,BR,BL", // corner string to render
	antiAlias: true, // false to disable anti-aliasing

	fillInTemplate: function(args, frag) {
		dojo.widget.Rounded.superclass.fillInTemplate.call(this, args, frag);

		dojo.html.insertCssFile(this.templateCssPath);

		// Magic to automatically calculate the box height/width if not supplied
		if (this.domNode.style.height<=0) {
			var minHeight = (this.radius*1)+this.domNode.clientHeight;
			this.domNode.style.height = minHeight+"px";
		}

		if (this.domNode.style.width<=0) {
			var minWidth = (this.radius*1)+this.domNode.clientWidth;
			this.domNode.style.width = minWidth+"px";
		}

		var cornersAvailable = ["TR", "TL", "BR", "BL"];
		var cornersPassed = this.corners.split(",");

		this.settings = {
			antiAlias: this.antiAlias
		};

		var setCorner = function(currentCorner) {
			var val = currentCorner.toLowerCase();
			if(dojo.lang.inArray(cornersPassed, currentCorner)) {
				this.settings[val] = { radius: this.radius, enabled: true };
			} else {
				this.settings[val] = { radius: 0 }
			}
		}
		dojo.lang.forEach(cornersAvailable, setCorner, this);

		this.domNode.style.margin = this.boxMargin;
		this.curvyCorners(this.settings);
		this.applyCorners();
	},

	// ------------- curvyCorners OBJECT

	curvyCorners: function(settings){	

		// Setup Globals
		this.box             = this.domNode;
		this.topContainer    = null;
		this.bottomContainer = null;
		this.masterCorners   = [];

		// Get box formatting details
		var boxHeight       = dojo.html.getStyle(this.box, "height");
		if(boxHeight=="") boxHeight="0px";
		var boxWidth        = dojo.html.getStyle(this.box, "width");
		var borderWidth     = dojo.html.getStyle(this.box, "borderTopWidth");
		if(borderWidth=="") borderWidth="0px";
		//alert(borderWidth);

		var borderColour    = dojo.html.getStyle(this.box, "borderTopColor");
		// Set to true if we have a border
		if(borderWidth>0) this.antiAlias=true;

		var boxColour       = dojo.html.getStyle(this.box, "backgroundColor");
		var backgroundImage = dojo.html.getStyle(this.box, "backgroundImage");
		var boxPosition     = dojo.html.getStyle(this.box, "position");

		// Set formatting propertes
		this.boxHeight       = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight));
		this.boxWidth        = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth));
		this.borderWidth     = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0));

		// DEBUG ME?

		//dojo.debug(this.rgb2Hex(boxColour));
		var test  = new dojo.gfx.color.Color(boxColour);
		//dojo.debug(test.toHex()); 

		this.boxColour       = ((boxColour != "" && boxColour != "transparent")? ((boxColour.substr(0, 3) == "rgb")? this.rgb2Hex(boxColour) : boxColour) : "#ffffff");
		this.borderColour    = ((borderColour != "" && borderColour != "transparent" && this.borderWidth > 0)? ((borderColour.substr(0, 3) == "rgb")? this.rgb2Hex(borderColour)  : borderColour) : this.boxColour);
		this.borderString    = this.borderWidth + "px" + " solid " + this.borderColour;
		this.backgroundImage = ((backgroundImage != "none")? backgroundImage : "");

		// Make box relative if not already absolute
		if(boxPosition != "absolute") this.box.style.position = "relative";

		//This method creates the corners and
		//applies them to the div element.

		this.applyCorners = function() {
			// Create top and bottom containers.
			// These will be used as a parent for the corners and bars.
			for(var t = 0; t < 2; t++) {
			    switch(t) {
			        // Top
			        case 0:
						// Only build top bar if a top corner is to be draw
						if(this.settings.tl.enabled || this.settings.tr.enabled ) {
							var newMainContainer = document.createElement("DIV");
			
							with(newMainContainer.style){
								width    = "100%";
								fontSize = "1px";
								overflow = "hidden";
								position = "absolute";
								//backgroundColor = "#FFFFC4";
								paddingLeft  = this.borderWidth + "px";
								paddingRight = this.borderWidth + "px";
								var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0);
								height = topMaxRadius + "px";
								top    = 0 - topMaxRadius + "px";
								left   = 0 - this.borderWidth + "px";
							}
							
							this.topContainer = this.box.appendChild(newMainContainer);
						}
			            break;
	
			        // Bottom
			        case 1:      
			            // Only build bottom bar if a top corner is to be draw
			            if(this.settings.bl.enabled || this.settings.br.enabled) {
							var newMainContainer = document.createElement("DIV");
							with(newMainContainer.style){
								width    = "100%";
								fontSize = "1px";
								overflow = "hidden";
								position = "absolute";
								//backgroundColor = "#FFFFC4";
								paddingLeft  = this.borderWidth + "px";
								paddingRight = this.borderWidth + "px";
								var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0);
								height  = botMaxRadius + "px";
								bottom  =  0 - botMaxRadius + "px";
								left    =  0 - this.borderWidth + "px";
							}
						this.bottomContainer = this.box.appendChild(newMainContainer);
			            }
		            break;
			    }
			}
	
			// Turn off current borders
			if(this.topContainer) this.box.style.borderTopWidth = "0px";
			if(this.bottomContainer) this.box.style.borderBottomWidth = "0px";
	
			// Create array of available corners
			var corners = ["tr", "tl", "br", "bl"];
		
			//Loop for each corner
	
			for(var i in corners) {
			    // Get current corner type from array
			    var cc = corners[i];

			    // Has the user requested the currentCorner be round?
			    if(!this.settings[cc]) {
			        // No
			        if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null)) {
						// We need to create a filler div to fill the space upto the next horzontal corner.
						var newCorner = document.createElement("DIV");
		
						// Setup corners properties
						newCorner.style.position = "relative";
						newCorner.style.fontSize = "1px";
						newCorner.style.overflow = "hidden";
		
						// Add background image?
						if(this.backgroundImage == "") {
							newCorner.style.backgroundColor = this.boxColour;
						} else {
							newCorner.style.backgroundImage = this.backgroundImage;
						}

			            switch(cc) {
							case "tl":
								with(newCorner.style){
									height      = topMaxRadius - this.borderWidth + "px";
									marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px";
									borderLeft  = this.borderString;
									borderTop   = this.borderString;
									left         = -this.borderWidth + "px";
								}
							break;
			
							case "tr":
								with(newCorner.style){
									height      = topMaxRadius - this.borderWidth + "px";
									marginLeft  = this.settings.tl.radius - (this.borderWidth*2) + "px";
									borderRight = this.borderString;
									borderTop   = this.borderString;
									backgroundPosition  = "-" + this.boxWidth + "px 0px";
									left         = this.borderWidth + "px";
								}
							break;
	
							case "bl":
								with(newCorner.style){
									height       = botMaxRadius - this.borderWidth + "px";
									marginRight  = this.settings.br.radius - (this.borderWidth*2) + "px";
									borderLeft   = this.borderString;
									borderBottom = this.borderString;
									left         = -this.borderWidth + "px";
								}
							break;
			
							case "br":
								with(newCorner.style){
									height       = botMaxRadius - this.borderWidth + "px";
									marginLeft   = this.settings.bl.radius - (this.borderWidth*2) + "px";
									borderRight  = this.borderString;
									borderBottom = this.borderString;
									left         = this.borderWidth + "px"
								}
							break;
			            }
			        }
			    } else {
			        /*
			        PERFORMANCE NOTE:

			        If more than one corner is requested and a corner has been already
			        created for the same radius then that corner will be used as a master and cloned.
			        The pixel bars will then be repositioned to form the new corner type.
			        All new corners start as a bottom right corner.
			        */
			        if(this.masterCorners[this.settings[cc].radius]) {
			            // Create clone of the master corner
			            var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);
			        } else {
			            // Yes, we need to create a new corner
			            var newCorner = document.createElement("DIV");
						with(newCorner.style){
							height = this.settings[cc].radius + "px";
							width  = this.settings[cc].radius + "px";
							position = "absolute";
							fontSize = "1px";
							overflow = "hidden";
						}
						// THE FOLLOWING BLOCK OF CODE CREATES A ROUNDED CORNER
						// ---------------------------------------------------- TOP
			
						// Get border radius
						var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth);
			
						// Cycle the x-axis
						for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++) {
							// Calculate the value of y1 which identifies the pixels inside the border
							if((intx +1) >= borderRadius) {
								var y1 = -1;
							} else {
								var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1);
							}
			
							// Only calculate y2 and y3 if there is a border defined
							if(borderRadius != j) {
								if((intx) >= borderRadius) {
									var y2 = -1;
								} else {
									var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2)));
								}
			
								if((intx+1) >= j) {
									var y3 = -1;
								} else {
									var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);
								}
							}

							// Calculate y4
							if((intx) >= j) {
								var y4 = -1;
							} else {
								var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2)));
							}

							// Draw bar on inside of the border with foreground colour
							if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius);
	
							// Only draw border/foreground antialiased pixels and border if there is a border defined
							if(borderRadius != j) {
								// Draw aa pixels?
								if(this.antiAlias) {
									// Cycle the y-axis
									for(var inty = (y1 + 1); inty < y2; inty++) {
										// For each of the pixels that need anti aliasing between the foreground and border colour draw single pixel divs
										if(this.backgroundImage != "") {					
											var borderFract = (this.pixelFraction(intx, inty, borderRadius) * 100);
					
											if (borderFract < 30) {
												this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);
											} else {
												this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);
											}
										} else {
											var pixelcolour = dojo.gfx.color.blend(this.boxColour, this.borderColour, this.pixelFraction(intx, inty, borderRadius));
											this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius);
										}
									}
								}

								// Draw bar for the border
								if(y3 >= y2) {
									if (y1 == -1) {
										y1 = 0;
									}
									this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, this.settings[cc].radius);
								}	
								// Set the colour for the outside curve
								var outsideColour = this.borderColour;
							} else {
								// Set the coour for the outside curve
								var outsideColour = this.boxColour;
								var y3 = y1;
							}
			
							// Draw aa pixels?
							if(this.antiAlias) {		
								// Cycle the y-axis and draw the anti aliased pixels on the
								// outside of the curve
								for(var inty = (y3 + 1); inty < y4; inty++) {
									// For each of the pixels that need anti aliasing between 
									//the foreground/border colour & background draw single pixel divs
									this.drawPixel(intx, inty, outsideColour, (this.pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);
								}
							}
			            }

			            // END OF CORNER CREATION
			            // ---------------------------------------------------- END

			            // We now need to store the current corner in the masterConers array
			            this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);
			        }
			
					//Now we have a new corner we need to reposition all the pixels unless
					//the current corner is the bottom right.
			        if(cc != "br") {	
						// Loop through all children (pixel bars)
						for(var t = 0, k = newCorner.childNodes.length; t < k; t++) {
							// Get current pixel bar
							var pixelBar = newCorner.childNodes[t];
	
							// Get current top and left properties
							var pixelBarTop    = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px")));
							var pixelBarLeft   = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px")));
							var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px")));
							
							// Reposition pixels
							if(cc == "tl" || cc == "bl") {
								pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px"; // Left
							}
							if(cc == "tr" || cc == "tl") {
								pixelBar.style.top =  this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px"; // Top
							}
							var value;
					
							switch(cc) {
								case "tr":
									value = (-1 *( Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) - (Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth))));
									pixelBar.style.backgroundPosition  = value + "px";
									
								break;
				
								case "tl":
									value = (-1 *( Math.abs((this.settings[cc].radius -pixelBarLeft -1)  - this.borderWidth) - (Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth))));
									pixelBar.style.backgroundPosition  = value + "px";

								break;
				
								case "bl":
									value = (-1 *( Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) - (Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth))));
									pixelBar.style.backgroundPosition  = value + "px";

								break;
							}
						}
					}
				}
				if(newCorner) {
					// Position the container
					switch(cc) {
						case "tl":
							if(newCorner.style.position == "absolute") newCorner.style.top  = "0px";
							if(newCorner.style.position == "absolute") newCorner.style.left = "0px";
							if(this.topContainer) this.topContainer.appendChild(newCorner);
						break;

						case "tr":
							if(newCorner.style.position == "absolute") newCorner.style.top  = "0px";
							if(newCorner.style.position == "absolute") newCorner.style.right = "0px";
							if(this.topContainer) this.topContainer.appendChild(newCorner);
						break;
		
						case "bl":
							if(newCorner.style.position == "absolute") newCorner.style.bottom  = "0px";
							if(newCorner.style.position == "absolute") newCorner.style.left = "0px";
							if(this.bottomContainer) this.bottomContainer.appendChild(newCorner);
						break;
						
						case "br":
							if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px";
							if(newCorner.style.position == "absolute") newCorner.style.right = "0px";
							if(this.bottomContainer) this.bottomContainer.appendChild(newCorner);
						break;
					}
				}
			}
			//The last thing to do is draw the rest of the filler DIVs.
			//We only need to create a filler DIVs when two corners have
			//diffrent radiuses in either the top or bottom container.
	
			// Find out which corner has the biiger radius and get the difference amount
			var radiusDiff = [];
			radiusDiff["t"] = this.settings.tl.enabled && this.settings.tr.enabled ? Math.abs(this.settings.tl.radius - this.settings.tr.radius) : 0;
			radiusDiff["b"] = this.settings.bl.enabled && this.settings.br.enabled ? Math.abs(this.settings.bl.radius - this.settings.br.radius) : 0;

			for(var z in radiusDiff) {
				if(radiusDiff[z]) {
					// Get the type of corner that is the smaller one
					var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r");

					// First we need to create a DIV for the space under the smaller corner
					var newFiller = document.createElement("DIV");
					with(newFiller.style) {
						height = radiusDiff[z] + "px";
						width  =  this.settings[smallerCornerType].radius+ "px"
						position = "absolute";
						fontSize = "1px";
						overflow = "hidden";
						backgroundColor = this.boxColour;
					}

					// Position filler
					switch(smallerCornerType) {
						case "tl":
							with(newFiller.style) {
								bottom = "0px";
								left   = "0px";
								borderLeft = this.borderString;
							}
							this.topContainer.appendChild(newFiller);
						break;
	
						case "tr":
							with(newFiller.style) {
								bottom = "0px";
								right  = "0px";
								borderRight = this.borderString;
							}
							this.topContainer.appendChild(newFiller);
						break;

						case "bl":
							with(newFiller.style) {
								top    = "0px";
								left   = "0px";
								borderLeft = this.borderString;
							}
							this.bottomContainer.appendChild(newFiller);
						break;

						case "br":
							with(newFiller.style) {
								top    = "0px";
								right  = "0px";
								borderRight = this.borderString;
							}
							this.bottomContainer.appendChild(newFiller);
						break;
					}
			    }

				// Create the bar to fill the gap between each corner horizontally
				var newFillerBar = document.createElement("DIV");
				with(newFillerBar.style) {
					position = "relative";
					fontSize = "1px";
					overflow = "hidden";
					backgroundColor = this.boxColour;
				}

				switch(z) {
					case "t":
						// Top Bar
						if(this.topContainer) {
							with(newFillerBar.style) {
								height      = topMaxRadius - this.borderWidth + "px";
								marginLeft  = this.settings.tl.radius - this.borderWidth + "px";
								marginRight = this.settings.tr.radius - this.borderWidth + "px";
								borderTop   = this.borderString;
							}
						this.topContainer.appendChild(newFillerBar);
						}
					break;

					case "b":
						if(this.bottomContainer) {
						// Bottom Bar
						with(newFillerBar.style) {
							height       = botMaxRadius - this.borderWidth + "px";
							marginLeft   = this.settings.bl.radius - this.borderWidth + "px";
							marginRight  = this.settings.br.radius - this.borderWidth + "px";
							borderBottom = this.borderString;
						}
						this.bottomContainer.appendChild(newFillerBar);
					}
					break;
				}
			}
		}

		// This function draws the pixles
		this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius) {
			// Create pixel
			var pixel = document.createElement("DIV");

			
			// Section doesn't like with (pixel.style) { DEBUG?
			pixel.style.height   = height + "px";
			pixel.style.width    = "1px";
			pixel.style.position = "absolute";
			pixel.style.fontSize = "1px";
			pixel.style.overflow = "hidden";
			
			// Dont apply background image to border pixels
			if(image == -1 && this.backgroundImage != "") {
				pixel.style.backgroundImage = this.backgroundImage;
				pixel.style.backgroundPosition  = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + cornerRadius + inty) -this.borderWidth) + "px";
			} else {
				pixel.style.backgroundColor = colour;
			}
			
			// Set opacity if the transparency is anything other than 100
			if (transAmount != 100) {
				dojo.html.setOpacity(pixel, transAmount);
			}
			// Set the pixels position
			pixel.style.top = inty + "px";
			pixel.style.left = intx + "px";
		
			newCorner.appendChild(pixel);
		}
	},

	//For a pixel cut by the line determines the fraction of the pixel on the 'inside' of the
	//line.  Returns a number between 0 and 1
	pixelFraction: function(x, y, r) {
		var pixelfraction = 0;
		
		//determine the co-ordinates of the two points on the perimeter of the pixel that the
		//circle crosses
		
		var xvalues = [];
		var yvalues = [];
		var point = 0;
		var whatsides = "";

		// x + 0 = Left
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2)));

		if ((intersect >= y) && (intersect < (y+1))) {
			whatsides = "Left";
			xvalues[point] = 0;
			yvalues[point] = intersect - y;
			point =  point + 1;
		}

		// y + 1 = Top
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2)));
		
		if ((intersect >= x) && (intersect < (x+1))) {
			whatsides = whatsides + "Top";
			xvalues[point] = intersect - x;
			yvalues[point] = 1;
			point = point + 1;
		}
		// x + 1 = Right
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2)));

		if ((intersect >= y) && (intersect < (y+1))) {
			whatsides = whatsides + "Right";
			xvalues[point] = 1;
			yvalues[point] = intersect - y;
			point =  point + 1;
		}
		// y + 0 = Bottom
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2)));

		if ((intersect >= x) && (intersect < (x+1))) {
			whatsides = whatsides + "Bottom";
			xvalues[point] = intersect - x;
			yvalues[point] = 0;
		}

	    //depending on which sides of the perimeter of the pixel the circle crosses calculate the
	    //fraction of the pixel inside the circle

		switch (whatsides) {
			case "LeftRight":
				pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2);
			break;
			
			case "TopRight":
				pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2);
			break;
			
			case "TopBottom":
				pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2);
			break;
			
			case "LeftBottom":
				pixelfraction = (yvalues[0]*xvalues[1])/2;
			break;
			
			default:
				pixelfraction = 1;
	    }
	    return pixelfraction;
	},

	// This function converts CSS rgb(x, x, x) to hexadecimal
	rgb2Hex: function (rgbColour) {
		try{	
			// Get array of RGB values
			var rgbArray = this.rgb2Array(rgbColour);
			
			// Get RGB values
			var red   = parseInt(rgbArray[0]);
			var green = parseInt(rgbArray[1]);
			var blue  = parseInt(rgbArray[2]);
			
			// Build hex colour code
			var hexColour = "#" + this.intToHex(red) + this.intToHex(green) + this.intToHex(blue);
		}
		catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");
		}
		return hexColour;
	},

	//Converts a number to hexadecimal format

	intToHex: function (strNum) {
		var base = strNum / 16;
		var rem = strNum % 16;
		var base = base - (rem / 16);
		var baseS = this.makeHex(base);
		var remS = this.makeHex(rem);
		return baseS + '' + remS;
	},
	//gets the hex bits of a number

	makeHex: function(x) {
		if((x >= 0) && (x <= 9)) {
			return x;
		} else {
			switch(x) {
				case 10: return "A";
				case 11: return "B";
				case 12: return "C";
				case 13: return "D";
				case 14: return "E";
				case 15: return "F";
			}
		}
	},

	// Returns an array of rbg values
	rgb2Array: function(rgbColour) {
		// Remove rgb()
		var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")"));
	
		// Split RGB into array
		var rgbArray = rgbValues.split(", ");
		return rgbArray;
	}
}); // end function

__CPAN_FILE__ src/widget/IntegerTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.IntegerTextbox");

dojo.require("dojo.widget.ValidationTextbox");
dojo.require("dojo.validate.common");

/*
  ****** IntegerTextbox ******

  A subclass of ValidationTextbox.
  Over-rides isValid/isInRange to test for integer input.
  Has 4 new properties that can be specified as attributes in the markup.

  @attr signed     The leading plus-or-minus sign. Can be true or false, default is either.
  @attr separator  The character used as the thousands separator.  Default is no separator.
  @attr min  Minimum signed value.  Default is -Infinity
  @attr max  Maximum signed value.  Default is +Infinity
*/
dojo.widget.defineWidget(
	"dojo.widget.IntegerTextbox",
	dojo.widget.ValidationTextbox,
	{
		mixInProperties: function(localProperties, frag){
			// First initialize properties in super-class.
			dojo.widget.IntegerTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if((localProperties.signed == "true")||
				(localProperties.signed == "always")){
				this.flags.signed = true;
			}else if((localProperties.signed == "false")||
					(localProperties.signed == "never")){
				this.flags.signed = false;
				this.flags.min = 0;
			}else{
				this.flags.signed = [ true, false ]; // optional
			}
			if(localProperties.separator){ 
				this.flags.separator = localProperties.separator;
			}
			if(localProperties.min){ 
				this.flags.min = parseInt(localProperties.min);
			}
			if(localProperties.max){ 
				this.flags.max = parseInt(localProperties.max);
			}
		},

		// Over-ride for integer validation
		isValid: function(){
			return dojo.validate.isInteger(this.textbox.value, this.flags);
		},
		isInRange: function(){
			return dojo.validate.isInRange(this.textbox.value, this.flags);
		}
	}
);

__CPAN_FILE__ src/widget/Checkbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Checkbox");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.event.*");
dojo.require("dojo.html.style");
dojo.require("dojo.html.selection");

// summary
//	Same as an HTML checkbox, but with fancy styling
dojo.widget.defineWidget(
	"dojo.widget.Checkbox",
	dojo.widget.HtmlWidget,
	{
		templatePath: dojo.uri.dojoUri('src/widget/templates/Checkbox.html'),
		templateCssPath: dojo.uri.dojoUri('src/widget/templates/Checkbox.css'),

		// Boolean
		//	if true, clicking will not change the state of the checkbox.
		//	in markup, this is specified as "disabled='disabled'", or just "disabled", 
		disabled: false,
		
		// String
		//	name used when submitting form; same as "name" attribute or plain HTML elements
		name: "",

		// String
		//	id attached to the checkbox, used when submitting form
		id: "",

		// Boolean
		//	if true, checkbox is initially marked turned on;
		//	in markup, specified as "checked='checked'" or just "checked"
		checked: false,
		
		// Integer
		//	order fields are traversed when user hits the tab key
		tabIndex: "",

		// Value
		//	equivalent to value field on normal checkbox (if checked, the value is passed as
		//	the value when form is submitted)
		value: "on",

		postMixInProperties: function(){
			dojo.widget.Checkbox.superclass.postMixInProperties.apply(this, arguments);
			
			// set tabIndex="0" because if tabIndex=="" user won't be able to tab to the field
			if(!this.disabled && this.tabIndex==""){ this.tabIndex="0"; }
		},

		fillInTemplate: function(){
			this._setInfo();
		},

		postCreate: function(){
			// find any associated label and create a labelled-by relationship
			// assumes <label for="inputId">label text </label> rather than
			// <label><input type="xyzzy">label text</label>
			var notcon = true;
			this.id = this.id !="" ? this.id : this.widgetId;
			if(this.id != ""){
				var labels = document.getElementsByTagName("label");
				if (labels != null && labels.length > 0){
					for(var i=0; i<labels.length; i++){
						if (labels[i].htmlFor == this.id){
							labels[i].id = (labels[i].htmlFor + "label");
							this._connectEvents(labels[i]);
							dojo.widget.wai.setAttr(this.domNode, "waiState", "labelledby", labels[i].id);
							break;
						}
					}
				}
			}
			this._connectEvents(this.domNode);
			// this is needed here for IE
			this.inputNode.checked=this.checked;
		},

		_connectEvents: function(/*DomNode*/ node){
			dojo.event.connect(node, "onmouseover", this, "mouseOver");
			dojo.event.connect(node, "onmouseout", this, "mouseOut");
			dojo.event.connect(node, "onkey", this, "onKey");
			dojo.event.connect(node, "onclick", this, "_onClick");
			dojo.html.disableSelection(node);
		},

		_onClick: function(/*Event*/ e){
			if(this.disabled == false){
				this.checked = !this.checked;
				this._setInfo();
			}
			e.preventDefault();
			e.stopPropagation();
			this.onClick();
		},

		onClick: function(){
			// summary: user overridable callback function for checkbox being clicked
		},

		onKey: function(/*Event*/ e){
			// summary: callback when user hits a key
			var k = dojo.event.browser.keys;
			if(e.key == " "){
	 			this._onClick(e);
	 		}
		},

		mouseOver: function(/*Event*/ e){
			// summary: callback when user moves mouse over checkbox
			this._hover(e, true);
		},

		mouseOut: function(/*Event*/ e){
			// summary: callback when user moves mouse off of checkbox
			this._hover(e, false);
		},

		_hover: function(/*Event*/ e, /*Boolean*/ isOver){
			if (this.disabled == false){
				var state = this.checked ? "On" : "Off";
				var style = "dojoHtmlCheckbox" + state + "Hover";
				if (isOver){
					dojo.html.addClass(this.imageNode, style);
				}else{
					dojo.html.removeClass(this.imageNode,style);
				}
			}
		},

		_setInfo: function(){
			// summary:
			//	set state of hidden checkbox node to correspond to displayed value.
			//	also set CSS class string according to checked/unchecked and disabled/enabled state
			var state = "dojoHtmlCheckbox" + (this.disabled ? "Disabled" : "") + (this.checked ? "On" : "Off");
			dojo.html.setClass(this.imageNode, "dojoHtmlCheckbox " + state);
			this.inputNode.checked = this.checked;
			if(this.disabled){
				this.inputNode.setAttribute("disabled",true);
			}else{
				this.inputNode.removeAttribute("disabled");
			}
			dojo.widget.wai.setAttr(this.domNode, "waiState", "checked", this.checked);
		}
	}
);

// summary
//	variation on Checkbox widget to be display on monitors in high-contrast mode (that don't display CSS background images)
dojo.widget.defineWidget(
	"dojo.widget.a11y.Checkbox",
	dojo.widget.Checkbox,
	{
		templatePath: dojo.uri.dojoUri('src/widget/templates/CheckboxA11y.html'),

		fillInTemplate: function(){
		},

		postCreate: function(args, frag){
			this.inputNode.checked=this.checked;
			//only set disabled if true since FF interprets any value for disabled as true
			if (this.disabled){
				this.inputNode.setAttribute("disabled",true);
			} 
		},

		_onClick: function(){
			this.onClick();
		}
	}
);
__CPAN_FILE__ src/widget/Editor.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/* TODO:
 * - font selector
 * - test, bug fix, more features :)
*/
dojo.provide("dojo.widget.Editor");
dojo.deprecated("dojo.widget.Editor", "is replaced by dojo.widget.Editor2", "0.5");

dojo.require("dojo.io.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Toolbar");
dojo.require("dojo.widget.RichText");
dojo.require("dojo.widget.ColorPalette");
dojo.require("dojo.string.extras");

dojo.widget.tags.addParseTreeHandler("dojo:Editor");

dojo.widget.Editor = function() {
	dojo.widget.HtmlWidget.call(this);
	this.contentFilters = [];
	this._toolbars = [];
}
dojo.inherits(dojo.widget.Editor, dojo.widget.HtmlWidget);

dojo.widget.Editor.itemGroups = {
	textGroup: ["bold", "italic", "underline", "strikethrough"],
	blockGroup: ["formatBlock", "fontName", "fontSize"],
	justifyGroup: ["justifyleft", "justifycenter", "justifyright"],
	commandGroup: ["save", "cancel"],
	colorGroup: ["forecolor", "hilitecolor"],
	listGroup: ["insertorderedlist", "insertunorderedlist"],
	indentGroup: ["outdent", "indent"],
	linkGroup: ["createlink", "insertimage", "inserthorizontalrule"]
};

dojo.widget.Editor.formatBlockValues = {
	"Normal": "p",
	"Main heading": "h2",
	"Sub heading": "h3",
	"Sub sub heading": "h4",
	"Preformatted": "pre"
};

dojo.widget.Editor.fontNameValues = {
	"Arial": "Arial, Helvetica, sans-serif",
	"Verdana": "Verdana, sans-serif",
	"Times New Roman": "Times New Roman, serif",
	"Courier": "Courier New, monospace"
};

dojo.widget.Editor.fontSizeValues = {
	"1 (8 pt)" : "1",
	"2 (10 pt)": "2",
	"3 (12 pt)": "3",
	"4 (14 pt)": "4",
	"5 (18 pt)": "5",
	"6 (24 pt)": "6",
	"7 (36 pt)": "7"
};

dojo.widget.Editor.defaultItems = [
	"commandGroup", "|", "blockGroup", "|", "textGroup", "|", "colorGroup", "|", "justifyGroup", "|", "listGroup", "indentGroup", "|", "linkGroup"
];

// ones we support by default without asking the RichText component
// NOTE: you shouldn't put buttons like bold, italic, etc in here
dojo.widget.Editor.supportedCommands = ["save", "cancel", "|", "-", "/", " "];

dojo.lang.extend(dojo.widget.Editor, {
	widgetType: "Editor",

	saveUrl: "",
	saveMethod: "post",
	saveArgName: "editorContent",
	closeOnSave: false,
	items: dojo.widget.Editor.defaultItems,
	formatBlockItems: dojo.lang.shallowCopy(dojo.widget.Editor.formatBlockValues),
	fontNameItems: dojo.lang.shallowCopy(dojo.widget.Editor.fontNameValues),
	fontSizeItems: dojo.lang.shallowCopy(dojo.widget.Editor.fontSizeValues),

	// used to get the properties of an item if it is given as a string
	getItemProperties: function(name) {
		var props = {};
		switch(name.toLowerCase()) {
			case "bold":
			case "italic":
			case "underline":
			case "strikethrough":
				props.toggleItem = true;
				break;

			case "justifygroup":
				props.defaultButton = "justifyleft";
				props.preventDeselect = true;
				props.buttonGroup = true;
				break;

			case "listgroup":
				props.buttonGroup = true;
				break;

			case "save":
			case "cancel":
				props.label = dojo.string.capitalize(name);
				break;

			case "forecolor":
			case "hilitecolor":
				props.name = name;
				props.toggleItem = true; // FIXME: they aren't exactly toggle items
				props.icon = this.getCommandImage(name);
				break;

			case "formatblock":
				props.name = "formatBlock";
				props.values = this.formatBlockItems;
				break;

			case "fontname":
				props.name = "fontName";
				props.values = this.fontNameItems;

			case "fontsize":
				props.name = "fontSize";
				props.values = this.fontSizeItems;
		}
		return props;
	},

	validateItems: true, // set to false to add items, regardless of support
	focusOnLoad: true,
	minHeight: "1em",

	_richText: null, // RichText widget
	_richTextType: "RichText",

	_toolbarContainer: null, // ToolbarContainer widget
	_toolbarContainerType: "ToolbarContainer",

	_toolbars: [],
	_toolbarType: "Toolbar",

	_toolbarItemType: "ToolbarItem",

	buildRendering: function(args, frag) {
		// get the node from args/frag
		var node = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
		var trt = dojo.widget.createWidget(this._richTextType, {
			focusOnLoad: this.focusOnLoad,
			minHeight: this.minHeight
		}, node)
		var _this = this;
		// this appears to fix a weird timing bug on Safari
		setTimeout(function(){
			_this.setRichText(trt);

			_this.initToolbar();

			_this.fillInTemplate(args, frag);
		}, 0);
	},

	setRichText: function(richText) {
		if(this._richText && this._richText == richText) {
			dojo.debug("Already set the richText to this richText!");
			return;
		}

		if(this._richText && !this._richText.isClosed) {
			dojo.debug("You are switching richTexts yet you haven't closed the current one. Losing reference!");
		}
		this._richText = richText;
		dojo.event.connect(this._richText, "close", this, "onClose");
		dojo.event.connect(this._richText, "onLoad", this, "onLoad");
		dojo.event.connect(this._richText, "onDisplayChanged", this, "updateToolbar");
		if(this._toolbarContainer) {
			this._toolbarContainer.enable();
			this.updateToolbar(true);
		}
	},

	initToolbar: function() {
		// var tic = new Date();
		if(this._toolbarContainer) { return; } // only create it once
		this._toolbarContainer = dojo.widget.createWidget(this._toolbarContainerType);
		var tb = this.addToolbar();
		var last = true;
		for(var i = 0; i < this.items.length; i++) {
			if(this.items[i] == "\n") { // new row
				tb = this.addToolbar();
			} else {
				if((this.items[i] == "|")&&(!last)){
					last = true;
				}else{
					last = this.addItem(this.items[i], tb);
				}
			}
		}
		this.insertToolbar(this._toolbarContainer.domNode, this._richText.domNode);
		// alert(new Date - tic);
	},

	// allow people to override this so they can make their own placement logic
	insertToolbar: function(tbNode, richTextNode) {
		dojo.html.insertBefore(tbNode, richTextNode);
		//dojo.html.insertBefore(this._toolbarContainer.domNode, this._richText.domNode);
	},

	addToolbar: function(toolbar) {
		this.initToolbar();
		if(!(toolbar instanceof dojo.widget.Toolbar)) {
			toolbar = dojo.widget.createWidget(this._toolbarType);
		}
		this._toolbarContainer.addChild(toolbar);
		this._toolbars.push(toolbar);
		return toolbar;
	},

	addItem: function(item, tb, dontValidate) {
		if(!tb) { tb = this._toolbars[0]; }
		var cmd = ((item)&&(!dojo.lang.isUndefined(item["getValue"]))) ?  cmd = item["getValue"](): item;

		var groups = dojo.widget.Editor.itemGroups;
		if(item instanceof dojo.widget.ToolbarItem) {
			tb.addChild(item);
		} else if(groups[cmd]) {
			var group = groups[cmd];
			var worked = true;
			if(cmd == "justifyGroup" || cmd == "listGroup") {
				var btnGroup = [cmd];
				for(var i = 0 ; i < group.length; i++) {
					if(dontValidate || this.isSupportedCommand(group[i])) {
						btnGroup.push(this.getCommandImage(group[i]));
					}else{
						worked = false;
					}
				}
				if(btnGroup.length){
					/*
					// the addChild interface is assinine. Work around it.
					var tprops = this.getItemProperties(cmd);
					var tmpGroup = dojo.widget.createWidget("ToolbarButtonGroup", tprops);
					dojo.debug(btnGroup);
					dojo.event.connect(tmpGroup, "onClick", this, "_action");
					dojo.event.connect(tmpGroup, "onChangeSelect", this, "_action");
					*/
					var btn = tb.addChild(btnGroup, null, this.getItemProperties(cmd));
					dojo.event.connect(btn, "onClick", this, "_action");
					dojo.event.connect(btn, "onChangeSelect", this, "_action");
				}
				return worked;
			} else {
				for(var i = 0; i < group.length; i++) {
					if(!this.addItem(group[i], tb)){
						worked = false;
					}
				}
				return worked;
			}
		} else {
			if((!dontValidate)&&(!this.isSupportedCommand(cmd))){
				return false;
			}
			if(dontValidate || this.isSupportedCommand(cmd)) {
				cmd = cmd.toLowerCase();
				if(cmd == "formatblock") {
					var select = dojo.widget.createWidget("ToolbarSelect", {
						name: "formatBlock",
						values: this.formatBlockItems
					});
					tb.addChild(select);
					var _this = this;
					dojo.event.connect(select, "onSetValue", function(item, value) {
						_this.onAction("formatBlock", value);
					});
				} else if(cmd == "fontname") {
					var select = dojo.widget.createWidget("ToolbarSelect", {
						name: "fontName",
						values: this.fontNameItems
					});
					tb.addChild(select);
					dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
						this.onAction("fontName", value);
					}));
				} else if(cmd == "fontsize") {
					var select = dojo.widget.createWidget("ToolbarSelect", {
						name: "fontSize",
						values: this.fontSizeItems
					});
					tb.addChild(select);
					dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
						this.onAction("fontSize", value);
					}));
				} else if(dojo.lang.inArray(cmd, ["forecolor", "hilitecolor"])) {
					var btn = tb.addChild(dojo.widget.createWidget("ToolbarColorDialog", this.getItemProperties(cmd)));
					dojo.event.connect(btn, "onSetValue", this, "_setValue");
				} else {
					var btn = tb.addChild(this.getCommandImage(cmd), null, this.getItemProperties(cmd));
					if(cmd == "save"){
						dojo.event.connect(btn, "onClick", this, "_save");
					}else if(cmd == "cancel"){
						dojo.event.connect(btn, "onClick", this, "_close");
					} else {
						dojo.event.connect(btn, "onClick", this, "_action");
						dojo.event.connect(btn, "onChangeSelect", this, "_action");
					}
				}
			}
		}
		return true;
	},

	enableToolbar: function() {
		if(this._toolbarContainer) {
			this._toolbarContainer.domNode.style.display = "";
			this._toolbarContainer.enable();
		}
	},

	disableToolbar: function(hide){
		if(hide){
			if(this._toolbarContainer){
				this._toolbarContainer.domNode.style.display = "none";
			}
		}else{
			if(this._toolbarContainer){
				this._toolbarContainer.disable();
			}
		}
	},

	_updateToolbarLastRan: null,
	_updateToolbarTimer: null,
	_updateToolbarFrequency: 500,

	updateToolbar: function(force) {
		if(!this._toolbarContainer) { return; }

		// keeps the toolbar from updating too frequently
		// TODO: generalize this functionality?
		var diff = new Date() - this._updateToolbarLastRan;
		if(!force && this._updateToolbarLastRan && (diff < this._updateToolbarFrequency)) {
			clearTimeout(this._updateToolbarTimer);
			var _this = this;
			this._updateToolbarTimer = setTimeout(function() {
				_this.updateToolbar();
			}, this._updateToolbarFrequency/2);
			return;
		} else {
			this._updateToolbarLastRan = new Date();
		}
		// end frequency checker

		var items = this._toolbarContainer.getItems();
		for(var i = 0; i < items.length; i++) {
			var item = items[i];
			if(item instanceof dojo.widget.ToolbarSeparator) { continue; }
			var cmd = item._name;
			if (cmd == "save" || cmd == "cancel") { continue; }
			else if(cmd == "justifyGroup") {
				try {
					if(!this._richText.queryCommandEnabled("justifyleft")) {
						item.disable(false, true);
					} else {
						item.enable(false, true);
						var jitems = item.getItems();
						for(var j = 0; j < jitems.length; j++) {
							var name = jitems[j]._name;
							var value = this._richText.queryCommandValue(name);
							if(typeof value == "boolean" && value) {
								value = name;
								break;
							} else if(typeof value == "string") {
								value = "justify"+value;
							} else {
								value = null;
							}
						}
						if(!value) { value = "justifyleft"; } // TODO: query actual style
						item.setValue(value, false, true);
					}
				} catch(err) {}
			} else if(cmd == "listGroup") {
				var litems = item.getItems();
				for(var j = 0; j < litems.length; j++) {
					this.updateItem(litems[j]);
				}
			} else {
				this.updateItem(item);
			}
		}
	},

	updateItem: function(item) {
		try {
			var cmd = item._name;
			var enabled = this._richText.queryCommandEnabled(cmd);
			item.setEnabled(enabled, false, true);

			var active = this._richText.queryCommandState(cmd);
			if(active && cmd == "underline") {
				// don't activate underlining if we are on a link
				active = !this._richText.queryCommandEnabled("unlink");
			}
			item.setSelected(active, false, true);
			return true;
		} catch(err) {
			return false;
		}
	},

	supportedCommands: dojo.widget.Editor.supportedCommands.concat(),

	isSupportedCommand: function(cmd) {
		// FIXME: how do we check for ActiveX?
		var yes = dojo.lang.inArray(cmd, this.supportedCommands);
		if(!yes) {
			try {
				var richText = this._richText || dojo.widget.HtmlRichText.prototype;
				yes = richText.queryCommandAvailable(cmd);
			} catch(E) {}
		}
		return yes;
	},

	getCommandImage: function(cmd) {
		if(cmd == "|") {
			return cmd;
		} else {
			return dojo.uri.dojoUri("src/widget/templates/buttons/" + cmd + ".gif");
		}
	},

	_action: function(e) {
		this._fire("onAction", e.getValue());
	},

	_setValue: function(a, b) {
		this._fire("onAction", a.getValue(), b);
	},

	_save: function(e){
		// FIXME: how should this behave when there's a larger form in play?
		if(!this._richText.isClosed){
			if(this.saveUrl.length){
				var content = {};
				content[this.saveArgName] = this.getHtml();
				dojo.io.bind({
					method: this.saveMethod,
					url: this.saveUrl,
					content: content
				});
			}else{
				dojo.debug("please set a saveUrl for the editor");
			}
			if(this.closeOnSave){
				this._richText.close(e.getName().toLowerCase() == "save");
			}
		}
	},

	_close: function(e) {
		if(!this._richText.isClosed) {
			this._richText.close(e.getName().toLowerCase() == "save");
		}
	},

	onAction: function(cmd, value) {
		switch(cmd) {
			case "createlink":
				if(!(value = prompt("Please enter the URL of the link:", "http://"))) {
					return;
				}
				break;
			case "insertimage":
				if(!(value = prompt("Please enter the URL of the image:", "http://"))) {
					return;
				}
				break;
		}
		this._richText.execCommand(cmd, value);
	},

	fillInTemplate: function(args, frag) {
		// dojo.event.connect(this, "onResized", this._richText, "onResized");
	},

	_fire: function(eventName) {
		if(dojo.lang.isFunction(this[eventName])) {
			var args = [];
			if(arguments.length == 1) {
				args.push(this);
			} else {
				for(var i = 1; i < arguments.length; i++) {
					args.push(arguments[i]);
				}
			}
			this[eventName].apply(this, args);
		}
	},

	getHtml: function(){
		this._richText.contentFilters = this._richText.contentFilters.concat(this.contentFilters);
		return this._richText.getEditorContent();
	},

	getEditorContent: function(){
		return this.getHtml();
	},

	onClose: function(save, hide){
		this.disableToolbar(hide);
		if(save) {
			this._fire("onSave");
		} else {
			this._fire("onCancel");
		}
	},

	// events baby!
	onLoad: function(){},
	onSave: function(){},
	onCancel: function(){}
});


__CPAN_FILE__ src/widget/PopupContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.PopupContainer");

dojo.require("dojo.html.style");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.selection");
dojo.require("dojo.html.iframe");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

// summary:
//		PopupContainerBase is the mixin class which provide popup behaviors:
//		it can open in a given position x,y or around a given node.
//		In addition, it handles animation and IE bleed through workaround.
// description:
//		This class can not be used standalone: it should be mixed-in to a
//		dojo.widget.HtmlWidget. Use PopupContainer instead if you want a
//		a standalone popup widget
dojo.declare(
	"dojo.widget.PopupContainerBase",
	null,
	function(){
		this.queueOnAnimationFinish = [];
	},
{
	isContainer: true,
	templateString: '<div dojoAttachPoint="containerNode" style="display:none;position:absolute;" class="dojoPopupContainer" ></div>',

	// Boolean: whether this popup is shown
	isShowingNow: false,

	// Widget: the shown sub popup if any
	currentSubpopup: null,

	// Int: the minimal popup zIndex
	beginZIndex: 1000,

	// Widget: parent popup widget
	parentPopup: null,
	// Widget: parent Widget
	parent: null,
	// Int: level of sub popup
	popupIndex: 0,

	// dojo.html.boxSizing: which bounding box to use for open aroundNode. By default use BORDER box of the aroundNode
	aroundBox: dojo.html.boxSizing.BORDER_BOX,

	// Object: in which window, the open() is triggered
	openedForWindow: null,

	processKey: function(/*Event*/evt){
		// summary: key event handler
		return false;
	},

	applyPopupBasicStyle: function(){
		// summary: apply necessary css rules to the top domNode
		// description:
		//		this function should be called in sub class where a custom
		//		templateString/templateStringPath is used (see Tooltip widget)
		with(this.domNode.style){
			display = 'none';
			position = 'absolute';
		}
	},

	aboutToShow: function() {
		// summary: connect to this stub to modify the content of the popup
	},

	open: function(/*Integer*/x, /*Integer*/y, /*DomNode*/parent, /*Object*/explodeSrc, /*String?*/orient, /*Array?*/padding){
		// summary:
		//		Open the popup at position (x,y), relative to dojo.body()
	 	//		Or open(node, parent, explodeSrc, aroundOrient) to open
	 	//		around node
		if (this.isShowingNow){ return; }

		this.aboutToShow();

		// if I click right button and menu is opened, then it gets 2 commands: close -> open
		// so close enables animation and next "open" is put to queue to occur at new location
		if(this.animationInProgress){
			this.queueOnAnimationFinish.push(this.open, arguments);
			return;
		}

		// save this so that the focus can be returned
		this.parent = parent;

		var around = false, node, aroundOrient;
		if(typeof x == 'object'){
			node = x;
			aroundOrient = explodeSrc;
			explodeSrc = parent;
			parent = y;
			around = true;
		}

		// for unknown reasons even if the domNode is attached to the body in postCreate(),
		// it's not attached here, so have to attach it here.
		dojo.body().appendChild(this.domNode);

		// if explodeSrc isn't specified then explode from my parent widget
		explodeSrc = explodeSrc || parent["domNode"] || [];

		//keep track of parent popup to decided whether this is a top level popup
		var parentPopup = null;
		this.isTopLevel = true;
		while(parent){
			if(parent !== this && (parent.setOpenedSubpopup != undefined && parent.applyPopupBasicStyle != undefined)){
				parentPopup = parent;
				this.isTopLevel = false;
				parentPopup.setOpenedSubpopup(this);
				break;
			}
			parent = parent.parent;
		}

		this.parentPopup = parentPopup;
		this.popupIndex = parentPopup ? parentPopup.popupIndex + 1 : 1;

		if(this.isTopLevel){
			var button = dojo.html.isNode(explodeSrc) ? explodeSrc : null;
			dojo.widget.PopupManager.opened(this, button);
		}

		//Store the current selection and restore it before the action for a menu item
		//is executed. This is required as clicking on an menu item deselects current selection
		if(this.isTopLevel && !dojo.withGlobal(this.openedForWindow||dojo.global(), dojo.html.selection.isCollapsed)){
			this._bookmark = dojo.withGlobal(this.openedForWindow||dojo.global(), dojo.html.selection.getBookmark);
		}else{
			this._bookmark = null;
		}

		//convert explodeSrc from format [x, y] to
		//{left: x, top: y, width: 0, height: 0} which is the new
		//format required by dojo.html.toCoordinateObject
		if(explodeSrc instanceof Array){
			explodeSrc = {left: explodeSrc[0], top: explodeSrc[1], width: 0, height: 0};
		}

		// display temporarily, and move into position, then hide again
		with(this.domNode.style){
			display="";
			zIndex = this.beginZIndex + this.popupIndex;
		}

		if(around){
			this.move(node, padding, aroundOrient);
		}else{
			this.move(x, y, padding, orient);
		}
		this.domNode.style.display="none";

		this.explodeSrc = explodeSrc;

		// then use the user defined method to display it
		this.show();

		this.isShowingNow = true;
	},

	// TODOC: move(node, padding, aroundOrient) how to do this?
	move: function(/*Int*/x, /*Int*/y, /*Integer?*/padding, /*String?*/orient){
		// summary: calculate where to place the popup

		var around = (typeof x == "object");
		if(around){
			var aroundOrient=padding;
			var node=x;
			padding=y;
			if(!aroundOrient){ //By default, attempt to open above the aroundNode, or below
				aroundOrient = {'BL': 'TL', 'TL': 'BL'};
			}
			dojo.html.placeOnScreenAroundElement(this.domNode, node, padding, this.aroundBox, aroundOrient);
		}else{
			if(!orient){ orient = 'TL,TR,BL,BR';}
			dojo.html.placeOnScreen(this.domNode, x, y, padding, true, orient);
		}
	},

	close: function(/*Boolean?*/force){
		// summary: hide the popup
		if(force){
			this.domNode.style.display="none";
		}

		// If we are in the process of opening the menu and we are asked to close it
		if(this.animationInProgress){
			this.queueOnAnimationFinish.push(this.close, []);
			return;
		}

		this.closeSubpopup(force);
		this.hide();
		if(this.bgIframe){
			this.bgIframe.hide();
			this.bgIframe.size({left: 0, top: 0, width: 0, height: 0});
		}
		if(this.isTopLevel){
			dojo.widget.PopupManager.closed(this);
		}
		this.isShowingNow = false;
		// return focus to the widget that opened the menu
		try {
			this.parent.domNode.focus();
		} catch(e) {}

		//do not need to restore if current selection is not empty
		//(use keyboard to select a menu item)
		if(this._bookmark && dojo.withGlobal(this.openedForWindow||dojo.global(), dojo.html.selection.isCollapsed)){
			if(this.openedForWindow){
				this.openedForWindow.focus()
			}
			dojo.withGlobal(this.openedForWindow||dojo.global(), "moveToBookmark", dojo.html.selection, [this._bookmark]);
		}
		this._bookmark = null;
	},

	closeAll: function(/*Boolean?*/force){
		// summary: hide all popups including sub ones
		if (this.parentPopup){
			this.parentPopup.closeAll(force);
		}else{
			this.close(force);
		}
	},

	setOpenedSubpopup: function(/*Widget*/popup) {
		// summary: used by sub popup to set currentSubpopup in the parent popup
		this.currentSubpopup = popup;
	},

	closeSubpopup: function(/*Boolean?*/force) {
		// summary: close opened sub popup
		if(this.currentSubpopup == null){ return; }

		this.currentSubpopup.close(force);
		this.currentSubpopup = null;
	},

	onShow: function() {
		dojo.widget.PopupContainer.superclass.onShow.apply(this, arguments);
		// With some animation (wipe), after close, the size of the domnode is 0
		// and next time when shown, the open() function can not determine
		// the correct place to popup, so we store the opened size here and
		// set it after close (in function onHide())
		this.openedSize={w: this.domNode.style.width, h: this.domNode.style.height};
		// prevent IE bleed through
		if(dojo.render.html.ie){
			if(!this.bgIframe){
				this.bgIframe = new dojo.html.BackgroundIframe();
				this.bgIframe.setZIndex(this.domNode);
			}

			this.bgIframe.size(this.domNode);
			this.bgIframe.show();
		}
		this.processQueue();
	},

	processQueue: function() {
		// summary: do events from queue
		if (!this.queueOnAnimationFinish.length) return;

		var func = this.queueOnAnimationFinish.shift();
		var args = this.queueOnAnimationFinish.shift();

		func.apply(this, args);
	},

	onHide: function() {
		dojo.widget.HtmlWidget.prototype.onHide.call(this);

		//restore size of the domnode, see comment in
		//function onShow()
		if(this.openedSize){
			with(this.domNode.style){
				width=this.openedSize.w;
				height=this.openedSize.h;
			}
		}

		this.processQueue();
	}
});

// summary: dojo.widget.PopupContainer is the widget version of dojo.widget.PopupContainerBase
dojo.widget.defineWidget(
	"dojo.widget.PopupContainer",
	[dojo.widget.HtmlWidget, dojo.widget.PopupContainerBase], {});


// summary:
//		the popup manager makes sure we don't have several popups
//		open at once. the root popup in an opening sequence calls
//		opened(). when a root menu closes it calls closed(). then
//		everything works. lovely.
dojo.widget.PopupManager = new function(){
	this.currentMenu = null;
	this.currentButton = null;		// button that opened current menu (if any)
	this.currentFocusMenu = null;	// the (sub)menu which receives key events
	this.focusNode = null;
	this.registeredWindows = [];

	this.registerWin = function(/*Window*/win){
		// summary: register a window so that when clicks/scroll in it, the popup can be closed automatically
		if(!win.__PopupManagerRegistered)
		{
			dojo.event.connect(win.document, 'onmousedown', this, 'onClick');
			dojo.event.connect(win, "onscroll", this, "onClick");
			dojo.event.connect(win.document, "onkey", this, 'onKey');
			win.__PopupManagerRegistered = true;
			this.registeredWindows.push(win);
		}
	};

	/*

	*/
	this.registerAllWindows = function(/*Window*/targetWindow){
		// summary:
		//		This function register all the iframes and the top window,
		//		so that whereever the user clicks in the page, the popup
		//		menu will be closed
		//		In case you add an iframe after onload event, please call
		//		dojo.widget.PopupManager.registerWin manually

		//starting from window.top, clicking everywhere in this page
		//should close popup menus
		if(!targetWindow) { //see comment below
			targetWindow = dojo.html.getDocumentWindow(window.top && window.top.document || window.document);
		}

		this.registerWin(targetWindow);

		for (var i = 0; i < targetWindow.frames.length; i++){
			try{
				//do not remove  dojo.html.getDocumentWindow, see comment in it
				var win = dojo.html.getDocumentWindow(targetWindow.frames[i].document);
				if(win){
					this.registerAllWindows(win);
				}
			}catch(e){ /* squelch error for cross domain iframes */ }
		}
	};

	this.unRegisterWin = function(/*Window*/win){
		// summary: remove listeners on the registered window
		if(win.__PopupManagerRegistered)
		{
			dojo.event.disconnect(win.document, 'onmousedown', this, 'onClick');
			dojo.event.disconnect(win, "onscroll", this, "onClick");
			dojo.event.disconnect(win.document, "onkey", this, 'onKey');
			win.__PopupManagerRegistered = false;
		}
	};

	this.unRegisterAllWindows = function(){
		// summary: remove listeners on all the registered windows
		for(var i=0;i<this.registeredWindows.length;++i){
			this.unRegisterWin(this.registeredWindows[i]);
		}
		this.registeredWindows = [];
	};

	dojo.addOnLoad(this, "registerAllWindows");
	dojo.addOnUnload(this, "unRegisterAllWindows");

	this.closed = function(/*Widget*/menu){
		// summary: notify the manager that menu is closed
		if (this.currentMenu == menu){
			this.currentMenu = null;
			this.currentButton = null;
			this.currentFocusMenu = null;
		}
	};

	this.opened = function(/*Widget*/menu, /*DomNode*/button){
		// summary: sets the current opened popup
		if (menu == this.currentMenu){ return; }

		if (this.currentMenu){
			this.currentMenu.close();
		}

		this.currentMenu = menu;
		this.currentFocusMenu = menu;
		this.currentButton = button;
	};

	this.setFocusedMenu = function(/*Widget*/menu){
		// summary:
		// 		Set the current focused popup, This is used by popups which supports keyboard navigation
		this.currentFocusMenu = menu;
	};

	this.onKey = function(/*Event*/e){
		if (!e.key) { return; }
		if(!this.currentMenu || !this.currentMenu.isShowingNow){ return; }

		var m = this.currentFocusMenu;
		while (m){
			if(m.processKey(e)){
				e.preventDefault();
				e.stopPropagation();
				break;
			}
			m = m.parentPopup;
		}
	},

	this.onClick = function(/*Event*/e){
		if (!this.currentMenu){ return; }

		var scrolloffset = dojo.html.getScroll().offset;

		// starting from the base menu, perform a hit test
		// and exit when one succeeds

		var m = this.currentMenu;

		while (m){
			if(dojo.html.overElement(m.domNode, e) || dojo.html.isDescendantOf(e.target, m.domNode)){
				return;
			}
			m = m.currentSubpopup;
		}

		// Also, if user clicked the button that opened this menu, then
		// that button will send the menu a close() command, so this code
		// shouldn't try to close the menu.  Closing twice messes up animation.
		if (this.currentButton && dojo.html.overElement(this.currentButton, e)){
			return;
		}

		// the click didn't fall within the open menu tree
		// so close it

		this.currentMenu.close();
	};
}
__CPAN_FILE__ src/widget/Dialog.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Dialog");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.event.*");
dojo.require("dojo.gfx.color");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.display");
dojo.require("dojo.html.iframe");

// summary
//	Mixin for widgets implementing a modal dialog
dojo.declare(
	"dojo.widget.ModalDialogBase", 
	null,
	{
		isContainer: true,

		// static variables
		shared: {bg: null, bgIframe: null},

		// String
		//	provide a focusable element or element id if you need to
		//	work around FF's tendency to send focus into outer space on hide
		focusElement: "",

		// String
		//	color of viewport when displaying a dialog
		bgColor: "black",
		
		// Number
		//	opacity (0~1) of viewport color (see bgColor attribute)
		bgOpacity: 0.4,

		// Boolean
		//	if true, readjusts the dialog (and dialog background) when the user moves the scrollbar
		followScroll: true,

		trapTabs: function(/*Event*/ e){
			// summary
			//	callback on focus
			if(e.target == this.tabStartOuter) {
				if(this._fromTrap) {
					this.tabStart.focus();
					this._fromTrap = false;
				} else {
					this._fromTrap = true;
					this.tabEnd.focus();
				}
			} else if (e.target == this.tabStart) {
				if(this._fromTrap) {
					this._fromTrap = false;
				} else {
					this._fromTrap = true;
					this.tabEnd.focus();
				}
			} else if(e.target == this.tabEndOuter) {
				if(this._fromTrap) {
					this.tabEnd.focus();
					this._fromTrap = false;
				} else {
					this._fromTrap = true;
					this.tabStart.focus();
				}
			} else if(e.target == this.tabEnd) {
				if(this._fromTrap) {
					this._fromTrap = false;
				} else {
					this._fromTrap = true;
					this.tabStart.focus();
				}
			}
		},

		clearTrap: function(/*Event*/ e) {
			// summary
			//	callback on blur
			var _this = this;
			setTimeout(function() {
				_this._fromTrap = false;
			}, 100);
		},

		postCreate: function() {
			// summary
			//	if the target mixin class already defined postCreate,
			//	dojo.widget.ModalDialogBase.prototype.postCreate.call(this)
			//	should be called in its postCreate()
			with(this.domNode.style){
				position = "absolute";
				zIndex = 999;
				display = "none";
				overflow = "visible";
			}
			var b = dojo.body();
			b.appendChild(this.domNode);

			if(!this.shared.bg){
				this.shared.bg = document.createElement("div");
				this.shared.bg.className = "dialogUnderlay";
				with(this.shared.bg.style){
					position = "absolute";
					left = top = "0px";
					zIndex = 998;
					display = "none";
				}
				this.setBackgroundColor(this.bgColor);
				b.appendChild(this.shared.bg);
				this.shared.bgIframe = new dojo.html.BackgroundIframe(this.shared.bg);
			}
		},

		setBackgroundColor: function(/*String*/ color) {
			// summary
			//	changes background color specified by "bgColor" parameter
			//	usage:
			//		setBackgrounColor("black");
			//		setBackgroundColor(0xff, 0xff, 0xff);
			if(arguments.length >= 3) {
				color = new dojo.gfx.color.Color(arguments[0], arguments[1], arguments[2]);
			} else {
				color = new dojo.gfx.color.Color(color);
			}
			this.shared.bg.style.backgroundColor = color.toString();
			return this.bgColor = color;
		},

		setBackgroundOpacity: function(/*Number*/ op) {
			// summary
			//	changes background opacity set by "bgOpacity" parameter
			if(arguments.length == 0) { op = this.bgOpacity; }
			dojo.html.setOpacity(this.shared.bg, op);
			try {
				this.bgOpacity = dojo.html.getOpacity(this.shared.bg);
			} catch (e) {
				this.bgOpacity = op;
			}
			return this.bgOpacity;
		},

		_sizeBackground: function() {
			if(this.bgOpacity > 0) {
				
				var viewport = dojo.html.getViewport();
				var h = viewport.height;
				var w = viewport.width;
				with(this.shared.bg.style){
					width = w + "px";
					height = h + "px";
				}
				var scroll_offset = dojo.html.getScroll().offset;
				this.shared.bg.style.top = scroll_offset.y + "px";
				this.shared.bg.style.left = scroll_offset.x + "px";
				// process twice since the scroll bar may have been removed
				// by the previous resizing
				var viewport = dojo.html.getViewport();
				if (viewport.width != w) { this.shared.bg.style.width = viewport.width + "px"; }
				if (viewport.height != h) { this.shared.bg.style.height = viewport.height + "px"; }
			}
		},

		_showBackground: function() {
			if(this.bgOpacity > 0) {
				this.shared.bg.style.display = "block";
			}
		},

		placeModalDialog: function() {
			var scroll_offset = dojo.html.getScroll().offset;
			var viewport_size = dojo.html.getViewport();
			
			// find the size of the dialog
			var mb = dojo.html.getMarginBox(this.containerNode);
			
			var x = scroll_offset.x + (viewport_size.width - mb.width)/2;
			var y = scroll_offset.y + (viewport_size.height - mb.height)/2;

			with(this.domNode.style){
				left = x + "px";
				top = y + "px";
			}
		},

		showModalDialog: function() {
			// summary
			//	call this function in show() of subclass
			if (this.followScroll && !this._scrollConnected){
				this._scrollConnected = true;
				dojo.event.connect(window, "onscroll", this, "_onScroll");
			}
			
			this.setBackgroundOpacity();
			this._sizeBackground();
			this._showBackground();
		},

		hideModalDialog: function(){
			// summary
			//	call this function in hide() of subclass

			// workaround for FF focus going into outer space
			if (this.focusElement) { 
				dojo.byId(this.focusElement).focus(); 
				dojo.byId(this.focusElement).blur();
			}

			this.shared.bg.style.display = "none";
			this.shared.bg.style.width = this.shared.bg.style.height = "1px";

			if (this._scrollConnected){
				this._scrollConnected = false;
				dojo.event.disconnect(window, "onscroll", this, "_onScroll");
			}
		},

		_onScroll: function(){
			var scroll_offset = dojo.html.getScroll().offset;
			this.shared.bg.style.top = scroll_offset.y + "px";
			this.shared.bg.style.left = scroll_offset.x + "px";
			this.placeModalDialog();
		},

		checkSize: function() {
			if(this.isShowing()){
				this._sizeBackground();
				this.placeModalDialog();
				this.onResized();
			}
		}
	});

// summary
//	Pops up a modal dialog window, blocking access to the screen and also graying out the screen
//	Dialog is extended from ContentPane so it supports all the same parameters (href, etc.)
dojo.widget.defineWidget(
	"dojo.widget.Dialog",
	[dojo.widget.ContentPane, dojo.widget.ModalDialogBase],
	{
		templatePath: dojo.uri.dojoUri("src/widget/templates/Dialog.html"),

		// Integer
		//	number of seconds for which the user cannot dismiss the dialog
		blockDuration: 0,
		
		// Integer
		//	if set, this controls the number of seconds the dialog will be displayed before automatically disappearing
		lifetime: 0,

		show: function() {
			if(this.lifetime){
				this.timeRemaining = this.lifetime;
				if(!this.blockDuration){
					dojo.event.connect(this.shared.bg, "onclick", this, "hide");
				}else{
					dojo.event.disconnect(this.shared.bg, "onclick", this, "hide");
				}
				if(this.timerNode){
					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
				}
				if(this.blockDuration && this.closeNode){
					if(this.lifetime > this.blockDuration){
						this.closeNode.style.visibility = "hidden";
					}else{
						this.closeNode.style.display = "none";
					}
				}
				this.timer = setInterval(dojo.lang.hitch(this, "_onTick"), 100);
			}

			this.showModalDialog();
			dojo.widget.Dialog.superclass.show.call(this);
		},

		onLoad: function(){
			// when href is specified we need to reposition
			// the dialog after the data is loaded
			this.placeModalDialog();
			dojo.widget.Dialog.superclass.onLoad.call(this);
		},
		
		fillInTemplate: function(){
			// dojo.event.connect(this.domNode, "onclick", this, "killEvent");
		},

		hide: function(){
			this.hideModalDialog();
			dojo.widget.Dialog.superclass.hide.call(this);

			if(this.timer){
				clearInterval(this.timer);
			}
		},
		
		setTimerNode: function(node){
			// summary
			//	specify into which node to write the remaining # of seconds
			// TODO: make this a parameter too
			this.timerNode = node;
		},

		setCloseControl: function(node) {
			// summary
			//	specify which node is the close button for this dialog
			// TODO: make this a parameter too
			this.closeNode = node;
			dojo.event.connect(node, "onclick", this, "hide");
		},

		setShowControl: function(node) {
			// summary
			//	when specified node is clicked, show this dialog
			// TODO: make this a parameter too
			dojo.event.connect(node, "onclick", this, "show");
		},
		
		_onTick: function(){
			// summary
			//	callback every second that the timer clicks
			if(this.timer){
				this.timeRemaining -= 100;
				if(this.lifetime - this.timeRemaining >= this.blockDuration){
					dojo.event.connect(this.shared.bg, "onclick", this, "hide");
					if(this.closeNode){
						this.closeNode.style.visibility = "visible";
					}
				}
				if(!this.timeRemaining){
					clearInterval(this.timer);
					this.hide();
				}else if(this.timerNode){
					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
				}
			}
		}
	}
);

__CPAN_FILE__ src/widget/InternetTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.InternetTextbox");

dojo.require("dojo.widget.ValidationTextbox");
dojo.require("dojo.validate.web");

dojo.widget.defineWidget(
	"dojo.widget.IpAddressTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary:  A Textbox which tests for a valid IP address
		// description:  Can specify formats for ipv4 or ipv6 as attributes in the markup.
		//
		// allowDottedDecimal  true or false, default is true.
		// allowDottedHex      true or false, default is true.
		// allowDottedOctal    true or false, default is true.
		// allowDecimal        true or false, default is true.
		// allowHex            true or false, default is true.
		// allowIPv6           true or false, default is true.
		// allowHybrid         true or false, default is true.

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// First initialize properties in super-class.
			dojo.widget.IpAddressTextbox.superclass.mixInProperties.apply(this, arguments);

			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.allowdotteddecimal){ 
				this.flags.allowDottedDecimal = (localProperties.allowdotteddecimal == "true");
			}
			if(localProperties.allowdottedhex){ 
				this.flags.allowDottedHex = (localProperties.allowdottedhex == "true");
			}
			if(localProperties.allowdottedoctal){ 
				this.flags.allowDottedOctal = (localProperties.allowdottedoctal == "true");
			}
			if(localProperties.allowdecimal){ 
				this.flags.allowDecimal = (localProperties.allowdecimal == "true");
			}
			if(localProperties.allowhex){ 
				this.flags.allowHex = (localProperties.allowhex == "true");
			}
			if(localProperties.allowipv6){ 
				this.flags.allowIPv6 = (localProperties.allowipv6 == "true");
			}
			if(localProperties.allowhybrid){ 
				this.flags.allowHybrid = (localProperties.allowhybrid == "true");
			}
		},

		isValid: function(){ 
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.isIpAddress(this.textbox.value, this.flags);
		}
	}
);

dojo.widget.defineWidget(
	"dojo.widget.UrlTextbox",
	dojo.widget.IpAddressTextbox,
	{
		// summary:  A Textbox which tests for a valid URL
		// scheme        Can be true or false.  If omitted the scheme is optional.
		// allowIP       Allow an IP address for hostname.  Default is true.
		// allowLocal    Allow the host to be "localhost".  Default is false.
		// allowCC       Allow 2 letter country code domains.  Default is true.
		// allowGeneric  Allow generic domains.  Can be true or false, default is true.

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// First initialize properties in super-class.
			dojo.widget.UrlTextbox.superclass.mixInProperties.apply(this, arguments);

			// Get properties from markup attributes, and assign to flags object.
			if ( localProperties.scheme ) { 
				this.flags.scheme = ( localProperties.scheme == "true" );
			}
			if ( localProperties.allowip ) { 
				this.flags.allowIP = ( localProperties.allowip == "true" );
			}
			if ( localProperties.allowlocal ) { 
				this.flags.allowLocal = ( localProperties.allowlocal == "true" );
			}
			if ( localProperties.allowcc ) { 
				this.flags.allowCC = ( localProperties.allowcc == "true" );
			}
			if ( localProperties.allowgeneric ) { 
				this.flags.allowGeneric = ( localProperties.allowgeneric == "true" );
			}
		},

		isValid: function(){ 
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.isUrl(this.textbox.value, this.flags);
		}
	}
);

//FIXME: DOC: need more consistent explanation on whether attributes are inherited from the parent.  Some make sense, some don't?

dojo.widget.defineWidget(
	"dojo.widget.EmailTextbox",
	dojo.widget.UrlTextbox,
	{
		// summary:  A Textbox which tests for a valid email address
		// description:
		//  Can use all markup attributes/properties of UrlTextbox except scheme.
		//
		// allowCruft: Allow address like <mailto:foo@yahoo.com>.  Default is false.

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// First initialize properties in super-class.
			dojo.widget.EmailTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.allowcruft){ 
				this.flags.allowCruft = (localProperties.allowcruft == "true");
			}
		},

		isValid: function(){
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.isEmailAddress(this.textbox.value, this.flags);
		}
	}
);

//TODO: perhaps combine with EmailTextbox?
dojo.widget.defineWidget(
	"dojo.widget.EmailListTextbox",
	dojo.widget.EmailTextbox,
	{
		// summary:  A Textbox which tests for a list of valid email addresses
		//
		// listSeparator:  The character used to separate email addresses.  
		//    Default is ";", ",", "\n" or " "

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// First initialize properties in super-class.
			dojo.widget.EmailListTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.listseparator){ 
				this.flags.listSeparator = localProperties.listseparator;
			}
		},

		isValid: function(){
			// summary: see dojo.widget.ValidationTextbox
			return dojo.validate.isEmailAddressList(this.textbox.value, this.flags);
		}
	}
);

__CPAN_FILE__ src/widget/ColorPalette.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ColorPalette");
dojo.require("dojo.widget.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.display");
dojo.require("dojo.html.selection");

dojo.widget.defineWidget(
	"dojo.widget.ColorPalette",
	dojo.widget.HtmlWidget,
{
	palette: "7x10",

	bgIframe: null,

	palettes: {
		"7x10": [["fff", "fcc", "fc9", "ff9", "ffc", "9f9", "9ff", "cff", "ccf", "fcf"],
			["ccc", "f66", "f96", "ff6", "ff3", "6f9", "3ff", "6ff", "99f", "f9f"],
			["c0c0c0", "f00", "f90", "fc6", "ff0", "3f3", "6cc", "3cf", "66c", "c6c"],
			["999", "c00", "f60", "fc3", "fc0", "3c0", "0cc", "36f", "63f", "c3c"],
			["666", "900", "c60", "c93", "990", "090", "399", "33f", "60c", "939"],
			["333", "600", "930", "963", "660", "060", "366", "009", "339", "636"],
			["000", "300", "630", "633", "330", "030", "033", "006", "309", "303"]],

		"3x4": [["ffffff"/*white*/, "00ff00"/*lime*/, "008000"/*green*/, "0000ff"/*blue*/],
			["c0c0c0"/*silver*/, "ffff00"/*yellow*/, "ff00ff"/*fuchsia*/, "000080"/*navy*/],
			["808080"/*gray*/, "ff0000"/*red*/, "800080"/*purple*/, "000000"/*black*/]]
			//["00ffff"/*aqua*/, "808000"/*olive*/, "800000"/*maroon*/, "008080"/*teal*/]];
	},

	buildRendering: function () {
		this.domNode = document.createElement("table");
//		dojo.body().appendChild(this.domNode);
		dojo.html.disableSelection(this.domNode);
		dojo.event.connect(this.domNode, "onmousedown", function (e) {
			e.preventDefault();
		});
		with (this.domNode) { // set the table's properties
			cellPadding = "0"; cellSpacing = "1"; border = "1";
			style.backgroundColor = "white"; //style.position = "absolute";
		}
		var colors = this.palettes[this.palette];
		for (var i = 0; i < colors.length; i++) {
			var tr = this.domNode.insertRow(-1);
			for (var j = 0; j < colors[i].length; j++) {
				if (colors[i][j].length == 3) {
					colors[i][j] = colors[i][j].replace(/(.)(.)(.)/, "$1$1$2$2$3$3");
				}

				var td = tr.insertCell(-1);
				with (td.style) {
					backgroundColor = "#" + colors[i][j];
					border = "1px solid gray";
					width = height = "15px";
					fontSize = "1px";
				}

				td.color = "#" + colors[i][j];

				td.onmouseover = function (e) { this.style.borderColor = "white"; }
				td.onmouseout = function (e) { this.style.borderColor = "gray"; }
				dojo.event.connect(td, "onmousedown", this, "click");

				td.innerHTML = "&nbsp;";
			}
		}

		if(dojo.render.html.ie){
			this.bgIframe = document.createElement("<iframe frameborder='0' src='javascript:void(0);'>");
			with(this.bgIframe.style){
				position = "absolute";
				left = top = "0px";
				display = "none";
			}
			dojo.body().appendChild(this.bgIframe);
			dojo.html.setOpacity(this.bgIframe, 0);
		}
	},

	click: function (e) {
		this.onColorSelect(e.currentTarget.color);
		e.currentTarget.style.borderColor = "gray";
	},

	onColorSelect: function (color) { },

	hide: function (){
		this.domNode.parentNode.removeChild(this.domNode);
		if(this.bgIframe){
			this.bgIframe.style.display = "none";
		}
	},

	showAt: function (x, y) {
		with(this.domNode.style){
			top = y + "px";
			left = x + "px";
			zIndex = 999;
		}
		dojo.body().appendChild(this.domNode);
		if(this.bgIframe){
			with(this.bgIframe.style){
				display = "block";
				top = y + "px";
				left = x + "px";
				zIndex = 998;
				var s = dojo.html.getMarginBox(this.domNode);
				width = s.width + "px";
				height = s.height + "px";
			}

		}
	}
});

__CPAN_FILE__ src/widget/Wizard.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Wizard");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.LayoutContainer");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.event.*");
dojo.require("dojo.html.style");

//////////////////////////////////////////
// WizardContainer -- a set of panels
//////////////////////////////////////////
dojo.widget.defineWidget(
	"dojo.widget.WizardContainer",
	dojo.widget.LayoutContainer,
{
	labelPosition: "top",

	templatePath: dojo.uri.dojoUri("src/widget/templates/Wizard.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Wizard.css"),

	selected: null,		// currently selected panel
	wizardNode: null, // the outer wizard node
	wizardPanelContainerNode: null, // the container for the panels
	wizardControlContainerNode: null, // the container for the wizard controls
	previousButton: null, // the previous button
	nextButton: null, // the next button
	cancelButton: null, // the cancel button
	doneButton: null, // the done button
	nextButtonLabel: "next",
	previousButtonLabel: "previous",
	cancelButtonLabel: "cancel",
	doneButtonLabel: "done",
	cancelFunction : "",

	hideDisabledButtons: false,

	fillInTemplate: function(args, frag){
		dojo.event.connect(this.nextButton, "onclick", this, "nextPanel");
		dojo.event.connect(this.previousButton, "onclick", this, "previousPanel");
		if (this.cancelFunction){
			dojo.event.connect(this.cancelButton, "onclick", this.cancelFunction);
		}else{
			this.cancelButton.style.display = "none";
		}
		dojo.event.connect(this.doneButton, "onclick", this, "done");
		this.nextButton.value = this.nextButtonLabel;
		this.previousButton.value = this.previousButtonLabel;
		this.cancelButton.value = this.cancelButtonLabel;
		this.doneButton.value = this.doneButtonLabel;
	},

	checkButtons: function(){
		var lastStep = !this.hasNextPanel();
		this.nextButton.disabled = lastStep;
		this.setButtonClass(this.nextButton);
		if(this.selected.doneFunction){
			this.doneButton.style.display = "";
			// hide the next button if this is the last one and we have a done function
			if(lastStep){
				this.nextButton.style.display = "none";
			}
		}else{
			this.doneButton.style.display = "none";
		}
		this.previousButton.disabled = ((!this.hasPreviousPanel()) || (!this.selected.canGoBack));
		this.setButtonClass(this.previousButton);
	},

	setButtonClass: function(button){
		if(!this.hideDisabledButtons){
			button.style.display = "";
			dojo.html.setClass(button, button.disabled ? "WizardButtonDisabled" : "WizardButton");
		}else{
			button.style.display = button.disabled ? "none" : "";
		}
	},

	registerChild: function(panel, insertionIndex){
		dojo.widget.WizardContainer.superclass.registerChild.call(this, panel, insertionIndex);
		this.wizardPanelContainerNode.appendChild(panel.domNode);
		panel.hide();

		if(!this.selected){
			this.onSelected(panel);
		}
		this.checkButtons();
	},

	onSelected: function(panel){
		// Deselect old panel and select new one
		if(this.selected ){
			if (this.selected.checkPass()) {
				this.selected.hide();
			} else {
				return;
			}
		}
		panel.show();
		this.selected = panel;
	},

	getPanels: function() {
		return this.getChildrenOfType("WizardPane", false);
	},

	selectedIndex: function() {
		if (this.selected) {
			return dojo.lang.indexOf(this.getPanels(), this.selected);
		}
		return -1;
	},

	nextPanel: function() {
		var selectedIndex = this.selectedIndex();
		if ( selectedIndex > -1 ) {
			var childPanels = this.getPanels();
			if (childPanels[selectedIndex + 1]) {
				this.onSelected(childPanels[selectedIndex + 1]);
			}
		}
		this.checkButtons();
	},

	previousPanel: function() {
		var selectedIndex = this.selectedIndex();
		if ( selectedIndex > -1 ) {
			var childPanels = this.getPanels();
			if (childPanels[selectedIndex - 1]) {
				this.onSelected(childPanels[selectedIndex - 1]);
			}
		}
		this.checkButtons();
	},

	hasNextPanel: function() {
		var selectedIndex = this.selectedIndex();
		return (selectedIndex < (this.getPanels().length - 1));
	},

	hasPreviousPanel: function() {
		var selectedIndex = this.selectedIndex();
		return (selectedIndex > 0);
	},

	done: function() {
		this.selected.done();
	}
});

//////////////////////////////////////////
// WizardPane -- a panel in a wizard
//////////////////////////////////////////
dojo.widget.defineWidget(
	"dojo.widget.WizardPane",
	dojo.widget.ContentPane,
{
	canGoBack: true,

	passFunction: "",
	doneFunction: "",

	fillInTemplate: function(args, frag) {
		if (this.passFunction) {
			this.passFunction = dj_global[this.passFunction];
		}
		if (this.doneFunction) {
			this.doneFunction = dj_global[this.doneFunction];
		}
	},

	checkPass: function() {
		if (this.passFunction && dojo.lang.isFunction(this.passFunction)) {
			var failMessage = this.passFunction();
			if (failMessage) {
				alert(failMessage);
				return false;
			}
		}
		return true;
	},

	done: function() {
		if (this.doneFunction && dojo.lang.isFunction(this.doneFunction)) {
			this.doneFunction();
		}
	}
});

__CPAN_FILE__ src/widget/Editor2.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/* TODO:
 * - font selector
 * - test, bug fix, more features :)
*/
dojo.provide("dojo.widget.Editor2");

dojo.require("dojo.io.*");
dojo.require("dojo.html.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.RichText");
dojo.require("dojo.widget.Editor2Toolbar");

// Object: Manager of current focused Editor2 Instance and available editor2 commands
dojo.widget.Editor2Manager = {
	_currentInstance: null,
	_loadedCommands: {},

	// Object: state a command may be in
	commandState: {Disabled: 0, Latched: 1, Enabled: 2},

	getCurrentInstance: function(){
		// summary: Return the current focused Editor2 instance
		return this._currentInstance;
	},
	setCurrentInstance: function(/*Widget*/inst){
		// summary: Set current focused Editor2 instance
		this._currentInstance = inst;
	},
	registerCommand: function(/*String*/name, /*Object*/cmd){
		// summary: Register an Editor2 command
		// name: name of the command (case insensitive)
		// cmd: an object which implements interface dojo.widget.Editor2Command
		name = name.toLowerCase();
		if(this._loadedCommands[name]){
			delete this._loadedCommands[name];
		}
		this._loadedCommands[name] = cmd;
	},
	getCommand: function(/*String*/name){
		// summary: Return Editor2 command with the given name
		// name: name of the command (case insensitive)
		name = name.toLowerCase();
		var oCommand = this._loadedCommands[name];
		if(oCommand){
			return oCommand;
		}

		switch(name){
			case 'htmltoggle':
				//Editor2 natively provide the htmltoggle functionalitity
				//and it is treated as a builtin command
				oCommand = new dojo.widget.Editor2BrowserCommand(name);
				break;
			case 'formatblock':
				oCommand = new dojo.widget.Editor2FormatBlockCommand(name);
				break;
			case 'anchor':
				oCommand = new dojo.widget.Editor2Command(name);
				break;

			//dialog command
			case 'createlink':
				oCommand = new dojo.widget.Editor2DialogCommand(name,
						{contentFile: "dojo.widget.Editor2Plugin.CreateLinkDialog",
							contentClass: "Editor2CreateLinkDialog",
							title: "Insert/Edit Link", width: "300px", height: "200px"});
				break;
			case 'insertimage':
				oCommand = new dojo.widget.Editor2DialogCommand(name,
						{contentFile: "dojo.widget.Editor2Plugin.InsertImageDialog",
							contentClass: "Editor2InsertImageDialog",
							title: "Insert/Edit Image", width: "400px", height: "270px"});
				break;
			// By default we assume that it is a builtin simple command.
			default:
				var curtInst = this.getCurrentInstance();
				if((curtInst && curtInst.queryCommandAvailable(name)) ||
					(!curtInst && dojo.widget.Editor2.prototype.queryCommandAvailable(name))){
					oCommand = new dojo.widget.Editor2BrowserCommand(name);
				}else{
					dojo.debug("dojo.widget.Editor2Manager.getCommand: Unknown command "+name);
					return;
				}
		}
		this._loadedCommands[name] = oCommand;
		return oCommand;
	},
	destroy: function(){
		// summary: Cleaning up. This is called automatically on page unload.
		this._currentInstance = null;
		for(var cmd in this._loadedCommands){
			this._loadedCommands[cmd].destory();
		}
	}
};

dojo.addOnUnload(dojo.widget.Editor2Manager, "destroy");

// summary:
//		dojo.widget.Editor2Command is the base class for all command in Editor2
dojo.lang.declare("dojo.widget.Editor2Command",null,{
		initializer: function(name){
			// summary: Constructor of this class
			this._name = name;
		},
		//this function should be re-implemented in subclass
		execute: function(para){
			// summary: Execute the command. should be implemented in subclass
			dojo.unimplemented("dojo.widget.Editor2Command.execute");
		},
		//default implemetation always returns Enabled
		getState: function(){
			// summary:
			//		Return the state of the command. The default behavior is
			//		to always return Enabled
			return dojo.widget.Editor2Manager.commandState.Enabled;
		},
		destory: function(){
			// summary: Destructor
		}
	}
);

// summary:
//		dojo.widget.Editor2BrowserCommand is the base class for all the browser built
//		in commands
dojo.lang.declare("dojo.widget.Editor2BrowserCommand", dojo.widget.Editor2Command, {
		execute: function(para){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			if(curInst){
				curInst.execCommand(this._name, para);
			}
		},
		getState: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			if(curInst){
				try{
					if(curInst.queryCommandEnabled(this._name)){
						if(curInst.queryCommandState(this._name)){
							return dojo.widget.Editor2Manager.commandState.Latched;
						}else{
							return dojo.widget.Editor2Manager.commandState.Enabled;
						}
					}else{
						return dojo.widget.Editor2Manager.commandState.Disabled;
					}
				}catch (e) {
					//dojo.debug("exception when getting state for command "+this._name+": "+e);
					return dojo.widget.Editor2Manager.commandState.Enabled;
				}
			}
			return dojo.widget.Editor2Manager.commandState.Disabled;
		},
		getValue: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			if(curInst){
				try{
					return curInst.queryCommandValue(this._name);
				}catch(e){}
			}
		}
	}
);

dojo.lang.declare("dojo.widget.Editor2FormatBlockCommand", dojo.widget.Editor2BrowserCommand, {
		/* In none-ActiveX mode under IE, <p> and no <p> text can not be distinguished
		getCurrentValue: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			if(!curInst){ return ''; }

			var h = dojo.render.html;

			// safari f's us for selection primitives
			if(h.safari){ return ''; }

			var selectedNode = (h.ie) ? curInst.document.selection.createRange().parentElement() : curInst.window.getSelection().anchorNode;
			// make sure we actuall have an element
			while((selectedNode)&&(selectedNode.nodeType != 1)){
				selectedNode = selectedNode.parentNode;
			}
			if(!selectedNode){ return ''; }

			var formats = ["p", "pre", "h1", "h2", "h3", "h4", "h5", "h6", "address"];
			// gotta run some specialized updates for the various
			// formatting options
			var type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())];
			while((selectedNode!=curInst.editNode)&&(!type)){
				selectedNode = selectedNode.parentNode;
				if(!selectedNode){ break; }
				type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())];
			}
			if(!type){
				type = "";
			}
			return type;
		}*/
	}
);

dojo.require("dojo.widget.FloatingPane");
// summary:
//		dojo.widget.Editor2Dialog provides a Dialog which can be modal or normal for the Editor2.
dojo.widget.defineWidget(
	"dojo.widget.Editor2Dialog",
	[dojo.widget.HtmlWidget, dojo.widget.FloatingPaneBase, dojo.widget.ModalDialogBase],
	{
		templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorDialog.html"),
		// Boolean: Whether this is a modal dialog. True by default.
		modal: true,
//		refreshOnShow: true, //for debug for now

		// String: Wwidth of the dialog. None by default
		width: false,
		// String: Height of the dialog. None by default
		height: false,

		// String: startup state of the dialog
		windowState: "minimized",

		displayCloseAction: true,

		contentFile: "",
		contentClass: "",

		fillInTemplate: function(args, frag){
			this.fillInFloatingPaneTemplate(args, frag);
			dojo.widget.Editor2Dialog.superclass.fillInTemplate.call(this, args, frag);
		},
		postCreate: function(){
			if(this.contentFile){
				dojo.require(this.contentFile);
			}
			if(this.modal){
				dojo.widget.ModalDialogBase.prototype.postCreate.call(this);
			}else{
				with(this.domNode.style) {
					zIndex = 999;
					display = "none";
				}
			}
			dojo.widget.FloatingPaneBase.prototype.postCreate.apply(this, arguments);
			dojo.widget.Editor2Dialog.superclass.postCreate.call(this);
			if(this.width && this.height){
				with(this.domNode.style){
					width = this.width;
					height = this.height;
				}
			}
		},
		createContent: function(){
			if(!this.contentWidget && this.contentClass){
				this.contentWidget = dojo.widget.createWidget(this.contentClass);
				this.addChild(this.contentWidget);
			}
		},
		show: function(){
			if(!this.contentWidget){
				//buggy IE: if the dialog is hidden, the button widgets
				//in the dialog can not be shown, so show it temporary (as the
				//dialog may decide not to show it in loadContent() later)
				dojo.widget.Editor2Dialog.superclass.show.apply(this, arguments);
				this.createContent();
				dojo.widget.Editor2Dialog.superclass.hide.call(this);
			}

			if(!this.contentWidget || !this.contentWidget.loadContent()){
				return;
			}
			this.showFloatingPane();
			dojo.widget.Editor2Dialog.superclass.show.apply(this, arguments);
			if(this.modal){
				this.showModalDialog();
			}
			this.placeModalDialog();
			if(this.modal){
				//place the background div under this modal pane
				this.shared.bg.style.zIndex = this.domNode.style.zIndex-1;
			}
		},
		onShow: function(){
			dojo.widget.Editor2Dialog.superclass.onShow.call(this);
			this.onFloatingPaneShow();
		},
		closeWindow: function(){
			this.hide();
			dojo.widget.Editor2Dialog.superclass.closeWindow.apply(this, arguments);
		},
		hide: function(){
			if(this.modal){
				this.hideModalDialog();
			}
			dojo.widget.Editor2Dialog.superclass.hide.call(this);
		}
	}
);

// summary:
//		dojo.widget.Editor2DialogContent is the actual content of a Editor2Dialog.
//		This class should be subclassed to provide the content.
dojo.widget.defineWidget(
	"dojo.widget.Editor2DialogContent",
	dojo.widget.HtmlWidget,
{
	widgetsInTemplate: true,

	loadContent:function(){
		// summary: Load the content. Called by Editor2Dialog when first shown
		return true;
	},
	cancel: function(){
		// summary: Default handler when cancel button is clicked.
		this.parent.hide();
	}
});

// summary:
//		dojo.widget.Editor2DialogCommand provides an easy way to popup a dialog when
//		the command is executed.
dojo.lang.declare("dojo.widget.Editor2DialogCommand", dojo.widget.Editor2BrowserCommand,
	function(name, dialogParas){
		this.dialogParas = dialogParas;
	},
{
	execute: function(){
		if(!this.dialog){
			if(!this.dialogParas.contentFile || !this.dialogParas.contentClass){
				alert("contentFile and contentClass should be set for dojo.widget.Editor2DialogCommand.dialogParas!");
				return;
			}
			this.dialog = dojo.widget.createWidget("Editor2Dialog", this.dialogParas);

			dojo.body().appendChild(this.dialog.domNode);

			dojo.event.connect(this, "destroy", this.dialog, "destroy");
		}
		this.dialog.show();
	}
});

// summary:
//		dojo.widget.Editor2 is the WYSIWYG editor in dojo with toolbar. It supports a plugin
//		framework which can be used to extend the functionalities of the editor, such as
//		adding a context menu, table operation etc.
// description:
//		Plugins are available using dojo's require syntax. Please find available built-in plugins
//		under src/widget/Editor2Plugin.
dojo.widget.defineWidget(
	"dojo.widget.Editor2",
	dojo.widget.RichText,
	{
//		// String: url to which save action should send content to
//		saveUrl: "",
//		// String: HTTP method for save (post or get)
//		saveMethod: "post",
//		saveArgName: "editorContent",
//		closeOnSave: false,

		// Boolean: Whether to share toolbar with other instances of Editor2
		shareToolbar: false,
		// Boolean: Whether the toolbar should scroll to keep it in the view
		toolbarAlwaysVisible: false,

//		htmlEditing: false,

		toolbarWidget: null,
		scrollInterval: null,

		// Object: dojo.uri.Uri object to specify the template file for the toolbar
		toolbarTemplatePath: dojo.uri.dojoUri("src/widget/templates/EditorToolbarOneline.html"),
		// Object: dojo.uri.Uri object to specify the css file for the toolbar
		toolbarTemplateCssPath: null,
//		toolbarTemplatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbarFCKStyle.html"),
//		toolbarTemplateCssPath: dojo.uri.dojoUri("src/widget/templates/Editor2/FCKDefault/EditorToolbarFCKStyle.css"),

		_inSourceMode: false,
		_htmlEditNode: null,

		editorOnLoad: function(){
			// summary:
			//		Create toolbar and other initialization routines. This is called after
			//		the finish of the loading of document in the editing element
//			dojo.profile.start("dojo.widget.Editor2::editorOnLoad");

			dojo.event.topic.publish("dojo.widget.Editor2::preLoadingToolbar", this);
			if(this.toolbarAlwaysVisible){
				dojo.require("dojo.widget.Editor2Plugin.AlwaysShowToolbar");
			}

			var toolbars = dojo.widget.byType("Editor2Toolbar");
			if((!toolbars.length)||(!this.shareToolbar)){
				if(this.toolbarWidget){
					this.toolbarWidget.show();
					//re-add the toolbar to the new domNode (caused by open() on another element)
					dojo.html.insertBefore(this.toolbarWidget.domNode, this.domNode.firstChild);
				}else{
					var tbOpts = {};
					tbOpts.templatePath = this.toolbarTemplatePath;
					if(this.toolbarTemplateCssPath){
						tbOpts.templateCssPath = this.toolbarTemplateCssPath;
					}
					this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", tbOpts, this.domNode.firstChild, "before");

					dojo.event.connect(this, "close", this.toolbarWidget, "hide");

					this.toolbarLoaded();
				}
			}else{
				// FIXME: 	selecting in one shared toolbar doesn't clobber
				// 			selection in the others. This is problematic.
				this.toolbarWidget = toolbars[0];
			}

			dojo.event.topic.registerPublisher("Editor2.clobberFocus", this, "clobberFocus");
			dojo.event.topic.subscribe("Editor2.clobberFocus", this, "setBlur");

			dojo.event.topic.publish("dojo.widget.Editor2::onLoad", this);
//			dojo.profile.end("dojo.widget.Editor2::editorOnLoad");
		},

		//event for plugins to use
		toolbarLoaded: function(){
			// summary:
			//		Fired when the toolbar for this editor is created.
			//		This event is for plugins to use
		},

		//TODO: provide a query mechanism about loaded plugins?
		registerLoadedPlugin: function(/*Object*/obj){
			// summary: Register a plugin which is loaded for this instance
			if(!this.loadedPlugins){
				this.loadedPlugins = [];
			}
			this.loadedPlugins.push(obj);
		},
		unregisterLoadedPlugin: function(/*Object*/obj){
			// summery: Delete a loaded plugin for this instance
			for(var i in this.loadedPlugins){
				if(this.loadedPlugins[i] === obj){
					delete this.loadedPlugins[i];
					return;
				}
			}
			dojo.debug("dojo.widget.Editor2.unregisterLoadedPlugin: unknow plugin object: "+obj);
		},

		//overload the original ones to provide extra commands
		execCommand: function(/*String*/command, argument){
			switch(command.toLowerCase()){
				case 'htmltoggle':
					this.toggleHtmlEditing();
					break;
				default:
					dojo.widget.Editor2.superclass.execCommand.apply(this, arguments);
			}
		},
		queryCommandEnabled: function(/*String*/command, argument){
			switch(command.toLowerCase()){
				case 'htmltoggle':
					return true;
				default:
					if(this._inSourceMode){ return false;}
					return dojo.widget.Editor2.superclass.queryCommandEnabled.apply(this, arguments);
			}
		},
		queryCommandState: function(/*String*/command, argument){
			switch(command.toLowerCase()){
				case 'htmltoggle':
					return this._inSourceMode;
				default:
					return dojo.widget.Editor2.superclass.queryCommandState.apply(this, arguments);
			}
		},

		onClick: function(/*Event*/e){
			dojo.widget.Editor2.superclass.onClick.call(this, e);
			//if Popup is used, call dojo.widget.PopupManager.onClick
			//manually when click in the editing area to close all
			//open popups (dropdowns)
			if(dojo.widget.PopupManager){
				if(!e){ //IE
					e = this.window.event;
				}
				dojo.widget.PopupManager.onClick(e);
			}
		},

		clobberFocus: function(){
			// summary: stub to signal other instances to clobber focus
		},
		toggleHtmlEditing: function(){
			// summary: toggle between WYSIWYG mode and HTML source mode
			if(this===dojo.widget.Editor2Manager.getCurrentInstance()){
				if(!this._inSourceMode){
					this._inSourceMode = true;

					if(!this._htmlEditNode){
						this._htmlEditNode = dojo.doc().createElement("textarea");
						dojo.html.insertAfter(this._htmlEditNode, this.editorObject);
					}
					this._htmlEditNode.style.display = "";
					this._htmlEditNode.style.width = "100%";
					this._htmlEditNode.style.height = dojo.html.getBorderBox(this.editNode).height+"px";
					this._htmlEditNode.value = this.editNode.innerHTML;

					//activeX object (IE) doesn't like to be hidden, so move it outside of screen instead
					with(this.editorObject.style){
						position = "absolute";
						left = "-2000px";
						top = "-2000px";
					}
				}else{
					this._inSourceMode = false;

					//In IE activeX mode, if _htmlEditNode is focused,
					//when toggling, an error would occur, so unfocus it
					this._htmlEditNode.blur();

					with(this.editorObject.style){
						position = "";
						left = "";
						top = "";
					}

					dojo.lang.setTimeout(this, "replaceEditorContent", 1, this._htmlEditNode.value);
					this._htmlEditNode.style.display = "none";
					this.focus();
				}
				this.updateToolbar(true);
			}
		},

		setFocus: function(){
			// summary: focus is set on this instance
//			dojo.debug("setFocus: start "+this.widgetId);
			if(dojo.widget.Editor2Manager.getCurrentInstance() === this){ return; }

			this.clobberFocus();
//			dojo.debug("setFocus:", this);
			dojo.widget.Editor2Manager.setCurrentInstance(this);
		},

		setBlur: function(){
			// summary: focus on this instance is lost
//			 dojo.debug("setBlur:", this);
			//dojo.event.disconnect(this.toolbarWidget, "exec", this, "execCommand");
		},

		saveSelection: function(){
			// summary: save the current selection for restoring it
			this._bookmark = null;
			this._bookmark = dojo.withGlobal(this.window, dojo.html.selection.getBookmark);
		},
		restoreSelection: function(){
			// summary: restore the last saved selection
			if(this._bookmark){
				this.focus(); //require for none-activeX IE
				dojo.withGlobal(this.window, "moveToBookmark", dojo.html.selection, [this._bookmark]);
				this._bookmark = null;
			}else{
				dojo.debug("restoreSelection: no saved selection is found!");
			}
		},

		_updateToolbarLastRan: null,
		_updateToolbarTimer: null,
		_updateToolbarFrequency: 500,

		updateToolbar: function(/*Boolean*/force){
			// summary: update the associated toolbar of this Editor2
			if((!this.isLoaded)||(!this.toolbarWidget)){ return; }

			// keeps the toolbar from updating too frequently
			// TODO: generalize this functionality?
			var diff = new Date() - this._updateToolbarLastRan;
			if( (!force)&&(this._updateToolbarLastRan)&&
				((diff < this._updateToolbarFrequency)) ){

				clearTimeout(this._updateToolbarTimer);
				var _this = this;
				this._updateToolbarTimer = setTimeout(function() {
					_this.updateToolbar();
				}, this._updateToolbarFrequency/2);
				return;

			}else{
				this._updateToolbarLastRan = new Date();
			}
			// end frequency checker

			//IE has the habit of generating events even when this editor is blurred, prevent this
			if(dojo.widget.Editor2Manager.getCurrentInstance() !== this){ return; }

			this.toolbarWidget.update();
		},

		destroy: function(/*Boolean*/finalize){
			this._htmlEditNode = null;
			dojo.event.disconnect(this, "close", this.toolbarWidget, "hide");
			if(!finalize){
				this.toolbarWidget.destroy();
			}
			dojo.widget.Editor2.superclass.destroy.call(this);
		},

		onDisplayChanged: function(/*Object*/e){
			dojo.widget.Editor2.superclass.onDisplayChanged.call(this,e);
			this.updateToolbar();
		},

		onLoad: function(){
			try{
				dojo.widget.Editor2.superclass.onLoad.call(this);
			}catch(e){ // FIXME: debug why this is throwing errors in IE!
				dojo.debug(e);
			}
			this.editorOnLoad();
		},

		onFocus: function(){
			dojo.widget.Editor2.superclass.onFocus.call(this);
			this.setFocus();
		},

		//overload to support source editing mode
		getEditorContent: function(){
			if(this._inSourceMode){
				this.replaceEditorContent(this._htmlEditNode.value);
			}
			return dojo.widget.Editor2.superclass.getEditorContent.call(this);
		}
		/*,
		// FIXME: probably not needed any more with new design, but need to verify
		_save: function(e){
			// FIXME: how should this behave when there's a larger form in play?
			if(!this.isClosed){
				dojo.debug("save attempt");
				if(this.saveUrl.length){
					var content = {};
					content[this.saveArgName] = this.getEditorContent();
					dojo.io.bind({
						method: this.saveMethod,
						url: this.saveUrl,
						content: content
					});
				}else{
					dojo.debug("please set a saveUrl for the editor");
				}
				if(this.closeOnSave){
					this.close(e.getName().toLowerCase() == "save");
				}
			}
		}*/
	},
	"html"
);
__CPAN_FILE__ src/widget/TreeSelector.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeSelector");

dojo.require("dojo.widget.HtmlWidget");


dojo.widget.defineWidget("dojo.widget.TreeSelector", dojo.widget.HtmlWidget, function() {
	this.eventNames = {};

	this.listenedTrees = [];

},
{
	widgetType: "TreeSelector",
	selectedNode: null,

	dieWithTree: false,

	eventNamesDefault: {
		select : "select",
		destroy : "destroy",
		deselect : "deselect",
		dblselect: "dblselect" // select already selected node.. Edit or whatever
	},

	initialize: function() {

		for(name in this.eventNamesDefault) {
			if (dojo.lang.isUndefined(this.eventNames[name])) {
				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
			}
		}

	},


	destroy: function() {
		dojo.event.topic.publish(this.eventNames.destroy, { source: this } );

		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
	},


	listenTree: function(tree) {
		dojo.event.topic.subscribe(tree.eventNames.titleClick, this, "select");
		dojo.event.topic.subscribe(tree.eventNames.iconClick, this, "select");
		dojo.event.topic.subscribe(tree.eventNames.collapse, this, "onCollapse");
		dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
		dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");

		/* remember all my trees to deselect when element is movedFrom them */
		this.listenedTrees.push(tree);
	},


	unlistenTree: function(tree) {

		dojo.event.topic.unsubscribe(tree.eventNames.titleClick, this, "select");
		dojo.event.topic.unsubscribe(tree.eventNames.iconClick, this, "select");
		dojo.event.topic.unsubscribe(tree.eventNames.collapse, this, "onCollapse");
		dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
		dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");


		for(var i=0; i<this.listenedTrees.length; i++){
           if(this.listenedTrees[i] === tree){
                   this.listenedTrees.splice(i, 1);
                   break;
           }
		}
	},


	onTreeDestroy: function(message) {

		this.unlistenTree(message.source);

		if (this.dieWithTree) {
			//dojo.debug("Killing myself "+this.widgetId);
			this.destroy();
			//dojo.debug("done");
		}
	},


	// deselect node if parent is collapsed
	onCollapse: function(message) {
		if (!this.selectedNode) return;

		var node = message.source;
		var parent = this.selectedNode.parent;
		while (parent !== node && parent.isTreeNode) {
			parent = parent.parent;
		}
		if (parent.isTreeNode) {
			this.deselect();
		}
	},



	select: function(message) {
		var node = message.source;
		var e = message.event;

		if (this.selectedNode === node) {
			if(e.ctrlKey || e.shiftKey || e.metaKey){
				// If the node is currently selected, and they select it again while holding
				// down a meta key, it deselects it
				this.deselect();
				return;
			}
			dojo.event.topic.publish(this.eventNames.dblselect, { node: node });
			return;
		}

		if (this.selectedNode) {
			this.deselect();
		}

		this.doSelect(node);

		dojo.event.topic.publish(this.eventNames.select, {node: node} );
	},

	/**
	 * Deselect node if target tree is out of our concern
	 */
	onMoveFrom: function(message) {
		if (message.child !== this.selectedNode) {
			return;
		}

		if (!dojo.lang.inArray(this.listenedTrees, message.newTree)) {
			this.deselect();
		}
	},

	onRemoveNode: function(message) {
		if (message.child !== this.selectedNode) {
			return;
		}

		this.deselect();
	},

	doSelect: function(node){

		node.markSelected();

		this.selectedNode = node;
	},

	deselect: function(){

		var node = this.selectedNode;

		this.selectedNode = null;
		node.unMarkSelected();
		dojo.event.topic.publish(this.eventNames.deselect, {node: node} );

	}

});




__CPAN_FILE__ src/widget/InlineEditBox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.InlineEditBox");

dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.gfx.color");
dojo.require("dojo.string");
dojo.require("dojo.html.*");
dojo.require("dojo.html.layout");

dojo.widget.defineWidget(
	"dojo.widget.InlineEditBox",
	dojo.widget.HtmlWidget,
	function(){
		// mutable objects need to be in constructor to give each instance its own copy
		this.history = [];
	},
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/InlineEditBox.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/InlineEditBox.css"),

	form: null,
	editBox: null,
	edit: null,
	text: null,
	textarea: null,
	submitButton: null,
	cancelButton: null,
	mode: "text",
	name: "",
	
	minWidth: 100, //px. minimum width of edit box
	minHeight: 200, //px. minimum width of edit box, if it's a TA

	editing: false,
	textValue: "",
	defaultText: "",
	doFade: false,
	
	onSave: function(newValue, oldValue, name){},
	onUndo: function(value){},

	postCreate: function(args, frag){
		// put original node back in the document, and attach handlers
		// which hide it and display the editor
		this.editable = this.getFragNodeRef(frag);
		dojo.html.insertAfter(this.editable, this.form);
		dojo.event.connect(this.editable, "onmouseover", this, "onMouseOver");
		dojo.event.connect(this.editable, "onmouseout", this, "onMouseOut");
		dojo.event.connect(this.editable, "onclick", this, "beginEdit");

		this.textValue = dojo.string.trim(this.editable.innerHTML);
		if(dojo.string.trim(this.textValue).length == 0){
			this.editable.innerHTML = this.defaultText;
		}		
	},
	
	onMouseOver: function(){
		if(!this.editing){
			if (!this.isEnabled){
				dojo.html.addClass(this.editable, "editableRegionDisabled");
			} else {
				dojo.html.addClass(this.editable, "editableRegion");
				if(this.mode == "textarea"){
					dojo.html.addClass(this.editable, "editableTextareaRegion");
				}
			}
		}
		
		this.mouseover();
	},
	
	mouseover: function(e){
		// TODO: How do we deprecate a function without going into overkill with debug statements?
		// dojo.deprecated("onMouseOver should be used instead of mouseover to listen for mouse events");
	},
	
	onMouseOut: function(){
		if(!this.editing){
			dojo.html.removeClass(this.editable, "editableRegion");
			dojo.html.removeClass(this.editable, "editableTextareaRegion");
			dojo.html.removeClass(this.editable, "editableRegionDisabled");
		}
		
		this.mouseout();
	},
	
	mouseout: function(e){
		// dojo.deprecated("onMouseOut should be used instead of mouseout to listen for mouse events");
	},

	// When user clicks the text, then start editing.
	// Hide the text and display the form instead.
	beginEdit: function(e){
		if(this.editing || !this.isEnabled){ return; }
		this.onMouseOut();
		this.editing = true;

		// setup the form's <input> or <textarea> field, as specified by mode
		var ee = this[this.mode.toLowerCase()];
		ee.value = dojo.string.trim(this.textValue);
		ee.style.fontSize = dojo.html.getStyle(this.editable, "font-size");
		ee.style.fontWeight = dojo.html.getStyle(this.editable, "font-weight");
		ee.style.fontStyle = dojo.html.getStyle(this.editable, "font-style");
		var bb = dojo.html.getBorderBox(this.editable);
		ee.style.width = Math.max(bb.width, this.minWidth) + "px";
		if(this.mode.toLowerCase()=="textarea"){
			ee.style.display = "block";
			ee.style.height = Math.max(bb.height, this.minHeight) + "px";
		} else {
			ee.style.display = "";
		}

		// show the edit form and hide the read only version of the text
		this.form.style.display = "";
		this.editable.style.display = "none";

		ee.focus();
		ee.select();
		this.submitButton.disabled = true;
	},

	saveEdit: function(e){
		e.preventDefault();
		e.stopPropagation();
		var ee = this[this.mode.toLowerCase()];
		if((this.textValue != ee.value)&&
			(dojo.string.trim(ee.value) != "")){
			this.doFade = true;
			this.history.push(this.textValue);
			this.onSave(ee.value, this.textValue, this.name);
			this.textValue = ee.value;
			this.editable.innerHTML = "";
			var textNode = document.createTextNode( this.textValue );
			this.editable.appendChild( textNode );
		}else{
			this.doFade = false;
		}
		this.finishEdit(e);
	},

	cancelEdit: function(e){
		if(!this.editing){ return false; }
		this.editing = false;
		this.form.style.display="none";
		this.editable.style.display = "";
		return true;
	},

	finishEdit: function(e){
		if(!this.cancelEdit(e)){ return; }
		if(this.doFade) {
			dojo.lfx.highlight(this.editable, dojo.gfx.color.hex2rgb("#ffc"), 700).play(300);
		}
		this.doFade = false;
	},
	
	setText: function(txt){
		// sets the text without informing the server
		txt = "" + txt;
		var tt = dojo.string.trim(txt);
		this.textValue = tt
		this.editable.innerHTML = tt;
	},

	undo: function(){
		if(this.history.length > 0){
			var curValue = this.textValue;
			var value = this.history.pop();
			this.editable.innerHTML = value;
			this.textValue = value;
			this.onUndo(value);
			this.onSave(value, curValue, this.name);
		}
	},

	checkForValueChange: function(){
		var ee = this[this.mode.toLowerCase()];
		if((this.textValue != ee.value)&&
			(dojo.string.trim(ee.value) != "")){
			this.submitButton.disabled = false;
		}
	},
	
	disable: function(){
		this.submitButton.disabled = true;
		this.cancelButton.disabled = true;
		var ee = this[this.mode.toLowerCase()];
		ee.disabled = true;
		
		dojo.widget.Widget.prototype.disable.call(this);
	},
	
	enable: function(){
		this.checkForValueChange();
		this.cancelButton.disabled = false;
		var ee = this[this.mode.toLowerCase()];
		ee.disabled = false;
		
		dojo.widget.Widget.prototype.enable.call(this);
	}
});

__CPAN_FILE__ src/widget/DateTextbox.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DateTextbox");

dojo.require("dojo.widget.ValidationTextbox");
dojo.require("dojo.date.format");
dojo.require("dojo.validate.datetime");

//TODO: combine date and time widgets?
dojo.widget.defineWidget(
	"dojo.widget.DateTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary: A TextBox which tests for a valid date
		// format: Deprecated. Style as described in v0.3 in dojo.validate.  Default is  "MM/DD/YYYY".

		// optional pattern used in display of formatted date.  Uses locale-specific format by default.  See dojo.date.format.
		displayFormat: "",
		// type of format appropriate to locale.  see dojo.date.format
		formatLength: "short",
//TODO: add date, saveFormat attributes like DropdownDatePicker?

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// First initialize properties in super-class.
			dojo.widget.DateTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.format){ 
				this.flags.format = localProperties.format;
			}
		},

		isValid: function(){ 
			// summary: see dojo.widget.ValidationTextbox

			if(this.flags.format){
				dojo.deprecated("dojo.widget.DateTextbox", "format attribute is deprecated; use displayFormat or formatLength instead", "0.5");
				return dojo.validate.isValidDate(this.textbox.value, this.flags.format);
			}

			return dojo.date.parse(this.textbox.value, {formatLength:this.formatLength, selector:'dateOnly', locale:this.lang, datePattern: this.displayFormat});
		}
	}
);

dojo.widget.defineWidget(
	"dojo.widget.TimeTextbox",
	dojo.widget.ValidationTextbox,
	{
		// summary: A TextBox which tests for a valid time
		// format: Deprecated. Described in v0.3 in dojo.validate.  Default is  "h:mm:ss t".
		// amSymbol: Deprecated. Used with format. The symbol used for AM.  Default is "AM" or "am".
		// pmSymbol: Deprecated. Used with format. The symbol used for PM.  Default is "PM" or "pm".

		// optional pattern used in display of formatted date.  Uses locale-specific format by default.  See dojo.date.format.
		displayFormat: "",
		// type of format appropriate to locale.  see dojo.date.format
		formatLength: "short",

		mixInProperties: function(/*Object*/localProperties){
			// summary: see dojo.widget.Widget

			// First initialize properties in super-class.
			dojo.widget.TimeTextbox.superclass.mixInProperties.apply(this, arguments);
	
			// Get properties from markup attributes, and assign to flags object.
			if(localProperties.format){ 
				this.flags.format = localProperties.format;
			}
			if(localProperties.amsymbol){ 
				this.flags.amSymbol = localProperties.amsymbol;
			}
			if(localProperties.pmsymbol){ 
				this.flags.pmSymbol = localProperties.pmsymbol;
			}
		},

		isValid: function(){ 
			// summary: see dojo.widget.ValidationTextbox
			if(this.flags.format){
				dojo.deprecated("dojo.widget.TimeTextbox", "format attribute is deprecated; use displayFormat or formatLength instead", "0.5");
				return dojo.validate.isValidTime(this.textbox.value, this.flags);
			}

			return dojo.date.parse(this.textbox.value, {formatLength:this.formatLength, selector:'timeOnly', locale:this.lang, timePattern: this.displayFormat});
		}
	}
);

__CPAN_FILE__ src/widget/ResizeHandle.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ResizeHandle");

dojo.require("dojo.widget.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.event.*");

dojo.widget.defineWidget(
	"dojo.widget.ResizeHandle",
	dojo.widget.HtmlWidget,
{
	isSizing: false,
	startPoint: null,
	startSize: null,
	minSize: null,

	targetElmId: '',

	templateCssPath: dojo.uri.dojoUri("src/widget/templates/ResizeHandle.css"),
	templateString: '<div class="dojoHtmlResizeHandle"><div></div></div>',

	postCreate: function(){
		dojo.event.connect(this.domNode, "onmousedown", this, "beginSizing");
	},

	beginSizing: function(e){
		if (this.isSizing){ return false; }

		// get the target dom node to adjust.  targetElmId can refer to either a widget or a simple node
		this.targetWidget = dojo.widget.byId(this.targetElmId);
		this.targetDomNode = this.targetWidget ? this.targetWidget.domNode : dojo.byId(this.targetElmId);
		if (!this.targetDomNode){ return; }

		this.isSizing = true;
		this.startPoint  = {'x':e.clientX, 'y':e.clientY};
		var mb = dojo.html.getMarginBox(this.targetDomNode);
		this.startSize  = {'w':mb.width, 'h':mb.height};

		dojo.event.kwConnect({
			srcObj: dojo.body(), 
			srcFunc: "onmousemove",
			targetObj: this,
			targetFunc: "changeSizing",
			rate: 25
		});
		dojo.event.connect(dojo.body(), "onmouseup", this, "endSizing");

		e.preventDefault();
	},

	changeSizing: function(e){
		// On IE, if you move the mouse above/to the left of the object being resized,
		// sometimes clientX/Y aren't set, apparently.  Just ignore the event.
		try{
			if(!e.clientX  || !e.clientY){ return; }
		}catch(e){
			// sometimes you get an exception accessing above fields...
			return;
		}
		var dx = this.startPoint.x - e.clientX;
		var dy = this.startPoint.y - e.clientY;
		
		var newW = this.startSize.w - dx;
		var newH = this.startSize.h - dy;

		// minimum size check
		if (this.minSize) {
			var mb = dojo.html.getMarginBox(this.targetDomNode);
			if (newW < this.minSize.w) {
				newW = mb.width;
			}
			if (newH < this.minSize.h) {
				newH = mb.height;
			}
		}
		
		if(this.targetWidget){
			this.targetWidget.resizeTo(newW, newH);
		}else{
			dojo.html.setMarginBox(this.targetDomNode, { width: newW, height: newH});
		}
		
		e.preventDefault();
	},

	endSizing: function(e){
		dojo.event.disconnect(dojo.body(), "onmousemove", this, "changeSizing");
		dojo.event.disconnect(dojo.body(), "onmouseup", this, "endSizing");

		this.isSizing = false;
	}


});

__CPAN_FILE__ src/widget/TreeNodeV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TreeNodeV3");

dojo.require("dojo.html.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TreeWithNode");

dojo.widget.defineWidget(
	"dojo.widget.TreeNodeV3",
	[dojo.widget.HtmlWidget, dojo.widget.TreeWithNode],
	function() {
		this.actionsDisabled = [];
	        this.object = {};
	},
{
	tryLazyInit: true,

	/*
	 * Basic actions one can perform on nodes and, some(addchild) on trees
	 */
	actions: {
		MOVE: "MOVE",
    	DETACH: "DETACH",
    	EDIT: "EDIT",
    	ADDCHILD: "ADDCHILD",
		SELECT: "SELECT"
	},
	
	
	labelClass: "",
	contentClass: "",

	expandNode: null,
	labelNode: null,
		
    /**
     *	can't call it nodeType cause of IE problems
     */
	nodeDocType: "",
    selected: false,
	
	getnodeDocType: function() {
		return this.nodeDocType;
	},
	
	cloneProperties: ["actionsDisabled","tryLazyInit","nodeDocType","objectId","object",
		   "title","isFolder","isExpanded","state"],
	
	
	/**
	 * copy cloneProperties with recursion into them
	 * contains "copy constructor"
	 */
	clone: function(deep) {
		var ret = new this.constructor();
		
		//dojo.debug("start cloning props "+this);
		
		for(var i=0; i<this.cloneProperties.length; i++) {
			var prop = this.cloneProperties[i];
			//dojo.debug("cloning "+prop+ ":" +this[prop]);
			ret[prop] = dojo.lang.shallowCopy(this[prop], true);			
		}
		
		if (this.tree.unsetFolderOnEmpty && !deep && this.isFolder) {
			ret.isFolder = false;
		}
		
		//dojo.debug("cloned props "+this);
		
		ret.toggleObj = this.toggleObj;
		
		dojo.widget.manager.add(ret);
		
		ret.tree = this.tree;
		ret.buildRendering({},{});
		ret.initialize({},{});
				
		if (deep && this.children.length) {
			//dojo.debug("deeper copy start");
			for(var i=0; i<this.children.length; i++) {
				var child = this.children[i];
				//dojo.debug("copy child "+child);
				if (child.clone) {
					ret.children.push(child.clone(deep));
				} else {
					ret.children.push(dojo.lang.shallowCopy(child, deep));
				}
			}
			//dojo.debug("deeper copy end");
			ret.setChildren();
		}
		
		
				
		return ret;
	},
				
			
	markProcessing: function() {
		this.markProcessingSavedClass = dojo.html.getClass(this.expandNode);
		dojo.html.setClass(this.expandNode, this.tree.classPrefix+'ExpandLoading');			
	},
	
	unmarkProcessing: function() {
		dojo.html.setClass(this.expandNode, this.markProcessingSavedClass);			
	},
	
	
	
	
	/**
	 * get information from args & parent, then build rendering
	 */
	buildRendering: function(args, fragment, parent) {
		//dojo.debug("Build for "+args.toSource());
		
		if (args.tree) {
			this.tree = dojo.lang.isString(args.tree) ? dojo.widget.manager.getWidgetById(args.tree) : args.tree;			
		} else if (parent && parent.tree) {
			this.tree = parent.tree;
		} 
		
		if (!this.tree) {
			dojo.raise("Can't evaluate tree from arguments or parent");
		}
		
		
		//dojo.profile.start("buildRendering - cloneNode");
		
		this.domNode = this.tree.nodeTemplate.cloneNode(true);
		this.expandNode = this.domNode.firstChild;
		this.contentNode = this.domNode.childNodes[1];
		this.labelNode = this.contentNode.firstChild;
		
		if (this.labelClass) {
			dojo.html.addClass(this.labelNode, this.labelClass);
		}
		
		if (this.contentClass) {
			dojo.html.addClass(this.contentNode, this.contentClass);
		}
		
		
		//dojo.profile.end("buildRendering - cloneNode");
		
		
		this.domNode.widgetId = this.widgetId;
		
		//dojo.profile.start("buildRendering - innerHTML");
		this.labelNode.innerHTML = this.title;
		//dojo.profile.end("buildRendering - innerHTML");
		
	},
	

	isTreeNode: true,

	
	object: {},

	title: "",
	
	isFolder: null, // set by widget depending on children/args

	contentNode: null, // the item label
	
	expandClass: "",


	isExpanded: false,
	

	containerNode: null,

	
	getInfo: function() {
		// No title here (title may be widget)
		var info = {
			widgetId: this.widgetId,
			objectId: this.objectId,
			index: this.getParentIndex()
		}

		return info;
	},
	
	setFolder: function() {
		//dojo.debug("SetFolder in "+this);
		this.isFolder = true;
		this.viewSetExpand();
		if (!this.containerNode) { // maybe this node was unfolderized and still has container
			this.viewAddContainer(); // all folders have container.
		}
		//dojo.debug("publish "+this.tree.eventNames.setFolder);
		dojo.event.topic.publish(this.tree.eventNames.afterSetFolder, { source: this });
	},
	
	
	
	initialize: function(args, frag, parent) {
		
		//dojo.profile.start("initialize");
		
		/**
		 * first we populate current widget from args,
		 * then use its data to initialize
		 * args may be empty, all data inside widget for copy constructor
		 */
		if (args.isFolder) {
			this.isFolder = true;
		}
		
		if (this.children.length || this.isFolder) {
			//dojo.debug("children found");
			//dojo.debug(this.children);
			//dojo.debug("isFolder "+args.isFolder);
			
			// viewSetExpand for Folder is set here also
			this.setFolder();			
		} else {
			// set expandicon for leaf 	
			this.viewSetExpand();
		}
		
		for(var i=0; i<this.actionsDisabled.length;i++) {
			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
		}
		//dojo.debug("publish "+this.tree.eventNames.changeTree);
		
		        

		dojo.event.topic.publish(this.tree.eventNames.afterChangeTree, {oldTree:null, newTree:this.tree, node:this} );
		
		
		//dojo.profile.end("initialize");
		
		//dojo.debug("initialize out "+this);
		//dojo.debug(this+" parent "+parent);
	},
		
	unsetFolder: function() {
		this.isFolder = false;
		this.viewSetExpand();		
		dojo.event.topic.publish(this.tree.eventNames.afterUnsetFolder, { source: this });
	},
	
	
	insertNode: function(parent, index) {
		
		if (!index) index = 0;
		//dojo.debug("insertNode "+this+" parent "+parent+" before "+index);
		
		if (index==0) {
			dojo.html.prependChild(this.domNode, parent.containerNode);
		} else {
			dojo.html.insertAfter(this.domNode, parent.children[index-1].domNode);
		}
	},
	
	updateTree: function(newTree) {

		if (this.tree === newTree) {
			return;
		}
		
		var oldTree = this.tree;
		
		
		dojo.lang.forEach(this.getDescendants(),
			function(elem) {			
				elem.tree = newTree;			
		});
		
		/**
		 * UNTESTED
		 * changes class prefix for all domnodes when moving between trees
		 */
		if (oldTree.classPrefix != newTree.classPrefix) {
			var stack = [this.domNode]
			var elem;
			var reg = new RegExp("(^|\\s)"+oldTree.classPrefix, "g");
			
			while (elem = stack.pop()) {
				for(var i=0; i<elem.childNodes.length; i++) {
					var childNode = elem.childNodes[i]
					if (childNode.nodeDocType != 1) continue;
					// change prefix for classes
					dojo.html.setClass(childNode, dojo.html.getClass(childNode).replace(reg, '$1'+newTree.classPrefix));
					stack.push(childNode);
				}
			}
			
		}
		
		var message = {oldTree:oldTree, newTree:newTree, node:this}
		
		dojo.event.topic.publish(this.tree.eventNames.afterChangeTree, message );		
		dojo.event.topic.publish(newTree.eventNames.afterChangeTree, message );
			
				
	},
	
	
	/**
	 * called every time the widget is added with createWidget or created wia markup
	 * from addChild -> registerChild or from postInitialize->registerChild
	 * not called in batch procession
	 * HTML & widget.createWidget only
	 * Layout MUST be removed when node is detached
	 * 
	 */
	addedTo: function(parent, index, dontPublishEvent) {
		//dojo.profile.start("addedTo");
		//dojo.debug(this + " addedTo "+parent+" index "+index);
		//dojo.debug(parent.children);
		//dojo.debug(parent.containerNode.innerHTML);
		
		//dojo.debug((new Error()).stack);
					
				
		if (this.tree !== parent.tree) {
			this.updateTree(parent.tree);
		}
		
		if (parent.isTreeNode) {
			if (!parent.isFolder) {
				//dojo.debug("folderize parent "+parent);
				parent.setFolder();
				parent.state = parent.loadStates.LOADED;
			}
		}
		
		
		var siblingsCount = parent.children.length;
		
		// setFolder works BEFORE insertNode
		this.insertNode(parent, index);
		
		
		this.viewAddLayout();
	
		
		//dojo.debug("siblings "+parent.children);
		
		if (siblingsCount > 1) {
			if (index == 0 && parent.children[1] instanceof dojo.widget.Widget) {
				parent.children[1].viewUpdateLayout();				
			}
			if (index == siblingsCount-1 && parent.children[siblingsCount-2] instanceof dojo.widget.Widget) {
				parent.children[siblingsCount-2].viewUpdateLayout();			
			}
		} else if (parent.isTreeNode) {
			// added as the first child
			//dojo.debug("added as first");
			parent.viewSetHasChildren();
		}
		
		if (!dontPublishEvent) {

			var message = {
				child: this,
				index: index,
				parent: parent
			}
				
			dojo.event.topic.publish(this.tree.eventNames.afterAddChild, message);
		}

		//dojo.profile.end("addedTo");
		
				
	},
	
	/**
	 * Fast program-only hacky creation of widget
	 * 	
	 */
	createSimple: function(args, parent) {
		// I pass no args and ignore default controller
		//dojo.profile.start(this.widgetType+" createSimple");
		//dojo.profile.start(this.widgetType+" createSimple constructor");
		if (args.tree) {
			var tree = args.tree;
		} else if (parent) {
			var tree = parent.tree;
		} else {
			dojo.raise("createSimple: can't evaluate tree");
		}
		tree = dojo.widget.byId(tree);
		
		//dojo.debug(tree);
		
		var treeNode = new tree.defaultChildWidget(); 
		//dojo.profile.end(this.widgetType+" createSimple constructor");
		
		//dojo.profile.start(this.widgetType+" createSimple mixin");		
		for(var x in args){ // fastMixIn			
			treeNode[x] = args[x];
		}
		
		
		//dojo.profile.end(this.widgetType+" createSimple mixin");
		
				
		// HtmlWidget.postMixIn 
		treeNode.toggleObj = dojo.lfx.toggle[treeNode.toggle.toLowerCase()] || dojo.lfx.toggle.plain;

		//dojo.profile.start(this.widgetType + " manager");
		dojo.widget.manager.add(treeNode);
		//dojo.profile.end(this.widgetType + " manager");
		
		//dojo.profile.start(this.widgetType + " buildRendering");
		treeNode.buildRendering(args, {}, parent);		
		//dojo.profile.end(this.widgetType + " buildRendering");
		
		treeNode.initialize(args, {}, parent);
		
		//dojo.profile.end(this.widgetType+"createSimple");
		if (treeNode.parent) {
			delete dojo.widget.manager.topWidgets[treeNode.widgetId];
		}
		
		return treeNode;
	},
	
	
	
	// can override e.g for case of div with +- text inside
	viewUpdateLayout: function() {
		//dojo.profile.start("viewUpdateLayout");
		//dojo.debug("UpdateLayout in "+this);

		this.viewRemoveLayout();
		this.viewAddLayout();
		//dojo.profile.end("viewUpdateLayout");	
	},
	
	
	viewAddContainer: function() {
		// make controller only if children exist
		this.containerNode = this.tree.containerNodeTemplate.cloneNode(true);
		this.domNode.appendChild(this.containerNode);
	},
	/*
	viewRemoveContainer: function() {
		// make controller only if children exist
		this.domNode.removeChild(this.containerNode);
		this.containerNode = null;
	},
	*/
	
	viewAddLayout: function() {
		//dojo.profile.start("viewAddLayout");
		//dojo.debug("viewAddLayout in "+this);
		
		if (this.parent["isTree"]) {
			//dojo.debug("Parent isTree => add isTreeRoot");
			
			// use setClass, not addClass for speed
			dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode) + ' '+this.tree.classPrefix+'IsRoot')
		}
		//dojo.debug(this.parent.children.length);
		//dojo.debug(this.parent.children[this.parent.children.length-1]);
		if (this.isLastChild()) {
			//dojo.debug("Checked last node for "+this);
			//dojo.debug("Parent last is "+this.parent.children[this.parent.children.length-1]);
			//dojo.debug("last node => add isTreeLast for "+this);
			dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode) + ' '+this.tree.classPrefix+'IsLast')			
		}
		//dojo.profile.end("viewAddLayout");
		//dojo.debug("viewAddLayout out");
		
	},
	
	
	viewRemoveLayout: function() {		
		//dojo.debug("viewRemoveLayout in "+this);
		//dojo.profile.start("viewRemoveLayout");
		//dojo.debug((new Error()).stack);
		dojo.html.removeClass(this.domNode, this.tree.classPrefix+"IsRoot");
		dojo.html.removeClass(this.domNode, this.tree.classPrefix+"IsLast");
		//dojo.profile.end("viewRemoveLayout");
	},
		
	viewGetExpandClass: function() {
		if (this.isFolder) {			
			return this.isExpanded ? "ExpandOpen" : "ExpandClosed";
		} else {
			return "ExpandLeaf";
		}
	},
	
	viewSetExpand: function() {
		//dojo.profile.start("viewSetExpand");
		
		//dojo.debug("viewSetExpand in "+this);
		
		var expand = this.tree.classPrefix+this.viewGetExpandClass();
		var reg = new RegExp("(^|\\s)"+this.tree.classPrefix+"Expand\\w+",'g');			
			
		dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode).replace(reg,'') + ' '+expand);
		
		//dojo.debug(dojo.html.getClass(this.domNode))
		//dojo.profile.end("viewSetExpand");
		this.viewSetHasChildrenAndExpand();
	},	

	viewGetChildrenClass: function() {
		return 'Children'+(this.children.length ? 'Yes' : 'No');
	},
	
	viewSetHasChildren: function() {		
		//dojo.debug(this+' '+this.children.length)
		
		var clazz = this.tree.classPrefix+this.viewGetChildrenClass();

		var reg = new RegExp("(^|\\s)"+this.tree.classPrefix+"Children\\w+",'g');			
		
		dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode).replace(reg,'') + ' '+clazz);
		
		this.viewSetHasChildrenAndExpand();
	},
	
	/**
	 * set TreeStateChildrenYes-ExpandClosed pair
	 * needed for IE, because IE reads only last class from .TreeChildrenYes.TreeExpandClosed pair
	 */
	viewSetHasChildrenAndExpand: function() {
		var clazz = this.tree.classPrefix+'State'+this.viewGetChildrenClass()+'-'+this.viewGetExpandClass();
		
		var reg = new RegExp("(^|\\s)"+this.tree.classPrefix+"State[\\w-]+",'g');			
		
		dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode).replace(reg,'') + ' '+clazz);		
	},
		
	viewUnfocus: function() {
		dojo.html.removeClass(this.labelNode, this.tree.classPrefix+"LabelFocused");
	},
	
	viewFocus: function() {
		dojo.html.addClass(this.labelNode, this.tree.classPrefix+"LabelFocused");
	},
    
    viewEmphase: function() {
        dojo.html.clearSelection(this.labelNode);
        
		dojo.html.addClass(this.labelNode, this.tree.classPrefix+'NodeEmphased');
    },
    
    viewUnemphase: function() {
        dojo.html.removeClass(this.labelNode, this.tree.classPrefix+'NodeEmphased');
    },
	
	
// ================================ detach from parent ===================================

	detach: function() {
		if (!this.parent) return;

		var parent = this.parent;
		var index = this.getParentIndex();

		this.doDetach.apply(this, arguments);

		dojo.event.topic.publish(this.tree.eventNames.afterDetach,
			{ child: this, parent: parent, index:index }
		);
		
	},
	

	/* node does not leave tree */
	doDetach: function() {
		//dojo.debug("doDetach in "+this+" parent "+this.parent+" class "+dojo.html.getClass(this.domNode));
				
		var parent = this.parent;
		
		//dojo.debug(parent.containerNode.style.display)
		
		if (!parent) return;
		
		var index = this.getParentIndex();
		
		
		this.viewRemoveLayout();
		
		dojo.widget.DomWidget.prototype.removeChild.call(parent, this);
		
		var siblingsCount = parent.children.length;
		
		//dojo.debug("siblingsCount "+siblingsCount);
		
		if (siblingsCount > 0) {
			if (index == 0) {	// deleted first node => update new first
				parent.children[0].viewUpdateLayout();		
			}
			if (index == siblingsCount) { // deleted last node
				parent.children[siblingsCount-1].viewUpdateLayout();		
			}
		} else {
			if (parent.isTreeNode) {
				parent.viewSetHasChildren();
			}
		}
				
		if (this.tree.unsetFolderOnEmpty && !parent.children.length && parent.isTreeNode) {
			parent.unsetFolder();
		}		
		
		//dojo.debug(parent.containerNode.style.display)
		
		this.parent = null;
	},
	
	
	/**
	 * publish destruction event so that controller may unregister/unlisten
	 */
	destroy: function() {
		
		dojo.event.topic.publish(this.tree.eventNames.beforeNodeDestroy, { source: this } );
		
		this.detach();		

		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
	},
	
	
	expand: function(){
        		
		if (this.isExpanded) return;


		//dojo.profile.start("expand "+this);
		
		//dojo.debug("expand in "+this);
		
		//dojo.profile.start("expand - lazy init "+this);
		if (this.tryLazyInit) {
			this.setChildren();
			this.tryLazyInit = false;
		}
		
		//dojo.profile.end("expand - lazy init "+this);
		
		
		this.isExpanded = true;

		this.viewSetExpand();

		//dojo.profile.start("expand - showChildren "+this);
		
		/**
		 * no matter if I have children or not. need to show/hide container anyway.
		 * use case: empty folder is expanded => then child is added, container already shown all fine
		 */
		this.showChildren();
		
		//dojo.profile.end("expand - showChildren "+this);
						
		
		//dojo.profile.end("expand "+this);
	},


	collapse: function(){
						
		if (!this.isExpanded) return;
		
		this.isExpanded = false;
		
		this.hideChildren();
	},


	hideChildren: function(){
		this.tree.toggleObj.hide(
			this.containerNode, this.tree.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onHideChildren")
		);
	},


	showChildren: function(){
		//dojo.profile.start("showChildren"+this);
        
		this.tree.toggleObj.show(
			this.containerNode, this.tree.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onShowChildren")
		);
        
		//dojo.profile.end("showChildren"+this);
	},
	 
    
    
	onShowChildren: function() {
        
		//dojo.profile.start("onShowChildren"+this);
        
        this.onShow();
        
		//dojo.profile.end("onShowChildren"+this);
        
		dojo.event.topic.publish(this.tree.eventNames.afterExpand, {source: this} );		
	},
	
	onHideChildren: function() {

		this.viewSetExpand();
		this.onHide();
		dojo.event.topic.publish(this.tree.eventNames.afterCollapse, {source: this} );
	},

	/* Edit current node : change properties and update contents */
	setTitle: function(title) {
		var oldTitle = this.title;
		
		this.labelNode.innerHTML = this.title = title;
				
		dojo.event.topic.publish(this.tree.eventNames.afterSetTitle, { source: this, oldTitle:oldTitle });

	},


	toString: function() {
		return '['+this.widgetType+', '+this.title+']';
	}


});

__CPAN_FILE__ src/widget/DropdownTimePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.DropdownTimePicker");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.DropdownContainer");
dojo.require("dojo.widget.TimePicker");
dojo.require("dojo.event.*");
dojo.require("dojo.html.*");
dojo.require("dojo.date.format");
dojo.require("dojo.date.serialize");
dojo.require("dojo.i18n.common");
dojo.requireLocalization("dojo.widget", "DropdownTimePicker");

// summary
//	input box with a drop-down gui control, for setting the time (hours, minutes, seconds, am/pm) of an event
dojo.widget.defineWidget(
	"dojo.widget.DropdownTimePicker",
	dojo.widget.DropdownContainer,
	{
		// URL
		//	path of icon for button to display time picker widget
		iconURL: dojo.uri.dojoUri("src/widget/templates/images/timeIcon.gif"),
		
		// Number
		//	z-index of time picker widget
		zIndex: "10",

		// pattern used in display of formatted time.  Uses locale-specific format by default.  See dojo.date.format.
		displayFormat: "",

		// String
		//	Deprecated. format string for how time is displayed in the input box using strftime, see dojo.date.strftime	
		timeFormat: "",

//FIXME: need saveFormat attribute support

		// type of format appropriate to locale.  see dojo.date.format
		formatLength: "short",

		// String
		//	time value in RFC3339 format (http://www.ietf.org/rfc/rfc3339.txt)
		//	ex: 12:00
		value: "",

		postMixInProperties: function() {
			dojo.widget.DropdownTimePicker.superclass.postMixInProperties.apply(this, arguments);
			var messages = dojo.i18n.getLocalization("dojo.widget", "DropdownTimePicker", this.lang);
			this.iconAlt = messages.selectTime;
		},

		fillInTemplate: function(){
			dojo.widget.DropdownTimePicker.superclass.fillInTemplate.apply(this, arguments);

			var timeProps = { widgetContainerId: this.widgetId, lang: this.lang };
			this.timePicker = dojo.widget.createWidget("TimePicker", timeProps, this.containerNode, "child");
			dojo.event.connect(this.timePicker, "onSetTime", this, "onSetTime");
			dojo.event.connect(this.inputNode,  "onchange",  this, "onInputChange");
			this.containerNode.style.zIndex = this.zIndex;
			this.containerNode.explodeClassName = "timeBorder";
			if(this.value){
				this.timePicker.selectedTime.anyTime = false;
				this.timePicker.setDateTime("2005-01-01T" + this.value);
				this.timePicker.initData();
				this.timePicker.initUI();
				this.onSetTime();
			}
		},
		
		onSetTime: function(){
			// summary: callback when user sets the time via the TimePicker widget
			if(this.timePicker.selectedTime.anyTime){
				this.inputNode.value = "";
			}else if(this.timeFormat){
				dojo.deprecated("dojo.widget.DropdownTimePicker",
				"Must use displayFormat attribute instead of timeFormat.  See dojo.date.format for specification.", "0.5");
				this.inputNode.value = dojo.date.strftime(this.timePicker.time, this.timeFormat, this.lang);
			}else{
				this.inputNode.value = dojo.date.format(this.timePicker.time,
					{formatLength:this.formatLength, datePattern:this.displayFormat, selector:'timeOnly', locale:this.lang});
			}

			this.hideContainer();
		},
		
		onInputChange: function(){
			// summary: callback when the user has typed in a time value manually
			this.timePicker.time = "2005-01-01T" + this.inputNode.value; //FIXME: i18n
			this.timePicker.setDateTime(this.timePicker.time);
			this.timePicker.initData();
			this.timePicker.initUI();
		},
		
		enable: function() {
			// summary: enable this widget to accept user input
			this.inputNode.disabled = false;
			this.timePicker.enable();
			dojo.widget.DropdownTimePicker.superclass.enable.apply(this, arguments);
		},
		
		disable: function() {
			// summary: lock this widget so that the user can't change the value
			this.inputNode.disabled = true;
			this.timePicker.disable();
			dojo.widget.DropdownTimePicker.superclass.disable.apply(this, arguments);
		}
	}
);

__CPAN_FILE__ src/widget/Show.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Show");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.event.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.math.curves");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");

dojo.widget.defineWidget(
	"dojo.widget.Show",
	dojo.widget.HtmlWidget,
	function(){
		this._slides=[];
	},
	{
	isContainer: true,
	_slide: -1,

	body: null,
	nav: null,
	hider: null,
	select: null,
	option: null,
	inNav: false,
	debugPane: null,
	noClick: false,
	templatePath: dojo.uri.dojoUri("src/widget/templates/Show.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Show.css"),
	fillInTemplate: function(args, frag){
		if(args.debugPane){
			var dp = this.debugPane = dojo.widget.byId(args.debugPane);
			dp.hide();
			dojo.event.connect(dp, "closeWindow", dojo.lang.hitch(this, function(){ this.debugPane = false; }));
		}
		var source = this.getFragNodeRef(frag);
		this.sourceNode = dojo.body().appendChild(source.cloneNode(true));
		for(var i = 0, child; child = this.sourceNode.childNodes[i]; i++){
			if(child.tagName && child.getAttribute("dojotype").toLowerCase() == "showslide"){
				child.className = "dojoShowPrintSlide";
				child.innerHTML = "<h1>" + child.title + "</h1>" + child.innerHTML;
			}
		}
		this.sourceNode.className = "dojoShowPrint";
		this.sourceNode.style.display = "none";
		
		dojo.event.connect(document, "onclick", this, "gotoSlideByEvent");
		if(dojo.render.html.ie) {
			dojo.event.connect(document,"onkeydown",this, "gotoSlideByEvent");
		} else {
			// while keydown works, keypress allows rapid successive key presses
			// to be handled correctly
			dojo.event.connect(document,"onkeypress",this, "gotoSlideByEvent");
		}
		dojo.event.connect(window, "onresize", this, "resizeWindow");
		dojo.event.connect(this.nav, "onmousemove", this, "popUpNav");
	},
	postCreate: function(){
		this._slides = [];
		for(var i = 0, child; child = this.children[i]; i++){
			if(child.widgetType == "ShowSlide"){
				this._slides.push(child);
				this.option.text = child.title+" ("+(i+1)+")";
				this.option.parentNode.insertBefore(this.option.cloneNode(true), this.option);
			}
		}
		this.option.parentNode.removeChild(this.option);
		this.domNode.style.display = "block";
		this.resizeWindow();

		this.gotoSlide(0, true);

		// check to see if we're initialized from a particular slide
		dojo.addOnLoad(dojo.lang.hitch(this, 
			function(){
				var th = window.location.hash;
				if(th.length){
					var parts = (""+window.location).split(this.widgetId+"_SlideNo_");
					if(parts.length > 1){
						setTimeout(dojo.lang.hitch(this, function(){
							this.gotoSlide(parseInt(parts[1]), true);
						}), 300);
					}
				}
			})
		);
	},
	gotoSlide: function(/*int*/ slide, /*Boolean*/preventSetHash){
		if(slide == this._slide){
			return;
		}

		if(!this._slides[slide]){
			// slide: string
			for(var i = 0, child; child = this._slides[i]; i++){
				if(child.title == slide){
					slide = i;
					break;
				}
			}
		}
		
		if(!this._slides[slide]){
			return;
		}

		if(this.debugPane){
			if(this._slides[slide].debug){
				this.debugPane.show();
			}else{
				this.debugPane.hide();
			}
		}
		
		if(this._slide != -1){
			while(this._slides[this._slide].previousAction()){}
		}

		if(!preventSetHash){
			window.location.href = "#"+this.widgetId+"_SlideNo_"+slide;
		}
		if(this._slides[this._slide]){
			this._slides[this._slide].hide();
		}
		
		this._slide = slide;
		this.select.selectedIndex = slide;
		var cn = this.contentNode;
		while(cn.firstChild){ cn.removeChild(cn.firstChild); }
		cn.appendChild(this._slides[slide].domNode);
		this._slides[slide].show();
	},
	gotoSlideByEvent: function(/*Event*/ event){
		var node = event.target;
		var type = event.type;
		if(type == "click"){
			if(node.tagName == "OPTION" && node.parentNode == this.select){
				this.gotoSlide(node.index);
			}else if(node == this.select){
				this.gotoSlide(node.selectedIndex);
			}else{
				this.nextSlide(event);
			}
		}else if (type=="keydown" || type=="keypress") {
			var key = event.keyCode;
			var ch = event.charCode;
			if(key == 63234 || key == 37){
				this.previousSlide(event);
			}else if(key == 63235 || key == 39 || ch == 32){
				this.nextSlide(event);
			}
		}
	},
	nextSlide: function(/*Event?*/ event){
		if(!this.stopEvent(event)){
			return false;
		}
		if(!this._slides[this._slide].nextAction(event)){
			if((this._slide + 1) != this._slides.length){
				this.gotoSlide(this._slide + 1);
				return true; // boolean
			}
			return false; // boolean
		}
	},
	previousSlide: function(/*Event?*/ event){
		if(!this.stopEvent(event)){
			return false;
		}
		if(!this._slides[this._slide].previousAction(event)){
			if((this._slide - 1) != -1){
				this.gotoSlide(this._slide - 1);
				return true; // boolean
			}
			return false; // boolean
		}
	},

	stopEvent: function(/*Event*/ ev){
		if(!ev){
			return true;
		}
	
		if (ev.type == "click" && (this._slides[this._slide].noClick || this.noClick)) {
			return false;
		}	
		var target = ev.target;
		// Check to see if the target is below the show domNode
		while(target != null){
			if(target == this.domNode){
				target = ev.target;
				break;
			}
			target = target.parentNode;
		}
		// Now that we know it's below this widget's domNode, we bubble up until we get to our domNode
		while(target && target != this.domNode){
			if(target.tagName == "A" || target.tagName == "INPUT" || target.tagName == "TEXTAREA" || target.tagName == "SELECT"){
				return false;
			}
			if(typeof target.onclick == "function" || typeof target.onkeypress == "function"){
				return false;
			}
			target = target.parentNode;
		}
		
		if(window.event){
			ev.returnValue = false;
			ev.cancelBubble = true;
		}else{
			ev.preventDefault();
			ev.stopPropagation();
		}
		
		return true;
	},
	popUpNav: function(){
		if(!this.inNav){
			// dojo.widget.Show.node = this.nav;
			dojo.lfx.propertyAnimation(this.nav, {
				"height": { start: 5, end: 30 }
			}, 250).play();
		}
		clearTimeout(this.inNav);
		this.inNav = setTimeout(dojo.lang.hitch(this, "hideNav"), 2000);
	},
	hideNav: function(){
		clearTimeout(this.inNav);
		this.inNav = false;
		// dojo.widget.Show.node = this.nav;
		dojo.lfx.propertyAnimation(this.nav, {
			"height": { start: 30, end: 5 }
		}, 250).play();
	},
	resizeWindow: function(/*Event*/ ev){
		dojo.body().style.height = "auto";
		var h = Math.max(
			document.documentElement.scrollHeight || dojo.body().scrollHeight,
			dojo.html.getViewport().height);
		dojo.body().style.height = h + "px";
	}
});

__CPAN_FILE__ src/widget/LayoutContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.LayoutContainer");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.html.layout");

// summary
//	Provides Delphi-style panel layout semantics.
//
// details
//	A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
//	that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
//	It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
//	and then it takes the child marked "client" and puts it into the remaining space in the middle.
//
//  Left/right positioning is similar to CSS's "float: left" and "float: right",
//	and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
//	CSS.
//
//	Note that there can only be one client element, but there can be multiple left, right, top,
//	or bottom elements.
//
// usage
//	<style>
//		html, body{ height: 100%; width: 100%; }
//	</style>
//	<div dojoType="LayoutContainer" style="width: 100%; height: 100%">
//		<div dojoType="ContentPane" layoutAlign="top">header text</div>
//		<div dojoType="ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div>
//		<div dojoType="ContentPane" layoutAlign="client">client area</div>
//	</div>
dojo.widget.defineWidget(
	"dojo.widget.LayoutContainer",
	dojo.widget.HtmlWidget,
{
	isContainer: true,

	// String
	//	- If the value is "top-bottom", then LayoutContainer will first position the "top" and "bottom" aligned elements,
	//	to and then put the left and right aligned elements in the remaining space, between the top and the bottom elements.
	//	It aligns the client element at the very end, in the remaining space.
	//
	//	- If the value is "left-right", then it first positions the "left" and "right" elements, and then puts the
	//	"top" and "bottom" elements in the remaining space, between the left and the right elements.
	//	It aligns the client element at the very end, in the remaining space.
	//
	//	- If the value is "none", then it will lay out each child in the natural order the children occur in.
	//	Basically each child is laid out into the "remaining space", where "remaining space" is initially
	//	the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
	//	
	layoutChildPriority: 'top-bottom',

	postCreate: function(){
		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
	},

	addChild: function(child, overrideContainerNode, pos, ref, insertIndex){
		dojo.widget.LayoutContainer.superclass.addChild.call(this, child, overrideContainerNode, pos, ref, insertIndex);
		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
	},

	removeChild: function(pane){
		dojo.widget.LayoutContainer.superclass.removeChild.call(this,pane);
		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
	},

	onResized: function(){
		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
	},

	show: function(){
		// If this node was created while display=="none" then it
		// hasn't been laid out yet.  Do that now.
		this.domNode.style.display="";
		this.checkSize();
		this.domNode.style.display="none";
		this.domNode.style.visibility="";

		dojo.widget.LayoutContainer.superclass.show.call(this);
	}
});

// This argument can be specified for the children of a LayoutContainer.
// Since any widget can be specified as a LayoutContainer child, mix it
// into the base widget class.  (This is a hack, but it's effective.)
dojo.lang.extend(dojo.widget.Widget, {
	layoutAlign: 'none'
});

__CPAN_FILE__ src/widget/TreeExpandOnSelect.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeExpandOnSelect");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeSelectorV3");
dojo.require("dojo.html.selection");

/**
 * when a node is selected, expands tree to make it visible
 * useful for program expansion
 */
dojo.widget.defineWidget(
	"dojo.widget.TreeExpandOnSelect",
	dojo.widget.HtmlWidget,
{
	selector: "",
	controller: "",
	
	initialize: function() {
		this.selector = dojo.widget.byId(this.selector);
		this.controller = dojo.widget.byId(this.controller);
		
		dojo.event.topic.subscribe(this.selector.eventNames.select, this, "onSelect");	
	},

	
	onSelect: function(message) {
		this.controller.expandToNode(message.node)
	}
	
	

});

__CPAN_FILE__ src/widget/ShowSlide.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.ShowSlide");

dojo.require("dojo.widget.*");
dojo.require("dojo.lang.common");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.lfx.html");
dojo.require("dojo.html.display");
dojo.require("dojo.html.layout");
dojo.require("dojo.animation.Animation");
dojo.require("dojo.gfx.color");

dojo.widget.defineWidget(
	"dojo.widget.ShowSlide",
	dojo.widget.HtmlWidget,
{
	title: "",
	_action: -1,
	isContainer: true,
	_components: {},
	_actions: [],

	gotoAction: function(/*int*/ action){
		this._action = action;
	},
	_nextAction: function(/*Event?*/ event){
		if((this._action + 1) != this._actions.length){
			++this._action;
			return true; // boolean
		}
		return false; // boolean
	},
	_previousAction: function(/*Event?*/ event){
		if((this._action - 1) != -1){
			--this._action;
			return true; // boolean
		}
		return false; // boolean
	},

	htmlTitle: null,
	debug: false,
	noClick: false,
	templatePath: dojo.uri.dojoUri("src/widget/templates/ShowSlide.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/ShowSlide.css"),
	postCreate: function(){
		this.htmlTitle.innerHTML = this.title;

		var actions = this.getChildrenOfType("ShowAction", false);
		var atypes = {};
		dojo.lang.forEach(actions, function(act){ atypes[act.on] = true; });

		this._components = {};
		var cn = this.containerNode;
		var nodes = dojo.render.html.ie ? cn.all : cn.getElementsByTagName('*');
		dojo.lang.forEach(nodes, function(node){
			var as = node.getAttribute("as");
			if(as){
				if(!this._components[as]){
					this._components[as] = [];
				}
				this._components[as].push(node);
				if(!atypes[as]){
					var tmpAction = dojo.widget.createWidget("ShowAction", { on: as });
					this.addChild(tmpAction);
					atypes[as] = true;
				}
			}
		}, this);

		this._actions = [];
		actions = this.getChildrenOfType("ShowAction", false);
		dojo.lang.forEach(actions, function(child){
			this._actions.push(child);
			var components = this._components[child.on];
			for(var j = 0, component; component = components[j]; j++){
				if(child["action"] && (
					(child.action != "remove")&&
					(child.action != "fadeout")&&
					(child.action != "wipeout")
				) ){
					this.hideComponent(component);
				}
			}
		}, this);
	},

	previousAction: function(/*Event?*/ event){
		if(!this.parent.stopEvent(event)){
			return false;
		}

		var action = this._actions[this._action];
		if(!action){
			return false;
		}

		var on = action.on;
		while(action.on == on){
			var components = this._components[on];
			for(var i = 0, component; component = components[i]; i++){
				if(
					(action.action == "remove")||
					(action.action == "fadeout")||
					(action.action == "wipeout")
				){
					if(component.style.display == "none"){
						component.style.display = "";
						component.style.visibility = "visible";
						var exits = true;
					}
					dojo.html.setOpacity(component, 1);
				}else if(action.action){
					this.hideComponent(component);
				}
			}

			--this._action;

			if(exits){
				return true;
			}	

			if(action.auto == "true"){
				on = this._actions[this._action].on;
			}

			action = this._actions[this._action];
			if(!action){
				return false;
			}
		}
		return true;
	},
	hideComponent: function(/*Node*/ component){
		component.style.visibility = "hidden";
		component.style.backgroundColor = "transparent";
		var parent = component.parentNode;
		if((parent)&&(parent.tagName.toLowerCase() == "li")){
			parent.oldType = parent.style.listStyleType;
			parent.style.listStyleType = "none";
		}
	},
	nextAction: function(/*Event?*/ event){
		if(!this.parent.stopEvent(event)){
			return false;
		}

		if(!this._nextAction(this)){
			return false;
		}

		var action = this._actions[this._action];
		if(!action){
			return false;
		}
		var tmpAction = action["action"];
		
		var components = this._components[action.on];
		for(var i = 0, component; component = components[i]; i++){
			if(tmpAction){
				var duration = action.duration || 1000;
				if((tmpAction == "fade")||(tmpAction == "fadeIn")){
					dojo.html.setOpacity(component, 0);
					dojo.lfx.html.fadeShow(component, duration).play(true);
				}else if(tmpAction == "fadeout"){
					dojo.lfx.html.fadeHide(component, duration).play(true);
				}else if(tmpAction == "fly"){
					var width = dojo.html.getMarginBox(component).width;
					var position = dojo.html.getAbsolutePosition(component);
					// alert(position);
					component.style.position = "relative";
					component.style.left = -(width + position.x) + "px";
					dojo.lfx.html.slideBy(component, { top: 0, left: (width + position.x)}, duration, -1, this.callWith).play(true);
				}else if((tmpAction == "wipe")||(tmpAction == "wipein")){
					dojo.lfx.html.wipeIn(component, duration).play();
				}else if(tmpAction == "wipeout"){
					dojo.lfx.html.wipeOut(component, duration).play();
				}else if(tmpAction == "color"){
					var from = new dojo.gfx.color.Color(action.from).toRgb();
					var to = new dojo.gfx.color.Color(action.to).toRgb();
					var anim = new dojo.animation.Animation(new dojo.math.curves.Line(from, to), duration, 0);
					var node = component;
					dojo.event.connect(anim, "onAnimate", function(e) {
						node.style.color = "rgb(" + e.coordsAsInts().join(",") + ")";
					});
					anim.play(true);
				}else if(tmpAction == "bgcolor"){
					dojo.lfx.html.unhighlight(component, action.to, duration).play();
				}else if(tmpAction == "remove"){
					component.style.display = "none";
				}

				if(tmpAction == "hide"){
					component.style.visibility = "hidden";
				}else{
					component.style.visibility = "visible";
				}
			}
		}
		
		action = this._actions[this._action + 1];
		if(action && action.auto == "true"){
			this.nextAction();
		}

		return true;
	},
	callWith: function(/*Node*/ node){
		if(!node){ return; }
		if(dojo.lang.isArray(node)){
			dojo.lang.forEach(node, arguments.callee);
			return;
		}
		var parent = node.parentNode;
		if((parent)&&(parent.tagName.toLowerCase() == "li")){
			parent.style.listStyleType = parent.oldType;
		}
	}
});

__CPAN_FILE__ src/widget/TreeBasicController.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeBasicController");

dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");


dojo.widget.defineWidget("dojo.widget.TreeBasicController", dojo.widget.HtmlWidget, {
	widgetType: "TreeBasicController",

	DNDController: "",

	dieWithTree: false,

	initialize: function(args, frag){

		/* no DND by default for compatibility */
		if (this.DNDController == "create") {
			dojo.require("dojo.dnd.TreeDragAndDrop");
			this.DNDController = new dojo.dnd.TreeDNDController(this);
		}



	},


	/**
	 * Binds controller to all tree events
	*/
	listenTree: function(tree) {
		//dojo.debug("Event "+tree.eventNames.treeClick);
		dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
		dojo.event.topic.subscribe(tree.eventNames.treeClick, this, "onTreeClick");
		dojo.event.topic.subscribe(tree.eventNames.treeCreate, this, "onTreeCreate");
		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");

		if (this.DNDController) {
			this.DNDController.listenTree(tree);
		}
	},

	unlistenTree: function(tree) {
		dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
		dojo.event.topic.unsubscribe(tree.eventNames.treeClick, this, "onTreeClick");
		dojo.event.topic.unsubscribe(tree.eventNames.treeCreate, this, "onTreeCreate");
		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
	},

	onTreeDestroy: function(message) {
		var tree = message.source;

		this.unlistenTree(tree);

		if (this.dieWithTree) {
			//alert("Killing myself "+this.widgetId);
			this.destroy();
			//dojo.debug("done");
		}
	},

	onCreateDOMNode: function(message) {

		var node = message.source;


		if (node.expandLevel > 0) {
			this.expandToLevel(node, node.expandLevel);
		}
	},

	// perform actions-initializers for tree
	onTreeCreate: function(message) {
		var tree = message.source;
		var _this = this;
		if (tree.expandLevel) {
			dojo.lang.forEach(tree.children,
				function(child) {
					_this.expandToLevel(child, tree.expandLevel-1)
				}
			);
		}
	},

	expandToLevel: function(node, level) {
		if (level == 0) return;

		var children = node.children;
		var _this = this;

		var handler = function(node, expandLevel) {
			this.node = node;
			this.expandLevel = expandLevel;
			// recursively expand opened node
			this.process = function() {
				//dojo.debug("Process "+node+" level "+level);
				for(var i=0; i<this.node.children.length; i++) {
					var child = node.children[i];

					_this.expandToLevel(child, this.expandLevel);
				}
			};
		}

		var h = new handler(node, level-1);


		this.expand(node, false, h, h.process);

	},




	onTreeClick: function(message){
		var node = message.source;

		if(node.isLocked()) {
			return false;
		}

		if (node.isExpanded){
			this.collapse(node);
		} else {
			this.expand(node);
		}
	},

	expand: function(node, sync, callObj, callFunc) {
		node.expand();
		if (callFunc) callFunc.apply(callObj, [node]);
	},

	collapse: function(node) {

		node.collapse();
	},

// =============================== move ============================

	/**
	 * Checks whether it is ok to change parent of child to newParent
	 * May incur type checks etc
	 *
	 * It should check only hierarchical possibility w/o index, etc
	 * because in onDragOver event for Between DND mode we can't calculate index at once on onDragOVer.
	 * index changes as client moves mouse up-down over the node
	 */
	canMove: function(child, newParent){

		if (child.actionIsDisabled(child.actions.MOVE)) {
			return false;
		}

		// if we move under same parent then no matter if ADDCHILD disabled for him
		// but if we move to NEW parent then check if action is disabled for him
		// also covers case for newParent being a non-folder in strict mode etc
		if (child.parent !== newParent && newParent.actionIsDisabled(newParent.actions.ADDCHILD)) {
			return false;
		}

		// Can't move parent under child. check whether new parent is child of "child".
		var node = newParent;
		while(node.isTreeNode) {
			//dojo.debugShallow(node.title)
			if (node === child) {
				// parent of newParent is child
				return false;
			}
			node = node.parent;
		}

		return true;
	},


	move: function(child, newParent, index) {

		/* move sourceTreeNode to new parent */
		if (!this.canMove(child, newParent)) {
			return false;
		}

		var result = this.doMove(child, newParent, index);

		if (!result) return result;

		if (newParent.isTreeNode) {
			this.expand(newParent);
		}

		return result;
	},

	doMove: function(child, newParent, index) {
		child.tree.move(child, newParent, index);

		return true;
	},

// =============================== removeNode ============================


	canRemoveNode: function(child) {
		if (child.actionIsDisabled(child.actions.REMOVE)) {
			return false;
		}

		return true;
	},


	removeNode: function(node, callObj, callFunc) {
		if (!this.canRemoveNode(node)) {
			return false;
		}

		return this.doRemoveNode(node, callObj, callFunc);
	},


	doRemoveNode: function(node, callObj, callFunc) {
		node.tree.removeNode(node);

		if (callFunc) {
			callFunc.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node]);
		}
	},


	// -----------------------------------------------------------------------------
	//                             Create node stuff
	// -----------------------------------------------------------------------------


	canCreateChild: function(parent, index, data) {
		if (parent.actionIsDisabled(parent.actions.ADDCHILD)) return false;

		return true;
	},


	/* send data to server and add child from server */
	/* data may contain an almost ready child, or anything else, suggested to server */
	/*in RPC controllers server responds with child data to be inserted */
	createChild: function(parent, index, data, callObj, callFunc) {
		if (!this.canCreateChild(parent, index, data)) {
			return false;
		}

		return this.doCreateChild.apply(this, arguments);
	},

	doCreateChild: function(parent, index, data, callObj, callFunc) {

		var widgetType = data.widgetType ? data.widgetType : "TreeNode";

		var newChild = dojo.widget.createWidget(widgetType, data);

		parent.addChild(newChild, index);

		this.expand(parent);

		if (callFunc) {
			callFunc.apply(callObj, [newChild]);
		}

		return newChild;
	}



});

__CPAN_FILE__ src/widget/Spinner.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Spinner");

dojo.require("dojo.io.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.html.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.string");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.IntegerTextbox");
dojo.require("dojo.widget.RealNumberTextbox");
dojo.require("dojo.widget.DateTextbox");

dojo.require("dojo.experimental");

// summary: Mixin for validation widgets with a spinner
// description: This class basically (conceptually) extends dojo.widget.ValidationTextbox.
//	It modifies the template to have up/down arrows, and provides related handling code.
dojo.declare(
	"dojo.widget.Spinner",
	null, 
	{
		_typamaticTimer: null,
		_typamaticFunction: null,
		_currentTimeout: this.defaultTimeout,
		_eventCount: 0,
		// Number
		//      number of milliseconds before a held key or button becomes typematic
		defaultTimeout: 500,
		// Number
		//      fraction of time used to change the typematic timer between events
		//      1.0 means that each typematic event fires at defaultTimeout intervals
		//      < 1.0 means that each typematic event fires at an increasing faster rate
		timeoutChangeRate: 0.90,

		templatePath: dojo.uri.dojoUri("src/widget/templates/Spinner.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/Spinner.css"),
		// String
		//      up arrow graphic URL
		incrementSrc: dojo.uri.dojoUri("src/widget/templates/images/spinnerIncrement.gif"),
		// String
		//      down arrow graphic URL
		decrementSrc: dojo.uri.dojoUri("src/widget/templates/images/spinnerDecrement.gif"),

		// does the keyboard related stuff
		_handleKeyEvents: function(/*Event*/ evt){
			if(!evt.key){ return; }

			if(!evt.ctrlKey && !evt.altKey){
			        switch(evt.key){
					case evt.KEY_DOWN_ARROW:
						dojo.event.browser.stopEvent(evt);
						this._downArrowPressed(evt);
						return;
					case evt.KEY_UP_ARROW:
						dojo.event.browser.stopEvent(evt);
						this._upArrowPressed(evt);
						return;
				}
			}
			this._eventCount++;
		},

		_onSpinnerKeyUp: function(/*Event*/ evt){
			this._arrowReleased(evt);
			this.onkeyup(evt);
		},

		// reset button size; this function is called when the input area has changed size
		_resize: function(){
			var inputSize = dojo.html.getBorderBox(this.textbox);
			this.buttonSize = { width: inputSize.height / 2, height: inputSize.height / 2 };
			if(this.upArrowNode){
				dojo.html.setMarginBox(this.upArrowNode, this.buttonSize);
				dojo.html.setMarginBox(this.downArrowNode, this.buttonSize);
			}
		},

		_pressButton: function(/*DomNode*/ node){
			node.style.borderWidth = "1px 0px 0px 1px";
			node.style.borderStyle = "inset";
		},

		_releaseButton: function(/*DomNode*/ node){
			node.style.borderWidth = "0px 1px 1px 0px";
			node.style.borderStyle = "outset";
		},

		_arrowPressed: function(/*Event*/ evt, /*Number*/ direction){
			var nodePressed = (direction == -1) ? this.downArrowNode : this.upArrowNode;
			var nodeReleased = (direction == +1) ? this.downArrowNode : this.upArrowNode;
			if(typeof evt != "number"){
				if(this._typamaticTimer != null){
					if(this._typamaticNode == nodePressed){
						return;
					}
					dojo.lang.clearTimeout(this._typamaticTimer);
				}
				this._releaseButton(nodeReleased);
				this._eventCount++;
				this._typamaticTimer = null;
				this._currentTimeout = this.defaultTimeout;

			}else if (evt != this._eventCount){
				this._releaseButton(nodePressed);
				return;
			}
			this._pressButton(nodePressed);
			this._setCursorX(this.adjustValue(direction,this._getCursorX()));
			this._typamaticNode = nodePressed;
			this._typamaticTimer = dojo.lang.setTimeout(this, "_arrowPressed", this._currentTimeout, this._eventCount, direction);
			this._currentTimeout = Math.round(this._currentTimeout * this.timeoutChangeRate);
		},

		_downArrowPressed: function(/*Event*/ evt){
			return this._arrowPressed(evt,-1);
		},

		// IE sends these events when rapid clicking, mimic an extra single click
		_downArrowDoubleClicked: function(/*Event*/ evt){
			var rc = this._downArrowPressed(evt);
			dojo.lang.setTimeout(this, "_arrowReleased", 50, null);
			return rc;
		},

		_upArrowPressed: function(/*Event*/ evt){
			return this._arrowPressed(evt,+1);
		},

		// IE sends these events when rapid clicking, mimic an extra single click
		_upArrowDoubleClicked: function(/*Event*/ evt){
			var rc = this._upArrowPressed(evt);
			dojo.lang.setTimeout(this, "_arrowReleased", 50, null);
			return rc;
		},

		_arrowReleased: function(/*Event*/ evt){
			this.textbox.focus();
			if(evt != null && typeof evt == "object" && evt.keyCode && evt.keyCode != null){
				var keyCode = evt.keyCode;
				var k = dojo.event.browser.keys;

				switch(keyCode){
					case k.KEY_DOWN_ARROW:
					case k.KEY_UP_ARROW:
						dojo.event.browser.stopEvent(evt);
						break;
				}
			}
			this._releaseButton(this.upArrowNode);
			this._releaseButton(this.downArrowNode);
			this._eventCount++;
			if(this._typamaticTimer != null){
				dojo.lang.clearTimeout(this._typamaticTimer);
			}
			this._typamaticTimer = null;
			this._currentTimeout = this.defaultTimeout;
		},

		_mouseWheeled: function(/*Event*/ evt){
			var scrollAmount = 0;
			if(typeof evt.wheelDelta == 'number'){ // IE
				scrollAmount = evt.wheelDelta;
			}else if (typeof evt.detail == 'number'){ // Mozilla+Firefox
				scrollAmount = -evt.detail;
			}
			if(scrollAmount > 0){
				this._upArrowPressed(evt);
				this._arrowReleased(evt);
			}else if (scrollAmount < 0){
				this._downArrowPressed(evt);
				this._arrowReleased(evt);
			}
		},

		_discardEvent: function(/*Event*/ evt){
			dojo.event.browser.stopEvent(evt);
		},

		_getCursorX: function(){
			var x = -1;
			try{
				this.textbox.focus();
				if (typeof this.textbox.selectionEnd == "number"){
					x = this.textbox.selectionEnd;
				}else if (document.selection && document.selection.createRange){
					var range = document.selection.createRange().duplicate();
					if(range.parentElement() == this.textbox){
						range.moveStart('textedit', -1);
						x = range.text.length;
					}
				}
			}catch(e){ /* squelch! */ }
			return x;
		},

		_setCursorX: function(/*Number*/ x){
			try{
				this.textbox.focus();
				if(!x){ x = 0; }
				if(typeof this.textbox.selectionEnd == "number"){
				this.textbox.selectionEnd = x;
				}else if(this.textbox.createTextRange){
				var range = this.textbox.createTextRange();
				range.collapse(true);
				range.moveEnd('character', x);
				range.moveStart('character', x);
				range.select();
				}
			}catch(e){ /* squelch! */ }
		},

		_spinnerPostMixInProperties: function(/*Object*/ args, /*Object*/ frag){
			// summary: the widget's postMixInProperties() method should call this method

			// set image size before instantiating template;
			// changing it aftwards doesn't work on FF
			var inputNode = this.getFragNodeRef(frag);
			var inputSize = dojo.html.getBorderBox(inputNode);
			this.buttonSize = { width: inputSize.height / 2 - 1, height: inputSize.height / 2 - 1};
		},

		_spinnerPostCreate: function(/*Object*/ args, /*Object*/ frag){
			// summary: the widget's postCreate() method should call this method

			// extra listeners
			if(this.textbox.addEventListener){
				// dojo.event.connect() doesn't seem to work with DOMMouseScroll
				this.textbox.addEventListener('DOMMouseScroll', dojo.lang.hitch(this, "_mouseWheeled"), false); // Mozilla + Firefox + Netscape
			}else{
				dojo.event.connect(this.textbox, "onmousewheel", this, "_mouseWheeled"); // IE + Safari
			}
			//dojo.event.connect(window, "onchange", this, "_resize");
		}
	}
);

// summary
//	create spinable, single integer, input field
dojo.widget.defineWidget(
	"dojo.widget.IntegerSpinner",
	[dojo.widget.IntegerTextbox, dojo.widget.Spinner],
{
	// summary: an IntegerSpinner with +/- buttons

	// Number
	//	increment amount
	delta: "1",

	postMixInProperties: function(/*Object*/ args, /*Object*/ frag){
		dojo.widget.IntegerSpinner.superclass.postMixInProperties.apply(this, arguments);
		this._spinnerPostMixInProperties(args, frag);
	},

	postCreate: function(/*Object*/ args, /*Object*/ frag){
		dojo.widget.IntegerSpinner.superclass.postCreate.apply(this, arguments);
		this._spinnerPostCreate(args, frag);
	},

	// sumary
	//	spin the input field
	//	direction < 0: spin down
	//	direction > 0: spin up
	//	direction = 0: revalidate existing value
	adjustValue: function(/*Number*/ direction, /*Number*/ x){
		var val = this.getValue().replace(/[^\-+\d]/g, "");
		if(val.length == 0){ return; }

		var num = Math.min(Math.max((parseInt(val)+(parseInt(this.delta) * direction)), (this.flags.min?this.flags.min:-Infinity)), (this.flags.max?this.flags.max:+Infinity));
		val = num.toString();

		if(num >= 0){
			val = ((this.flags.signed == true)?'+':' ')+val; // make sure first char is a nondigit
		}

		if(this.flags.separator.length > 0){
			for (var i=val.length-3; i > 1; i-=3){
				val = val.substr(0,i)+this.flags.separator+val.substr(i);
			}
		}

		if(val.substr(0,1) == ' '){ val = val.substr(1); } // remove space

		this.setValue(val);

		return val.length;
	}
});

/*
  ****** RealNumberSpinner ******

  A subclass of RealNumberTextbox.
  @attr places    The exact number of decimal places.  If omitted, it's unlimited and optional.
  @attr exponent  Can be true or false.  If omitted the exponential part is optional.
  @attr eSigned   Is the exponent signed?  Can be true or false, if omitted the sign is optional.
*/
dojo.widget.defineWidget(
	"dojo.widget.RealNumberSpinner",
	[dojo.widget.RealNumberTextbox, dojo.widget.Spinner],
	function(){ dojo.experimental("dojo.widget.RealNumberSpinner"); },
{
	// new subclass properties
	delta: "1e1",

	postMixInProperties: function(/*Object*/ args, /*Object*/ frag){
		dojo.widget.RealNumberSpinner.superclass.postMixInProperties.apply(this, arguments);
		this._spinnerPostMixInProperties(args, frag);
	},

	postCreate: function(/*Object*/ args, /*Object*/ frag){
		dojo.widget.RealNumberSpinner.superclass.postCreate.apply(this, arguments);
		this._spinnerPostCreate(args, frag);
	},

	adjustValue: function(/*Number*/ direction, /*Number*/ x){
			var val = this.getValue().replace(/[^\-+\.eE\d]/g, "");
			if(!val.length){ return; }

			var num = parseFloat(val);
			if(isNaN(num)){ return; }
			var delta = this.delta.split(/[eE]/);
			if(!delta.length){
				delta = [1, 1];
			}else{
				delta[0] = parseFloat(delta[0].replace(/[^\-+\.\d]/g, ""));
				if(isNaN(delta[0])){ delta[0] = 1; }
				if(delta.length > 1){
					delta[1] = parseInt(delta[1]);
				}
				if(isNaN(delta[1])){ delta[1] = 1; }
			}
			val = this.getValue().split(/[eE]/);
			if(!val.length){ return; }
			var numBase = parseFloat(val[0].replace(/[^\-+\.\d]/g, ""));
			if(val.length == 1){
				var numExp = 0;
			}else{
				var numExp = parseInt(val[1].replace(/[^\-+\d]/g, ""));
			}
			if(x <= val[0].length){
				x = 0;
				numBase += delta[0] * direction;
			}else{
				x = Number.MAX_VALUE;
				numExp += delta[1] * direction;
				if(this.flags.eSigned == false && numExp < 0){
					numExp = 0;
				}
			}
			num = Math.min(Math.max((numBase * Math.pow(10,numExp)), (this.flags.min?this.flags.min:-Infinity)), (this.flags.max?this.flags.max:+Infinity));
			if((this.flags.exponent == true || (this.flags.exponent != false && x != 0)) && num.toExponential){
				if (isNaN(this.flags.places) || this.flags.places == Infinity){
					val = num.toExponential();
				}else{
					val = num.toExponential(this.flags.places);
				}
			}else if(num.toFixed && num.toPrecision){
				if(isNaN(this.flags.places) || this.flags.places == Infinity){
					val = num.toPrecision((1/3).toString().length-1);
				}else{
					val = num.toFixed(this.flags.places);
				}
			}else{
				val = num.toString();
			}

			if(num >= 0){
				if(this.flags.signed == true){
					val = '+' + val;
				}
			}
			val = val.split(/[eE]/);
			if(this.flags.separator.length > 0){
				if(num >= 0 && val[0].substr(0,1) != '+'){
					val[0] = ' ' + val[0]; // make sure first char is nondigit for easy algorithm
				}
				var i = val[0].lastIndexOf('.');
				if(i >= 0){
					i -= 3;
				}else{
					i = val[0].length-3;
				}
				for (; i > 1; i-=3){
					val[0] = val[0].substr(0,i)+this.flags.separator+val[0].substr(i);
				}
				if(val[0].substr(0,1) == ' '){ val[0] = val[0].substr(1); } // remove space
			}
			if(val.length > 1){
				if((this.flags.eSigned == true)&&(val[1].substr(0,1) != '+')){
					val[1] = '+' + val[1];
				}else if((!this.flags.eSigned)&&(val[1].substr(0,1) == '+')){
					val[1] = val[1].substr(1);
				}else if((!this.flags.eSigned)&&(val[1].substr(0,1) == '-')&&(num.toFixed && num.toPrecision)){
					if(isNaN(this.flags.places)){
						val[0] = num.toPrecision((1/3).toString().length-1);
					}else{
						val[0] = num.toFixed(this.flags.places).toString();
					}
					val[1] = "0";
				}
				val[0] += 'e' + val[1];
			}
			this.setValue(val[0]);
			if(x > val[0].length){ x = val[0].length; }
			return x;
	}
});

dojo.widget.defineWidget(
	"dojo.widget.TimeSpinner",
	[dojo.widget.TimeTextbox, dojo.widget.Spinner],
	function(){ dojo.experimental("dojo.widget.TimeSpinner"); },
{
	postMixInProperties: function(/*Object*/ args, /*Object*/ frag){
		dojo.widget.TimeSpinner.superclass.postMixInProperties.apply(this, arguments);
		this._spinnerPostMixInProperties(args, frag);
	},

	postCreate: function(/*Object*/ args, /*Object*/ frag){
		dojo.widget.TimeSpinner.superclass.postCreate.apply(this, arguments);
		this._spinnerPostCreate(args, frag);
	},

	adjustValue: function(/*Number*/ direction, /*Number*/ x){
	//FIXME: formatting should make use of dojo.date.format?
		var val = this.getValue();
		var format = (this.flags.format && this.flags.format.search(/[Hhmst]/) >= 0) ? this.flags.format : "hh:mm:ss t";
		if(direction == 0 || !val.length || !this.isValid()){ return; }
		if (!this.flags.amSymbol){
			this.flags.amSymbol = "AM";
		}
		if (!this.flags.pmSymbol){
			this.flags.pmSymbol = "PM";
		}
		var re = dojo.regexp.time(this.flags);
		var qualifiers = format.replace(/H/g,"h").replace(/[^hmst]/g,"").replace(/([hmst])\1/g,"$1");
		var hourPos = qualifiers.indexOf('h') + 1;
		var minPos = qualifiers.indexOf('m') + 1;
		var secPos = qualifiers.indexOf('s') + 1;
		var ampmPos = qualifiers.indexOf('t') + 1;
		// tweak format to match the incoming data exactly to help find where the cursor is
		var cursorFormat = format;
		var ampm = "";
		if (ampmPos > 0){
			ampm = val.replace(new RegExp(re),"$"+ampmPos);
			cursorFormat = cursorFormat.replace(/t+/, ampm.replace(/./g,"t"));
		}
		var hour = 0;
		var deltaHour = 1;
		if (hourPos > 0){
			hour = val.replace(new RegExp(re),"$"+hourPos);
			if (dojo.lang.isString(this.delta)){
				deltaHour = this.delta.replace(new RegExp(re),"$"+hourPos);
			}
			if (isNaN(deltaHour)){
				deltaHour = 1;
			} else {
				deltaHour = parseInt(deltaHour);
			}
			if (hour.length == 2){
				cursorFormat = cursorFormat.replace(/([Hh])+/, "$1$1");
			} else {
				cursorFormat = cursorFormat.replace(/([Hh])+/, "$1");
			}
			if (isNaN(hour)){
				hour = 0;
			} else {
				hour = parseInt(hour.replace(/^0(\d)/,"$1"));
			}
		}
		var min = 0;
		var deltaMin = 1;
		if (minPos > 0){
			min = val.replace(new RegExp(re),"$"+minPos);
			if (dojo.lang.isString(this.delta)){
				deltaMin = this.delta.replace(new RegExp(re),"$"+minPos);
			}
			if (isNaN(deltaMin)){
				deltaMin = 1;
			} else {
				deltaMin = parseInt(deltaMin);
			}
			cursorFormat = cursorFormat.replace(/m+/, min.replace(/./g,"m"));
			if (isNaN(min)){
				min = 0;
			} else {
				min = parseInt(min.replace(/^0(\d)/,"$1"));
			}
		}
		var sec = 0;
		var deltaSec = 1;
		if (secPos > 0){
			sec = val.replace(new RegExp(re),"$"+secPos);
			if (dojo.lang.isString(this.delta)){
				deltaSec = this.delta.replace(new RegExp(re),"$"+secPos);
			}
			if (isNaN(deltaSec)){
				deltaSec = 1;
			} else {
				deltaSec = parseInt(deltaSec);
			}
			cursorFormat = cursorFormat.replace(/s+/, sec.replace(/./g,"s"));
			if (isNaN(sec)){
				sec = 0;
			} else {
				sec = parseInt(sec.replace(/^0(\d)/,"$1"));
			}
		}
		if (isNaN(x) || x >= cursorFormat.length){
			x = cursorFormat.length-1;
		}
		var cursorToken = cursorFormat.charAt(x);

		switch(cursorToken){
			case 't':
				if (ampm == this.flags.amSymbol){
					ampm = this.flags.pmSymbol;
				}
				else if (ampm == this.flags.pmSymbol){
					ampm = this.flags.amSymbol;
				}
				break;
			default:
				if (hour >= 1 && hour < 12 && ampm == this.flags.pmSymbol){
					hour += 12;
				}
				if (hour == 12 && ampm == this.flags.amSymbol){
					hour = 0;
				}
				switch(cursorToken){
					case 's':
						sec += deltaSec * direction;
						while (sec < 0){
							min--;
							sec += 60;
						}
						while (sec >= 60){
							min++;
							sec -= 60;
						}
					case 'm':
						if (cursorToken == 'm'){
							min += deltaMin * direction;
						}
						while (min < 0){
							hour--;
							min += 60;
						}
						while (min >= 60){
							hour++;
							min -= 60;
						}
					case 'h':
					case 'H':
						if (cursorToken == 'h' || cursorToken == 'H'){
							hour += deltaHour * direction;
						}
						while (hour < 0){
							hour += 24;
						}
						while (hour >= 24){
							hour -= 24;
						}
						break;
					default: // should never get here
						return;
				}
				if (hour >= 12){
					ampm = this.flags.pmSymbol;
					if (format.indexOf('h') >= 0 && hour >= 13){
						hour -= 12;
					}
				} else {
					ampm = this.flags.amSymbol;
					if (format.indexOf('h') >= 0 && hour == 0){
						hour = 12;
					}
				}
		}

		cursorFormat = format;
		if (hour >= 0 && hour < 10 && format.search(/[hH]{2}/) >= 0){
			hour = "0" + hour.toString();
		}
		if (hour >= 10 && cursorFormat.search(/[hH]{2}/) < 0 ){
			cursorFormat = cursorFormat.replace(/(h|H)/, "$1$1");
		}
		if (min >= 0 && min < 10 && cursorFormat.search(/mm/) >= 0){
			min = "0" + min.toString();
		}
		if (min >= 10 && cursorFormat.search(/mm/) < 0 ){
			cursorFormat = cursorFormat.replace(/m/, "$1$1");
		}
		if (sec >= 0 && sec < 10 && cursorFormat.search(/ss/) >= 0){
			sec = "0" + sec.toString();
		}
		if (sec >= 10 && cursorFormat.search(/ss/) < 0 ){
			cursorFormat = cursorFormat.replace(/s/, "$1$1");
		}
		x = cursorFormat.indexOf(cursorToken);
		if (x == -1){
			x = format.length;
		}
		format = format.replace(/[hH]+/, hour);
		format = format.replace(/m+/, min);
		format = format.replace(/s+/, sec);
		format = format.replace(/t/, ampm);
		this.setValue(format);
		if(x > format.length){ x = format.length; }
		return x;
	}
});

__CPAN_FILE__ src/widget/Parse.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Parse");
dojo.require("dojo.widget.Manager");
dojo.require("dojo.dom");

//
// dojoML parser should be moved out of 'widget', codifying the difference between a 'component'
// and a 'widget'. A 'component' being anything that can be generated from a tag.
//
// a particular dojoML tag would be handled by a registered tagHandler with a hook for a default handler
// if the widget system is loaded, a widget builder would be attach itself as the default handler
// 
// widget tags are no longer registered themselves:
// they are now arbitrarily namespaced, so we cannot register them all, and the non-prefixed portions 
// are no longer guaranteed unique 
// 
// therefore dojo.widget.tags should go with this parser code out of the widget module
//

dojo.widget.Parse = function(fragment){
	this.propertySetsList = [];
	this.fragment = fragment;
	
	this.createComponents = function(frag, parentComp){
		var comps = [];
		var built = false;
		// if we have items to parse/create at this level, do it!
		try{
			if((frag)&&(frag["tagName"])&&(frag!=frag["nodeRef"])){
				
				// these are in fact, not ever for widgets per-se anymore, 
				// but for other markup elements (aka components)
				var djTags = dojo.widget.tags;
				
				// we split so that you can declare multiple 
				// non-destructive components from the same ctor node
				var tna = String(frag["tagName"]).split(";");
				for(var x=0; x<tna.length; x++){
					var ltn = (tna[x].replace(/^\s+|\s+$/g, "")).toLowerCase();
					// FIXME: unsure what this does
					frag.tagName = ltn;
					if(djTags[ltn]){
						built = true;
						var ret = djTags[ltn](frag, this, parentComp, frag["index"]);
						comps.push(ret);
					} else {
						// we require a namespace prefix, default to dojo:
						if (ltn.indexOf(":") == -1){
							ltn = "dojo:"+ltn;
						}
						// FIXME: handling failure condition correctly?
						//var ret = djTags[ltn](frag, this, parentComp, frag["index"]);
						var ret = dojo.widget.buildWidgetFromParseTree(ltn, frag, this, parentComp, frag["index"]);
						if (ret) {
							built = true;
							comps.push(ret);
						}
					}
				}
			}
		}catch(e){
			dojo.debug("dojo.widget.Parse: error:" + e);
			// note, commenting out the next line is breaking several widgets for me
			// throw e;
			// IE is such a bitch sometimes
		}
		// if there's a sub-frag, build widgets from that too
		if(!built){
			comps = comps.concat(this.createSubComponents(frag, parentComp));
		}
		return comps;
	}

	/*	createSubComponents recurses over a raw JavaScript object structure,
			and calls the corresponding handler for its normalized tagName if it exists
	*/
	this.createSubComponents = function(fragment, parentComp){
		var frag, comps = [];
		for(var item in fragment){
			frag = fragment[item];
			if ((frag)&&(typeof frag == "object")&&(frag!=fragment.nodeRef)&&(frag!=fragment["tagName"])){
				comps = comps.concat(this.createComponents(frag, parentComp));
			}
		}
		return comps;
	}

	/*  parsePropertySets checks the top level of a raw JavaScript object
			structure for any propertySets.  It stores an array of references to 
			propertySets that it finds.
	*/
	this.parsePropertySets = function(fragment){
		return [];
		/*
		var propertySets = [];
		for(var item in fragment){
			if((fragment[item]["tagName"] == "dojo:propertyset")){
				propertySets.push(fragment[item]);
			}
		}
		// FIXME: should we store these propertySets somewhere for later retrieval
		this.propertySetsList.push(propertySets);
		return propertySets;
		*/
	}
	
	/*  parseProperties checks a raw JavaScript object structure for
			properties, and returns an array of properties that it finds.
	*/
	this.parseProperties = function(fragment){
		var properties = {};
		for(var item in fragment){
			// FIXME: need to check for undefined?
			// case: its a tagName or nodeRef
			if((fragment[item] == fragment["tagName"])||(fragment[item] == fragment.nodeRef)){
				// do nothing
			}else{
				if((fragment[item]["tagName"])&&
					(dojo.widget.tags[fragment[item].tagName.toLowerCase()])){
					// TODO: it isn't a property or property set, it's a fragment, 
					// so do something else
					// FIXME: needs to be a better/stricter check
					// TODO: handle xlink:href for external property sets
				}else if((fragment[item][0])&&(fragment[item][0].value!="")&&(fragment[item][0].value!=null)){
					try{
						// FIXME: need to allow more than one provider
						if(item.toLowerCase() == "dataprovider") {
							var _this = this;
							this.getDataProvider(_this, fragment[item][0].value);
							properties.dataProvider = this.dataProvider;
						}
						properties[item] = fragment[item][0].value;
						var nestedProperties = this.parseProperties(fragment[item]);
						// FIXME: this kind of copying is expensive and inefficient!
						for(var property in nestedProperties){
							properties[property] = nestedProperties[property];
						}
					}catch(e){ dojo.debug(e); }
				}
				switch(item.toLowerCase()){
				case "checked":
				case "disabled":
					if (typeof properties[item] != "boolean"){ 
						properties[item] = true;
					}
				break;
				}
			} 
		}
		return properties;
	}

	/* getPropertySetById returns the propertySet that matches the provided id
	*/
	
	this.getDataProvider = function(objRef, dataUrl){
		// FIXME: this is currently sync.  To make this async, we made need to move 
		//this step into the widget ctor, so that it is loaded when it is needed 
		// to populate the widget
		dojo.io.bind({
			url: dataUrl,
			load: function(type, evaldObj){
				if(type=="load"){
					objRef.dataProvider = evaldObj;
				}
			},
			mimetype: "text/javascript",
			sync: true
		});
	}

	
	this.getPropertySetById = function(propertySetId){
		for(var x = 0; x < this.propertySetsList.length; x++){
			if(propertySetId == this.propertySetsList[x]["id"][0].value){
				return this.propertySetsList[x];
			}
		}
		return "";
	}
	
	/* getPropertySetsByType returns the propertySet(s) that match(es) the
	 * provided componentClass
	 */
	this.getPropertySetsByType = function(componentType){
		var propertySets = [];
		for(var x=0; x < this.propertySetsList.length; x++){
			var cpl = this.propertySetsList[x];
			var cpcc = cpl["componentClass"]||cpl["componentType"]||null;
			var propertySetId = this.propertySetsList[x]["id"][0].value;
			if((cpcc)&&(propertySetId == cpcc[0].value)){
				propertySets.push(cpl);
			}
		}
		return propertySets;
	}
	
	/* getPropertySets returns the propertySet for a given component fragment
	*/
	this.getPropertySets = function(fragment){
		var ppl = "dojo:propertyproviderlist";
		var propertySets = [];
		var tagname = fragment["tagName"];
		if(fragment[ppl]){ 
			var propertyProviderIds = fragment[ppl].value.split(" ");
			// FIXME: should the propertyProviderList attribute contain #
			// 		  syntax for reference to ids or not?
			// FIXME: need a better test to see if this is local or external
			// FIXME: doesn't handle nested propertySets, or propertySets that
			// 		  just contain information about css documents, etc.
			for(var propertySetId in propertyProviderIds){
				if((propertySetId.indexOf("..")==-1)&&(propertySetId.indexOf("://")==-1)){
					// get a reference to a propertySet within the current parsed structure
					var propertySet = this.getPropertySetById(propertySetId);
					if(propertySet != ""){
						propertySets.push(propertySet);
					}
				}else{
					// FIXME: add code to parse and return a propertySet from
					// another document
					// alex: is this even necessaray? Do we care? If so, why?
				}
			}
		}
		// we put the typed ones first so that the parsed ones override when
		// iteration happens.
		return (this.getPropertySetsByType(tagname)).concat(propertySets);
	}
	
	/* 
		nodeRef is the node to be replaced... in the future, we might want to add 
		an alternative way to specify an insertion point

		componentName is the expected dojo widget name, i.e. Button of ContextMenu

		properties is an object of name value pairs
		ns is the namespace of the widget.  Defaults to "dojo"
	*/
	this.createComponentFromScript = function(nodeRef, componentName, properties, ns){
		properties.fastMixIn = true;			
		// FIXME: we pulled it apart and now we put it back together ... 
		var ltn = (ns || "dojo") + ":" + componentName.toLowerCase();
		if(dojo.widget.tags[ltn]){
			return [dojo.widget.tags[ltn](properties, this, null, null, properties)];
		}
		return [dojo.widget.buildWidgetFromParseTree(ltn, properties, this, null, null, properties)];
	}
}

dojo.widget._parser_collection = {"dojo": new dojo.widget.Parse() };
dojo.widget.getParser = function(name){
	if(!name){ name = "dojo"; }
	if(!this._parser_collection[name]){
		this._parser_collection[name] = new dojo.widget.Parse();
	}
	return this._parser_collection[name];
}

/**
 * Creates widget.
 *
 * @param name     The name of the widget to create with optional namespace prefix,
 *                 e.g."ns:widget", namespace defaults to "dojo".
 * @param props    Key-Value pairs of properties of the widget
 * @param refNode  If the position argument is specified, this node is used as
 *                 a reference for inserting this node into a DOM tree; else
 *                 the widget becomes the domNode
 * @param position The position to insert this widget's node relative to the
 *                 refNode argument
 * @return The new Widget object
 */

dojo.widget.createWidget = function(name, props, refNode, position){
	var isNode = false;
	var isNameStr = (typeof name == "string");
	if(isNameStr){
		var pos = name.indexOf(":");
		var ns = (pos > -1) ? name.substring(0,pos) : "dojo";
		if(pos > -1){ name = name.substring(pos+1); }
		var lowerCaseName = name.toLowerCase();
		var namespacedName = ns + ":" + lowerCaseName;
		isNode = (dojo.byId(name) && (!dojo.widget.tags[namespacedName])); 
	}

	if((arguments.length == 1) && ((isNode)||(!isNameStr))){
		// we got a DOM node 
		var xp = new dojo.xml.Parse(); 
		// FIXME: we should try to find the parent! 
		var tn = (isNode) ? dojo.byId(name) : name; 
		return dojo.widget.getParser().createComponents(xp.parseElement(tn, null, true))[0]; 
	}
	
	function fromScript(placeKeeperNode, name, props, ns){
		props[namespacedName] = { 
			dojotype: [{value: lowerCaseName}],
			nodeRef: placeKeeperNode,
			fastMixIn: true
		};
		props.ns = ns;
		return dojo.widget.getParser().createComponentFromScript(placeKeeperNode, name, props, ns);
	}

	props = props||{};
	var notRef = false;
	var tn = null;
	var h = dojo.render.html.capable;
	if(h){
		tn = document.createElement("span");
	}
	if(!refNode){
		notRef = true;
		refNode = tn;
		if(h){
			dojo.body().appendChild(refNode);
		}
	}else if(position){
		dojo.dom.insertAtPosition(tn, refNode, position);
	}else{ // otherwise don't replace, but build in-place
		tn = refNode;
	}
	var widgetArray = fromScript(tn, name.toLowerCase(), props, ns);
	if(	(!widgetArray)||(!widgetArray[0])||
		(typeof widgetArray[0].widgetType == "undefined") ){
		throw new Error("createWidget: Creation of \"" + name + "\" widget failed.");
	}
	try{
		if(notRef){
			if(widgetArray[0].domNode.parentNode){
				widgetArray[0].domNode.parentNode.removeChild(widgetArray[0].domNode);
			}
		}
	}catch(e){
		/* squelch for Safari */
		dojo.debug(e);
	}
	return widgetArray[0]; // just return the widget
}

__CPAN_FILE__ src/widget/TreeEmphaseOnSelect.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeEmphaseOnSelect");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TreeSelectorV3");
dojo.require("dojo.html.selection");

// selector extension to emphase node

dojo.widget.defineWidget(
	"dojo.widget.TreeEmphaseOnSelect",
	dojo.widget.HtmlWidget,
{
	selector: "",
	
	initialize: function() {
		this.selector = dojo.widget.byId(this.selector);
		
		dojo.event.topic.subscribe(this.selector.eventNames.select, this, "onSelect");
		dojo.event.topic.subscribe(this.selector.eventNames.deselect, this, "onDeselect");	
	},

	
	onSelect: function(message) {
		message.node.viewEmphase()		
	},
	
	onDeselect: function(message) {
		message.node.viewUnemphase()
	}
	

});

__CPAN_FILE__ src/widget/RemoteTabController.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.RemoteTabController");

//Summary
//Remote Tab Controller widget.  Can be located independently of a tab
//container and control the selection of its tabs
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.TabContainer");
dojo.require("dojo.event.*");

dojo.deprecated("dojo.widget.RemoteTabController is slated for removal in 0.5; use PageController or TabController instead.", "0.5");

dojo.widget.defineWidget(
    "dojo.widget.RemoteTabController",
    dojo.widget.TabController,
	{
        templateCssPath: dojo.uri.dojoUri("src/widget/templates/RemoteTabControl.css"),
		templateString: '<div dojoAttachPoint="domNode" wairole="tablist"></div>',

		"class": "dojoRemoteTabController",

		// String
		//	ID of page container that I connect to
		tabContainer: "",
	
		postMixInProperties: function(){
			this.containerId = this.tabContainer;
			dojo.widget.RemoteTabController.superclass.postMixInProperties.apply(this, arguments);
		},
			
		fillInTemplate: function() {
			dojo.html.addClass(this.domNode, this["class"]);  // "class" is a reserved word in JS

			if (this.tabContainer) {
				dojo.addOnLoad(dojo.lang.hitch(this, "setupTabs"));
			}

			dojo.widget.RemoteTabController.superclass.fillInTemplate.apply(this, arguments);
		}
	}
);

__CPAN_FILE__ src/widget/Toolbar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Toolbar");

dojo.require("dojo.widget.*");
dojo.require("dojo.html.style");

/* ToolbarContainer
 *******************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarContainer",
	dojo.widget.HtmlWidget,
{
	isContainer: true,

	templateString: '<div class="toolbarContainer" dojoAttachPoint="containerNode"></div>',
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Toolbar.css"),

	getItem: function(name) {
		if(name instanceof dojo.widget.ToolbarItem) { return name; }
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				var item = child.getItem(name);
				if(item) { return item; }
			}
		}
		return null;
	},

	getItems: function() {
		var items = [];
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				items = items.concat(child.getItems());
			}
		}
		return items;
	},

	enable: function() {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				child.enable.apply(child, arguments);
			}
		}
	},

	disable: function() {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				child.disable.apply(child, arguments);
			}
		}
	},

	select: function(name) {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				child.select(arguments);
			}
		}
	},

	deselect: function(name) {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				child.deselect(arguments);
			}
		}
	},

	getItemsState: function() {
		var values = {};
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				dojo.lang.mixin(values, child.getItemsState());
			}
		}
		return values;
	},

	getItemsActiveState: function() {
		var values = {};
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				dojo.lang.mixin(values, child.getItemsActiveState());
			}
		}
		return values;
	},

	getItemsSelectedState: function() {
		var values = {};
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.Toolbar) {
				dojo.lang.mixin(values, child.getItemsSelectedState());
			}
		}
		return values;
	}
});

/* Toolbar
 **********/

dojo.widget.defineWidget(
	"dojo.widget.Toolbar",
	dojo.widget.HtmlWidget,
{
	isContainer: true,

	templateString: '<div class="toolbar" dojoAttachPoint="containerNode" unselectable="on" dojoOnMouseover="_onmouseover" dojoOnMouseout="_onmouseout" dojoOnClick="_onclick" dojoOnMousedown="_onmousedown" dojoOnMouseup="_onmouseup"></div>',

	// given a node, tries to find it's toolbar item
	_getItem: function(node) {
		var start = new Date();
		var widget = null;
		while(node && node != this.domNode) {
			if(dojo.html.hasClass(node, "toolbarItem")) {
				var widgets = dojo.widget.manager.getWidgetsByFilter(function(w) { return w.domNode == node; });
				if(widgets.length == 1) {
					widget = widgets[0];
					break;
				} else if(widgets.length > 1) {
					dojo.raise("Toolbar._getItem: More than one widget matches the node");
				}
			}
			node = node.parentNode;
		}
		return widget;
	},

	_onmouseover: function(e) {
		var widget = this._getItem(e.target);
		if(widget && widget._onmouseover) { widget._onmouseover(e); }
	},

	_onmouseout: function(e) {
		var widget = this._getItem(e.target);
		if(widget && widget._onmouseout) { widget._onmouseout(e); }
	},

	_onclick: function(e) {
		var widget = this._getItem(e.target);
		if(widget && widget._onclick){
			widget._onclick(e);
		}
	},

	_onmousedown: function(e) {
		var widget = this._getItem(e.target);
		if(widget && widget._onmousedown) { widget._onmousedown(e); }
	},

	_onmouseup: function(e) {
		var widget = this._getItem(e.target);
		if(widget && widget._onmouseup) { widget._onmouseup(e); }
	},

	addChild: function(item, pos, props) {
		var widget = dojo.widget.ToolbarItem.make(item, null, props);
		var ret = dojo.widget.Toolbar.superclass.addChild.call(this, widget, null, pos, null);
		return ret;
	},

	push: function() {
		for(var i = 0; i < arguments.length; i++) {
			this.addChild(arguments[i]);
		}
	},

	getItem: function(name) {
		if(name instanceof dojo.widget.ToolbarItem) { return name; }
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem
				&& child._name == name) { return child; }
		}
		return null;
	},

	getItems: function() {
		var items = [];
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem) {
				items.push(child);
			}
		}
		return items;
	},

	getItemsState: function() {
		var values = {};
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem) {
				values[child._name] = {
					selected: child._selected,
					enabled: child._enabled
				};
			}
		}
		return values;
	},

	getItemsActiveState: function() {
		var values = this.getItemsState();
		for(var item in values) {
			values[item] = values[item].enabled;
		}
		return values;
	},

	getItemsSelectedState: function() {
		var values = this.getItemsState();
		for(var item in values) {
			values[item] = values[item].selected;
		}
		return values;
	},

	enable: function() {
		var items = arguments.length ? arguments : this.children;
		for(var i = 0; i < items.length; i++) {
			var child = this.getItem(items[i]);
			if(child instanceof dojo.widget.ToolbarItem) {
				child.enable(false, true);
			}
		}
	},

	disable: function() {
		var items = arguments.length ? arguments : this.children;
		for(var i = 0; i < items.length; i++) {
			var child = this.getItem(items[i]);
			if(child instanceof dojo.widget.ToolbarItem) {
				child.disable();
			}
		}
	},

	select: function() {
		for(var i = 0; i < arguments.length; i++) {
			var name = arguments[i];
			var item = this.getItem(name);
			if(item) { item.select(); }
		}
	},

	deselect: function() {
		for(var i = 0; i < arguments.length; i++) {
			var name = arguments[i];
			var item = this.getItem(name);
			if(item) { item.disable(); }
		}
	},

	setValue: function() {
		for(var i = 0; i < arguments.length; i += 2) {
			var name = arguments[i], value = arguments[i+1];
			var item = this.getItem(name);
			if(item) {
				if(item instanceof dojo.widget.ToolbarItem) {
					item.setValue(value);
				}
			}
		}
	}
});

/* ToolbarItem hierarchy:
	- ToolbarItem
		- ToolbarButton
		- ToolbarDialog
			- ToolbarMenu
		- ToolbarSeparator
			- ToolbarSpace
				- ToolbarFlexibleSpace
*/


/* ToolbarItem
 **************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarItem",
	dojo.widget.HtmlWidget,
{
	templateString: '<span unselectable="on" class="toolbarItem"></span>',

	_name: null,
	getName: function() { return this._name; },
	setName: function(value) { return (this._name = value); },
	getValue: function() { return this.getName(); },
	setValue: function(value) { return this.setName(value); },

	_selected: false,
	isSelected: function() { return this._selected; },
	setSelected: function(is, force, preventEvent) {
		if(!this._toggleItem && !force) { return; }
		is = Boolean(is);
		if(force || this._enabled && this._selected != is) {
			this._selected = is;
			this.update();
			if(!preventEvent) {
				this._fireEvent(is ? "onSelect" : "onDeselect");
				this._fireEvent("onChangeSelect");
			}
		}
	},
	select: function(force, preventEvent) {
		return this.setSelected(true, force, preventEvent);
	},
	deselect: function(force, preventEvent) {
		return this.setSelected(false, force, preventEvent);
	},

	_toggleItem: false,
	isToggleItem: function() { return this._toggleItem; },
	setToggleItem: function(value) { this._toggleItem = Boolean(value); },

	toggleSelected: function(force) {
		return this.setSelected(!this._selected, force);
	},

	_enabled: true,
	isEnabled: function() { return this._enabled; },
	setEnabled: function(is, force, preventEvent) {
		is = Boolean(is);
		if(force || this._enabled != is) {
			this._enabled = is;
			this.update();
			if(!preventEvent) {
				this._fireEvent(this._enabled ? "onEnable" : "onDisable");
				this._fireEvent("onChangeEnabled");
			}
		}
		return this._enabled;
	},
	enable: function(force, preventEvent) {
		return this.setEnabled(true, force, preventEvent);
	},
	disable: function(force, preventEvent) {
		return this.setEnabled(false, force, preventEvent);
	},
	toggleEnabled: function(force, preventEvent) {
		return this.setEnabled(!this._enabled, force, preventEvent);
	},

	_icon: null,
	getIcon: function() { return this._icon; },
	setIcon: function(value) {
		var icon = dojo.widget.Icon.make(value);
		if(this._icon) {
			this._icon.setIcon(icon);
		} else {
			this._icon = icon;
		}
		var iconNode = this._icon.getNode();
		if(iconNode.parentNode != this.domNode) {
			if(this.domNode.hasChildNodes()) {
				this.domNode.insertBefore(iconNode, this.domNode.firstChild);
			} else {
				this.domNode.appendChild(iconNode);
			}
		}
		return this._icon;
	},

	// TODO: update the label node (this.labelNode?)
	_label: "",
	getLabel: function() { return this._label; },
	setLabel: function(value) {
		var ret = (this._label = value);
		if(!this.labelNode) {
			this.labelNode = document.createElement("span");
			this.domNode.appendChild(this.labelNode);
		}
		this.labelNode.innerHTML = "";
		this.labelNode.appendChild(document.createTextNode(this._label));
		this.update();
		return ret;
	},

	// fired from: setSelected, setEnabled, setLabel
	update: function() {
		if(this._enabled) {
			dojo.html.removeClass(this.domNode, "disabled");
			if(this._selected) {
				dojo.html.addClass(this.domNode, "selected");
			} else {
				dojo.html.removeClass(this.domNode, "selected");
			}
		} else {
			this._selected = false;
			dojo.html.addClass(this.domNode, "disabled");
			dojo.html.removeClass(this.domNode, "down");
			dojo.html.removeClass(this.domNode, "hover");
		}
		this._updateIcon();
	},

	_updateIcon: function() {
		if(this._icon) {
			if(this._enabled) {
				if(this._cssHover) {
					this._icon.hover();
				} else if(this._selected) {
					this._icon.select();
				} else {
					this._icon.enable();
				}
			} else {
				this._icon.disable();
			}
		}
	},

	_fireEvent: function(evt) {
		if(typeof this[evt] == "function") {
			var args = [this];
			for(var i = 1; i < arguments.length; i++) {
				args.push(arguments[i]);
			}
			this[evt].apply(this, args);
		}
	},

	_onmouseover: function(e) {
		if(!this._enabled) { return; }
		dojo.html.addClass(this.domNode, "hover");
		this._fireEvent("onMouseOver");
	},

	_onmouseout: function(e) {
		dojo.html.removeClass(this.domNode, "hover");
		dojo.html.removeClass(this.domNode, "down");
		if(!this._selected) {
			dojo.html.removeClass(this.domNode, "selected");
		}
		this._fireEvent("onMouseOut");
	},

	_onclick: function(e) {
		// FIXME: buttons never seem to have this._enabled set to true on Opera 9
		// dojo.debug("widget:", this.widgetType, ":", this.getName(), ", enabled:", this._enabled);
		if(this._enabled && !this._toggleItem) {
			this._fireEvent("onClick");
		}
	},

	_onmousedown: function(e) {
		if(e.preventDefault) { e.preventDefault(); }
		if(!this._enabled) { return; }
		dojo.html.addClass(this.domNode, "down");
		if(this._toggleItem) {
			if(this.parent.preventDeselect && this._selected) {
				return;
			}
			this.toggleSelected();
		}
		this._fireEvent("onMouseDown");
	},

	_onmouseup: function(e) {
		dojo.html.removeClass(this.domNode, "down");
		this._fireEvent("onMouseUp");
	},

	onClick: function() { },
	onMouseOver: function() { },
	onMouseOut: function() { },
	onMouseDown: function() { },
	onMouseUp: function() { },

	fillInTemplate: function(args, frag) {
		if(args.name) { this._name = args.name; }
		if(args.selected) { this.select(); }
		if(args.disabled) { this.disable(); }
		if(args.label) { this.setLabel(args.label); }
		if(args.icon) { this.setIcon(args.icon); }
		if(args.toggleitem||args.toggleItem) { this.setToggleItem(true); }
	}
});

dojo.widget.ToolbarItem.make = function(wh, whIsType, props) {
	var item = null;

	if(wh instanceof Array) {
		item = dojo.widget.createWidget("ToolbarButtonGroup", props);
		item.setName(wh[0]);
		for(var i = 1; i < wh.length; i++) {
			item.addChild(wh[i]);
		}
	} else if(wh instanceof dojo.widget.ToolbarItem) {
		item = wh;
	} else if(wh instanceof dojo.uri.Uri) {
		item = dojo.widget.createWidget("ToolbarButton",
			dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
	} else if(whIsType) {
		item = dojo.widget.createWidget(wh, props);
	} else if(typeof wh == "string" || wh instanceof String) {
		switch(wh.charAt(0)) {
			case "|":
			case "-":
			case "/":
				item = dojo.widget.createWidget("ToolbarSeparator", props);
				break;
			case " ":
				if(wh.length == 1) {
					item = dojo.widget.createWidget("ToolbarSpace", props);
				} else {
					item = dojo.widget.createWidget("ToolbarFlexibleSpace", props);
				}
				break;
			default:
				if(/\.(gif|jpg|jpeg|png)$/i.test(wh)) {
					item = dojo.widget.createWidget("ToolbarButton",
						dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
				} else {
					item = dojo.widget.createWidget("ToolbarButton",
						dojo.lang.mixin(props||{}, {label: wh.toString()}));
				}
		}
	} else if(wh && wh.tagName && /^img$/i.test(wh.tagName)) {
		item = dojo.widget.createWidget("ToolbarButton",
			dojo.lang.mixin(props||{}, {icon: wh}));
	} else {
		item = dojo.widget.createWidget("ToolbarButton",
			dojo.lang.mixin(props||{}, {label: wh.toString()}));
	}
	return item;
}

/* ToolbarButtonGroup
 *********************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarButtonGroup",
	dojo.widget.ToolbarItem,
{
	isContainer: true,

	templateString: '<span unselectable="on" class="toolbarButtonGroup" dojoAttachPoint="containerNode"></span>',

	// if a button has the same name, it will be selected
	// if this is set to a number, the button at that index will be selected
	defaultButton: "",

    postCreate: function() {
        for (var i = 0; i < this.children.length; i++) {
            this._injectChild(this.children[i]);
        }
    },

	addChild: function(item, pos, props) {
		var widget = dojo.widget.ToolbarItem.make(item, null, dojo.lang.mixin(props||{}, {toggleItem:true}));
		var ret = dojo.widget.ToolbarButtonGroup.superclass.addChild.call(this, widget, null, pos, null);
        this._injectChild(widget);
        return ret;
    },

    _injectChild: function(widget) {
        dojo.event.connect(widget, "onSelect", this, "onChildSelected");
        dojo.event.connect(widget, "onDeselect", this, "onChildDeSelected");
        if(widget._name == this.defaultButton
			|| (typeof this.defaultButton == "number"
			&& this.children.length-1 == this.defaultButton)) {
			widget.select(false, true);
		}
	},

	getItem: function(name) {
		if(name instanceof dojo.widget.ToolbarItem) { return name; }
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem
				&& child._name == name) { return child; }
		}
		return null;
	},

	getItems: function() {
		var items = [];
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem) {
				items.push(child);
			}
		}
		return items;
	},

	onChildSelected: function(e) {
		this.select(e._name);
	},

	onChildDeSelected: function(e) {
		this._fireEvent("onChangeSelect", this._value);
	},

	enable: function(force, preventEvent) {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem) {
				child.enable(force, preventEvent);
				if(child._name == this._value) {
					child.select(force, preventEvent);
				}
			}
		}
	},

	disable: function(force, preventEvent) {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem) {
				child.disable(force, preventEvent);
			}
		}
	},

	_value: "",
	getValue: function() { return this._value; },

	select: function(name, force, preventEvent) {
		for(var i = 0; i < this.children.length; i++) {
			var child = this.children[i];
			if(child instanceof dojo.widget.ToolbarItem) {
				if(child._name == name) {
					child.select(force, preventEvent);
					this._value = name;
				} else {
					child.deselect(true, true);
				}
			}
		}
		if(!preventEvent) {
			this._fireEvent("onSelect", this._value);
			this._fireEvent("onChangeSelect", this._value);
		}
	},
	setValue: this.select,

	preventDeselect: false // if true, once you select one, you can't have none selected
});

/* ToolbarButton
 ***********************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarButton",
	dojo.widget.ToolbarItem,
{
	fillInTemplate: function(args, frag) {
		dojo.widget.ToolbarButton.superclass.fillInTemplate.call(this, args, frag);
		dojo.html.addClass(this.domNode, "toolbarButton");
		if(this._icon) {
			this.setIcon(this._icon);
		}
		if(this._label) {
			this.setLabel(this._label);
		}

		if(!this._name) {
			if(this._label) {
				this.setName(this._label);
			} else if(this._icon) {
				var src = this._icon.getSrc("enabled").match(/[\/^]([^\.\/]+)\.(gif|jpg|jpeg|png)$/i);
				if(src) { this.setName(src[1]); }
			} else {
				this._name = this._widgetId;
			}
		}
	}
});

/* ToolbarDialog
 **********************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarDialog",
	dojo.widget.ToolbarButton,
{
	fillInTemplate: function (args, frag) {
		dojo.widget.ToolbarDialog.superclass.fillInTemplate.call(this, args, frag);
		dojo.event.connect(this, "onSelect", this, "showDialog");
		dojo.event.connect(this, "onDeselect", this, "hideDialog");
	},

	showDialog: function (e) {
		dojo.lang.setTimeout(dojo.event.connect, 1, document, "onmousedown", this, "deselect");
	},

	hideDialog: function (e) {
		dojo.event.disconnect(document, "onmousedown", this, "deselect");
	}

});

/* ToolbarMenu
 **********************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarMenu",
	dojo.widget.ToolbarDialog,
	{}
);

/* ToolbarMenuItem
 ******************/
dojo.widget.ToolbarMenuItem = function() {
}

/* ToolbarSeparator
 **********************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarSeparator",
	dojo.widget.ToolbarItem,
{
	templateString: '<span unselectable="on" class="toolbarItem toolbarSeparator"></span>',

	defaultIconPath: new dojo.uri.dojoUri("src/widget/templates/buttons/sep.gif"),

	fillInTemplate: function(args, frag, skip) {
		dojo.widget.ToolbarSeparator.superclass.fillInTemplate.call(this, args, frag);
		this._name = this.widgetId;
		if(!skip) {
			if(!this._icon) {
				this.setIcon(this.defaultIconPath);
			}
			this.domNode.appendChild(this._icon.getNode());
		}
	},

	// don't want events!
	_onmouseover: null,
    _onmouseout: null,
    _onclick: null,
    _onmousedown: null,
    _onmouseup: null
});

/* ToolbarSpace
 **********************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarSpace",
	dojo.widget.ToolbarSeparator,
{
	fillInTemplate: function(args, frag, skip) {
		dojo.widget.ToolbarSpace.superclass.fillInTemplate.call(this, args, frag, true);
		if(!skip) {
			dojo.html.addClass(this.domNode, "toolbarSpace");
		}
	}
});

/* ToolbarSelect
 ******************/

dojo.widget.defineWidget(
	"dojo.widget.ToolbarSelect",
	dojo.widget.ToolbarItem,
{
	templateString: '<span class="toolbarItem toolbarSelect" unselectable="on"><select dojoAttachPoint="selectBox" dojoOnChange="changed"></select></span>',

	fillInTemplate: function(args, frag) {
		dojo.widget.ToolbarSelect.superclass.fillInTemplate.call(this, args, frag, true);
		var keys = args.values;
		var i = 0;
		for(var val in keys) {
			var opt = document.createElement("option");
			opt.setAttribute("value", keys[val]);
			opt.innerHTML = val;
			this.selectBox.appendChild(opt);
		}
	},

	changed: function(e) {
		this._fireEvent("onSetValue", this.selectBox.value);
	},

	setEnabled: function(is, force, preventEvent) {
		var ret = dojo.widget.ToolbarSelect.superclass.setEnabled.call(this, is, force, preventEvent);
		this.selectBox.disabled = !this._enabled;
		return ret;
	},

	// don't want events!
	_onmouseover: null,
    _onmouseout: null,
    _onclick: null,
    _onmousedown: null,
    _onmouseup: null
});

/* Icon
 *********/
// arguments can be IMG nodes, Image() instances or URLs -- enabled is the only one required
dojo.widget.Icon = function(enabled, disabled, hovered, selected){
	if(!arguments.length){
		// FIXME: should this be dojo.raise?
		throw new Error("Icon must have at least an enabled state");
	}
	var states = ["enabled", "disabled", "hovered", "selected"];
	var currentState = "enabled";
	var domNode = document.createElement("img");

	this.getState = function(){ return currentState; }
	this.setState = function(value){
		if(dojo.lang.inArray(states, value)){
			if(this[value]){
				currentState = value;
				var img = this[currentState];
				if ((dojo.render.html.ie55 || dojo.render.html.ie60) && img.src && img.src.match(/[.]png$/i) ) {
					domNode.width = img.width||img.offsetWidth;
					domNode.height = img.height||img.offsetHeight;
					domNode.setAttribute("src", dojo.uri.dojoUri("src/widget/templates/images/blank.gif").uri);
					domNode.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+img.src+"',sizingMethod='image')";
				} else {
					domNode.setAttribute("src", img.src);
				}
			}
		}else{
			throw new Error("Invalid state set on Icon (state: " + value + ")");
		}
	}

	this.setSrc = function(state, value){
		if(/^img$/i.test(value.tagName)){
			this[state] = value;
		}else if(typeof value == "string" || value instanceof String
			|| value instanceof dojo.uri.Uri){
			this[state] = new Image();
			this[state].src = value.toString();
		}
		return this[state];
	}

	this.setIcon = function(icon){
		for(var i = 0; i < states.length; i++){
			if(icon[states[i]]){
				this.setSrc(states[i], icon[states[i]]);
			}
		}
		this.update();
	}

	this.enable = function(){ this.setState("enabled"); }
	this.disable = function(){ this.setState("disabled"); }
	this.hover = function(){ this.setState("hovered"); }
	this.select = function(){ this.setState("selected"); }

	this.getSize = function(){
		return {
			width: domNode.width||domNode.offsetWidth,
			height: domNode.height||domNode.offsetHeight
		};
	}

	this.setSize = function(w, h){
		domNode.width = w;
		domNode.height = h;
		return { width: w, height: h };
	}

	this.getNode = function(){
		return domNode;
	}

	this.getSrc = function(state){
		if(state){ return this[state].src; }
		return domNode.src||"";
	}

	this.update = function(){
		this.setState(currentState);
	}

	for(var i = 0; i < states.length; i++){
		var arg = arguments[i];
		var state = states[i];
		this[state] = null;
		if(!arg){ continue; }
		this.setSrc(state, arg);
	}

	this.enable();
}

dojo.widget.Icon.make = function(a,b,c,d){
	for(var i = 0; i < arguments.length; i++){
		if(arguments[i] instanceof dojo.widget.Icon){
			return arguments[i];
		}
	}

	return new dojo.widget.Icon(a,b,c,d);
}

/* ToolbarColorDialog
 ******************/
dojo.widget.defineWidget(
	"dojo.widget.ToolbarColorDialog",
	dojo.widget.ToolbarDialog,
{
 	palette: "7x10",

	fillInTemplate: function (args, frag) {
		dojo.widget.ToolbarColorDialog.superclass.fillInTemplate.call(this, args, frag);
		this.dialog = dojo.widget.createWidget("ColorPalette", {palette: this.palette});
		this.dialog.domNode.style.position = "absolute";

		dojo.event.connect(this.dialog, "onColorSelect", this, "_setValue");
	},

	_setValue: function(color) {
		this._value = color;
		this._fireEvent("onSetValue", color);
	},

	showDialog: function (e) {
		dojo.widget.ToolbarColorDialog.superclass.showDialog.call(this, e);
		var abs = dojo.html.getAbsolutePosition(this.domNode, true);
		var y = abs.y + dojo.html.getBorderBox(this.domNode).height;
		this.dialog.showAt(abs.x, y);
	},

	hideDialog: function (e) {
		dojo.widget.ToolbarColorDialog.superclass.hideDialog.call(this, e);
		this.dialog.hide();
	}
});
__CPAN_FILE__ src/widget/SvgButton.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

// FIXME: not yet functional

dojo.provide("dojo.widget.SvgButton");

dojo.require("dojo.widget.Button");

dojo.widget.SvgButton = function(){
	// FIXME: this is incomplete and doesn't work yet
	// if DOMButton turns into a mixin, we should subclass Button instead and
	// just mix in the DOMButton properties.

	dojo.widget.DomButton.call(this);
	dojo.widget.SvgWidget.call(this);

	// FIXME: freaking implement this already!
	this.onFoo = function(){ alert("bar"); }

	this.label = "huzzah!";

	this.setLabel = function(x, y, textSize, label, shape){
		//var labelNode = this.domNode.ownerDocument.createTextNode(this.label);
		//var textNode = this.domNode.ownerDocument.createElement("text");
		var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape);
		var textString = "";
		switch(shape) {
			case "ellipse":
				textString = "<text x='"+ coords[6] + "' y='"+ coords[7] + "'>"+ label + "</text>";
				//textNode.setAttribute("x", coords[6]);
				//textNode.setAttribute("y", coords[7]);
				break;
			case "rectangle":
				//FIXME: implement
				textString = "";
				//textNode.setAttribute("x", coords[6]);
				//textNode.setAttribute("y", coords[7]);
				break;
			case "circle":
				//FIXME: implement
				textString = "";
				//textNode.setAttribute("x", coords[6]);
				//textNode.setAttribute("y", coords[7]);
				break;
		}
		//textNode.appendChild(labelNode);
		//this.domNode.appendChild(textNode);
		return textString;
		//alert(textNode.getComputedTextLength());
	}

	this.fillInTemplate = function(x, y, textSize, label, shape){
		// the idea is to set the text to the appropriate place given its length
		// and the template shape
		
		// FIXME: For now, assuming text sizes are integers in SVG units
		this.textSize = textSize || 12;
		this.label = label;
		// FIXEME: for now, I'm going to fake this... need to come up with a real way to 
		// determine the actual width of the text, such as computedStyle
		var textWidth = this.label.length*this.textSize ;
		//this.setLabel();
	}
}

dojo.inherits(dojo.widget.SvgButton, dojo.widget.DomButton);

// FIXME
dojo.widget.SvgButton.prototype.shapeString = function(x, y, textSize, label, shape) {
	switch(shape) {
		case "ellipse":
			var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape)
			return "<ellipse cx='"+ coords[4]+"' cy='"+ coords[5]+"' rx='"+ coords[2]+"' ry='"+ coords[3]+"'/>";
			break;
		case "rect":
			//FIXME: implement
			return "";
			//return "<rect x='110' y='45' width='70' height='30'/>";
			break;
		case "circle":
			//FIXME: implement
			return "";
			//return "<circle cx='210' cy='60' r='23'/>";
			break;
	}
}

dojo.widget.SvgButton.prototype.coordinates = function(x, y, textSize, label, shape) {
	switch(shape) {
		case "ellipse":
			var buttonWidth = label.length*textSize;
			var buttonHeight = textSize*2.5
			var rx = buttonWidth/2;
			var ry = buttonHeight/2;
			var cx = rx + x;
			var cy = ry + y;
			var textX = cx - rx*textSize/25;
			var textY = cy*1.1;
			return [buttonWidth, buttonHeight, rx, ry, cx, cy, textX, textY];
			break;
		case "rectangle":
			//FIXME: implement
			return "";
			break;
		case "circle":
			//FIXME: implement
			return "";
			break;
	}
}

dojo.widget.SvgButton.prototype.labelString = function(x, y, textSize, label, shape){
	var textString = "";
	var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape);
	switch(shape) {
		case "ellipse":
			textString = "<text x='"+ coords[6] + "' y='"+ coords[7] + "'>"+ label + "</text>";
			break;
		case "rectangle":
			//FIXME: implement
			textString = "";
			break;
		case "circle":
			//FIXME: implement
			textString = "";
			break;
	}
	return textString;
}

dojo.widget.SvgButton.prototype.templateString = function(x, y, textSize, label, shape) {
	return "<g class='dojoButton' dojoAttachEvent='onClick; onMouseMove: onFoo;' dojoAttachPoint='labelNode'>"+ dojo.widgets.SVGButton.prototype.shapeString(x, y, textSize, label, shape) + dojo.widget.SVGButton.prototype.labelString(x, y, textSize, label, shape) + "</g>";
}

__CPAN_FILE__ src/widget/TreeDndControllerV3.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeDndControllerV3");

dojo.require("dojo.dnd.TreeDragAndDropV3");
	
dojo.widget.defineWidget(
	"dojo.widget.TreeDndControllerV3",
	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
	function() {
		this.dragSources = {};
		this.dropTargets = {};
		this.listenedTrees = {};
	},
{
	listenTreeEvents: ["afterChangeTree","beforeTreeDestroy", "afterAddChild"],
	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget}, 
	
	initialize: function(args) {
		this.treeController = dojo.lang.isString(args.controller) ? dojo.widget.byId(args.controller) : args.controller;
		
		if (!this.treeController) {
			dojo.raise("treeController must be declared");
		}
		
	},

	onBeforeTreeDestroy: function(message) {
		this.unlistenTree(message.source);
	},
	
	// first Dnd registration happens in addChild
	// because I have information about parent on this stage and can use it
	// to check locking or other things
	onAfterAddChild: function(message) {
		//dojo.debug("Dnd addChild "+message.child);
		this.listenNode(message.child);		
	},


	onAfterChangeTree: function(message) {
		/* catch new nodes on afterAddChild, because I need parent */		
		if (!message.oldTree) return;
		
		//dojo.debug("HERE");
		
		if (!message.newTree || !this.listenedTrees[message.newTree.widgetId]) {			
			this.processDescendants(message.node, this.listenNodeFilter, this.unlistenNode);
		}		
		
		if (!this.listenedTrees[message.oldTree.widgetId]) {
			// we have new node
			this.processDescendants(message.node, this.listenNodeFilter, this.listenNode);	
		}
		//dojo.profile.end("onTreeChange");
	},
	
	
	/**
	 * Controller(node model) creates DndNodes because it passes itself to node for synchroneous drops processing
	 * I can't process DnD with events cause an event can't return result success/false
	*/
	listenNode: function(node) {

		//dojo.debug("listen dnd "+node);
		//dojo.debug((new Error()).stack)
		//dojo.profile.start("Dnd listenNode "+node);		
		if (!node.tree.DndMode) return;
		if (this.dragSources[node.widgetId] || this.dropTargets[node.widgetId]) return;

	
		/* I drag label, not domNode, because large domNodes are very slow to copy and large to drag */

		var source = null;
		var target = null;

	
		if (!node.actionIsDisabled(node.actions.MOVE)) {
			//dojo.debug("reg source")
			
			//dojo.profile.start("Dnd source "+node);		
			var source = this.makeDragSource(node);
			//dojo.profile.end("Dnd source "+node);		

			this.dragSources[node.widgetId] = source;
		}

		//dojo.profile.start("Dnd target "+node);		
		//dojo.debug("reg target");
		var target = this.makeDropTarget(node);
		//dojo.profile.end("Dnd target "+node);		

		this.dropTargets[node.widgetId] = target;

		//dojo.profile.end("Dnd listenNode "+node);		


	},
	
	/**
	 * Factory method, override it to create special source
	 */
	makeDragSource: function(node) {
		return new dojo.dnd.TreeDragSourceV3(node.contentNode, this, node.tree.widgetId, node);
	},


	/**
	 * Factory method, override it to create special target
	 */
	makeDropTarget: function(node) {
		 return new dojo.dnd.TreeDropTargetV3(node.contentNode, this.treeController, node.tree.DndAcceptTypes, node);
	},

	unlistenNode: function(node) {

		if (this.dragSources[node.widgetId]) {
			dojo.dnd.dragManager.unregisterDragSource(this.dragSources[node.widgetId]);
			delete this.dragSources[node.widgetId];
		}

		if (this.dropTargets[node.widgetId]) {
			dojo.dnd.dragManager.unregisterDropTarget(this.dropTargets[node.widgetId]);
			delete this.dropTargets[node.widgetId];
		}
	}

});

__CPAN_FILE__ src/widget/TimePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.TimePicker");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.event.*");
dojo.require("dojo.date.serialize");
dojo.require("dojo.date.format");
dojo.require("dojo.dom");
dojo.require("dojo.html.style");

dojo.requireLocalization("dojo.i18n.calendar", "gregorian");
dojo.requireLocalization("dojo.widget", "TimePicker");

dojo.widget.defineWidget(
	"dojo.widget.TimePicker",
	dojo.widget.HtmlWidget,
	function(){
		// selected time, JS Date object
		this.time = "";
		// set following flag to true if a default time should be set
		this.useDefaultTime = false;
		// set the following to true to set default minutes to current time, false to // use zero
		this.useDefaultMinutes = false;
		// rfc 3339 date
		this.storedTime = "";
		// time currently selected in the UI, stored in hours, minutes, seconds in the format that will be actually displayed
		this.currentTime = {};
		this.classNames = {
			selectedTime: "selectedItem"
		};
		this.any = "any"; //FIXME: never used?
		// dom node indecies for selected hour, minute, amPm, and "any time option"
		this.selectedTime = {
			hour: "",
			minute: "",
			amPm: "",
			anyTime: false
		};

		// minutes are ordered as follows: ["12", "6", "1", "7", "2", "8", "3", "9", "4", "10", "5", "11"]
		this.hourIndexMap = ["", 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11, 0];
		// minutes are ordered as follows: ["00", "30", "05", "35", "10", "40", "15", "45", "20", "50", "25", "55"]
		this.minuteIndexMap = [0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11];
	},
{
	isContainer: false,
	templatePath: dojo.uri.dojoUri("src/widget/templates/TimePicker.html"),
	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TimePicker.css"),

	fillInTemplate: function(args, frag){
		// Copy style info from input node to output node
		var source = this.getFragNodeRef(frag);
		dojo.html.copyStyle(this.domNode, source);

		this.initData();
		this.initUI();
	},

	postMixInProperties: function(localProperties, frag) {
		dojo.widget.TimePicker.superclass.postMixInProperties.apply(this, arguments);
		this.calendar = dojo.i18n.getLocalization("dojo.i18n.calendar", "gregorian", this.lang); // "am","pm"
		this.widgetStrings = dojo.i18n.getLocalization("dojo.widget", "TimePicker", this.lang); // "any"
	},

	initData: function() {
		// FIXME: doesn't currently validate the time before trying to set it
		// Determine the date/time from stored info, or by default don't 
		//  have a set time
		// FIXME: should normalize against whitespace on storedTime... for now 
		// just a lame hack
		if(this.storedTime.indexOf("T")!=-1 && this.storedTime.split("T")[1] && this.storedTime!=" " && this.storedTime.split("T")[1]!="any") {
			this.time = dojo.widget.TimePicker.util.fromRfcDateTime(this.storedTime, this.useDefaultMinutes, this.selectedTime.anyTime);
		} else if (this.useDefaultTime) {
			this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", this.useDefaultMinutes, this.selectedTime.anyTime);
		} else {
			this.selectedTime.anyTime = true;
			this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", 0, 1);
		}
	},

	initUI: function() {
		// set UI to match the currently selected time
		if(!this.selectedTime.anyTime && this.time) {
			var amPmHour = dojo.widget.TimePicker.util.toAmPmHour(this.time.getHours());
			var hour = amPmHour[0];
			var isAm = amPmHour[1];
			var minute = this.time.getMinutes();
			var minuteIndex = parseInt(minute/5);
			this.onSetSelectedHour(this.hourIndexMap[hour]);
			this.onSetSelectedMinute(this.minuteIndexMap[minuteIndex]);
			this.onSetSelectedAmPm(isAm);
		} else {
			this.onSetSelectedAnyTime();
		}
	},
	
	setTime: function(date) {
		if(date) {
			this.selectedTime.anyTime = false;
			this.setDateTime(dojo.date.toRfc3339(date));
		} else {
			this.selectedTime.anyTime = true;
		}
		this.initData();
		this.initUI();
	},

	setDateTime: function(rfcDate) {
		this.storedTime = rfcDate;
	},
	
	onClearSelectedHour: function(evt) {
		this.clearSelectedHour();
	},

	onClearSelectedMinute: function(evt) {
		this.clearSelectedMinute();
	},

	onClearSelectedAmPm: function(evt) {
		this.clearSelectedAmPm();
	},

	onClearSelectedAnyTime: function(evt) {
		this.clearSelectedAnyTime();
		if(this.selectedTime.anyTime) {
			this.selectedTime.anyTime = false;
			this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", this.useDefaultMinutes);
			this.initUI();
		}
	},

	clearSelectedHour: function() {
		var hourNodes = this.hourContainerNode.getElementsByTagName("td");
		for (var i=0; i<hourNodes.length; i++) {
			dojo.html.setClass(hourNodes.item(i), "");
		}
	},

	clearSelectedMinute: function() {
		var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
		for (var i=0; i<minuteNodes.length; i++) {
			dojo.html.setClass(minuteNodes.item(i), "");
		}
	},

	clearSelectedAmPm: function() {
		var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
		for (var i=0; i<amPmNodes.length; i++) {
			dojo.html.setClass(amPmNodes.item(i), "");
		}
	},

	clearSelectedAnyTime: function() {
		dojo.html.setClass(this.anyTimeContainerNode, "anyTimeContainer");
	},

	onSetSelectedHour: function(evt) {
		this.onClearSelectedAnyTime();
		this.onClearSelectedHour();
		this.setSelectedHour(evt);
		this.onSetTime();
	},

	setSelectedHour: function(evt) {
		if(evt && evt.target) {
			if(evt.target.nodeType == dojo.dom.ELEMENT_NODE) {
				var eventTarget = evt.target;
			} else {
				var eventTarget = evt.target.parentNode;
			}
			dojo.event.browser.stopEvent(evt);
			dojo.html.setClass(eventTarget, this.classNames.selectedTime);
			this.selectedTime["hour"] = eventTarget.innerHTML;
		} else if (!isNaN(evt)) {
			var hourNodes = this.hourContainerNode.getElementsByTagName("td");
			if(hourNodes.item(evt)) {
				dojo.html.setClass(hourNodes.item(evt), this.classNames.selectedTime);
				this.selectedTime["hour"] = hourNodes.item(evt).innerHTML;
			}
		}
		this.selectedTime.anyTime = false;
	},

	onSetSelectedMinute: function(evt) {
		this.onClearSelectedAnyTime();
		this.onClearSelectedMinute();
		this.setSelectedMinute(evt);
		this.selectedTime.anyTime = false;
		this.onSetTime();
	},

	setSelectedMinute: function(evt) {
		if(evt && evt.target) {
			if(evt.target.nodeType == dojo.dom.ELEMENT_NODE) {
				var eventTarget = evt.target;
			} else {
				var eventTarget = evt.target.parentNode;
			}
			dojo.event.browser.stopEvent(evt);
			dojo.html.setClass(eventTarget, this.classNames.selectedTime);
			this.selectedTime["minute"] = eventTarget.innerHTML;
		} else if (!isNaN(evt)) {
			var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
			if(minuteNodes.item(evt)) {
				dojo.html.setClass(minuteNodes.item(evt), this.classNames.selectedTime);
				this.selectedTime["minute"] = minuteNodes.item(evt).innerHTML;
			}
		}
	},

	onSetSelectedAmPm: function(evt) {
		this.onClearSelectedAnyTime();
		this.onClearSelectedAmPm();
		this.setSelectedAmPm(evt);
		this.selectedTime.anyTime = false;
		this.onSetTime();
	},

	setSelectedAmPm: function(evt) {
		var eventTarget = evt.target;
		if(evt && eventTarget) {
			if(eventTarget.nodeType != dojo.dom.ELEMENT_NODE) {
				eventTarget = eventTarget.parentNode;
			}
			dojo.event.browser.stopEvent(evt);
			this.selectedTime.amPm = eventTarget.id;
			dojo.html.setClass(eventTarget, this.classNames.selectedTime);
		} else {
			evt = evt ? 0 : 1;
			var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
			if(amPmNodes.item(evt)) {
				this.selectedTime.amPm = amPmNodes.item(evt).id;
				dojo.html.setClass(amPmNodes.item(evt), this.classNames.selectedTime);
			}
		}
	},

	onSetSelectedAnyTime: function(evt) {
		this.onClearSelectedHour();
		this.onClearSelectedMinute();
		this.onClearSelectedAmPm();
		this.setSelectedAnyTime();
		this.onSetTime();
	},

	setSelectedAnyTime: function(evt) {
		this.selectedTime.anyTime = true;
		dojo.html.setClass(this.anyTimeContainerNode, this.classNames.selectedTime + " " + "anyTimeContainer");
	},

	onClick: function(evt) {
		dojo.event.browser.stopEvent(evt);
	},

	onSetTime: function() {
		if(this.selectedTime.anyTime) {
			this.time = new Date();
			var tempDateTime = dojo.widget.TimePicker.util.toRfcDateTime(this.time);
			this.setDateTime(tempDateTime.split("T")[0]);
		} else {
			var hour = 12;
			var minute = 0;
			var isAm = false;
			if(this.selectedTime["hour"]) {
				hour = parseInt(this.selectedTime["hour"], 10);
			}
			if(this.selectedTime["minute"]) {
				minute = parseInt(this.selectedTime["minute"], 10);
			}
			if(this.selectedTime["amPm"]) {
				isAm = (this.selectedTime["amPm"].toLowerCase() == "am");
			}
			this.time = new Date();
			this.time.setHours(dojo.widget.TimePicker.util.fromAmPmHour(hour, isAm));
			this.time.setMinutes(minute);
			this.setDateTime(dojo.widget.TimePicker.util.toRfcDateTime(this.time));
		}
	}
});

dojo.widget.TimePicker.util = new function() {
	// utility functions
	this.toRfcDateTime = function(jsDate) {
		if(!jsDate) {
			jsDate = new Date();
		}
		jsDate.setSeconds(0);
		return dojo.date.strftime(jsDate, "%Y-%m-%dT%H:%M:00%z"); //FIXME: use dojo.date.toRfc3339 instead
	}

	this.fromRfcDateTime = function(rfcDate, useDefaultMinutes, isAnyTime) {
		var tempDate = new Date();
		if(!rfcDate || rfcDate.indexOf("T")==-1) {
			if(useDefaultMinutes) {
				tempDate.setMinutes(Math.floor(tempDate.getMinutes()/5)*5);
			} else {
				tempDate.setMinutes(0);
			}
		} else {
			var tempTime = rfcDate.split("T")[1].split(":");
			// fullYear, month, date
			var tempDate = new Date();
			tempDate.setHours(tempTime[0]);
			tempDate.setMinutes(tempTime[1]);
		}
		return tempDate;
	}

	this.toAmPmHour = function(hour) {
		var amPmHour = hour;
		var isAm = true;
		if (amPmHour == 0) {
			amPmHour = 12;
		} else if (amPmHour>12) {
			amPmHour = amPmHour - 12;
			isAm = false;
		} else if (amPmHour == 12) {
			isAm = false;
		}
		return [amPmHour, isAm];
	}

	this.fromAmPmHour = function(amPmHour, isAm) {
		var hour = parseInt(amPmHour, 10);
		if(isAm && hour == 12) {
			hour = 0;
		} else if (!isAm && hour<12) {
			hour = hour + 12;
		}
		return hour;
	}
}

__CPAN_FILE__ src/widget/SlideShow.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.SlideShow");

dojo.require("dojo.event.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.html.display");

dojo.widget.defineWidget(
	"dojo.widget.SlideShow",
	dojo.widget.HtmlWidget,
	{
		templatePath: dojo.uri.dojoUri("src/widget/templates/SlideShow.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/templates/SlideShow.css"),

		// useful properties
		imgUrls: [],		// the images we'll go through
		imgUrlBase: "",
		urlsIdx: 0,		// where in the images we are
		delay: 4000, 		// give it 4 seconds
		transitionInterval: 2000, // 2 seconds
		imgWidth: 800,	// img width
		imgHeight: 600,	// img height
		background: "img2", // what's in the bg
		foreground: "img1", // what's in the fg
		stopped: false,	// should I stay or should I go?
		fadeAnim: null, // references our animation

		// our DOM nodes:
		imagesContainer: null,
		startStopButton: null,
		controlsContainer: null,
		img1: null,
		img2: null,
		preventCache: false,

		fillInTemplate: function(){
			// safari will cache the images and not fire an image onload event if
			// there are only two images in the slideshow
			if(dojo.render.html.safari && this.imgUrls.length == 2) {
				this.preventCache = true;
			}
			dojo.html.setOpacity(this.img1, 0.9999);
			dojo.html.setOpacity(this.img2, 0.9999);
			with(this.imagesContainer.style){
				width = this.imgWidth+"px";
				height = this.imgHeight+"px";
			}
			with(this.img1.style){
				width = this.imgWidth+"px";
				height = this.imgHeight+"px";
			}
			with(this.img2.style){
				width = this.imgWidth+"px";
				height = this.imgHeight+"px";
			}
			if(this.imgUrls.length>1){
				this.img2.src = this.imgUrlBase+this.imgUrls[this.urlsIdx++] + this.getUrlSuffix();
				this.endTransition();
			}else{
				this.img1.src = this.imgUrlBase+this.imgUrls[this.urlsIdx++] + this.getUrlSuffix();
			}
		},

		getUrlSuffix: function() {
			if(this.preventCache) {
				return "?ts=" + (new Date()).getTime();
			} else {
				return "";
			}
		},
		
		togglePaused: function(){
			dojo.debug("pause");
			if(this.stopped){
				this.stopped = false;
				this.backgroundImageLoaded();
				this.startStopButton.value= "pause";
			}else{
				this.stopped = true;
				this.startStopButton.value= "play";
			}
		},

		backgroundImageLoaded: function(){
			// start fading out the foreground image
			if(this.stopped){ return; }

			// actually start the fadeOut effect
			// NOTE: if we wanted to use other transition types, we'd set them up
			// 		 here as well
			if(this.fadeAnim) {
				this.fadeAnim.stop();
			}
			this.fadeAnim = dojo.lfx.fadeOut(this[this.foreground], 
				this.transitionInterval, null);
			dojo.event.connect(this.fadeAnim,"onEnd",this,"endTransition");
			this.fadeAnim.play();
		},

		endTransition: function(){
			// move the foreground image to the background 
			with(this[this.background].style){ zIndex = parseInt(zIndex)+1; }
			with(this[this.foreground].style){ zIndex = parseInt(zIndex)-1; }

			// fg/bg book-keeping
			var tmp = this.foreground;
			this.foreground = this.background;
			this.background = tmp;
			// keep on truckin
			this.loadNextImage();
		},

		loadNextImage: function(){
			// load a new image in that container, and make sure it informs
			// us when it finishes loading
			dojo.event.kwConnect({
				srcObj: this[this.background],
				srcFunc: "onload",
				adviceObj: this,
				adviceFunc: "backgroundImageLoaded",
				once: true, // make sure we only ever hear about it once
				delay: this.delay
			});
			dojo.html.setOpacity(this[this.background], 1.0);
			this[this.background].src = this.imgUrlBase+this.imgUrls[this.urlsIdx++];
			if(this.urlsIdx>(this.imgUrls.length-1)){
				this.urlsIdx = 0;
			}
		}
	}
);

__CPAN_FILE__ src/widget/SwtWidget.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.SwtWidget");

dojo.require("dojo.event.*");
dojo.require("dojo.widget.Widget");
dojo.require("dojo.uri.*");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.extras");

try{
	importPackage(Packages.org.eclipse.swt.widgets);

	dojo.declare("dojo.widget.SwtWidget", dojo.widget.Widget,
		function() {
			if((arguments.length>0)&&(typeof arguments[0] == "object")){
				this.create(arguments[0]);
			}
		},
	{
		display: null,
		shell: null,

		show: function(){ },
		hide: function(){ },

		addChild: function(){ },
		registerChild: function(){ },
		addWidgetAsDirectChild: function(){ },
		removeChild: function(){ },
		cleanUp: function(){ },
		destroyRendering: function(){ },
		postInitialize: function(){ },
	});

	// initialize SWT runtime

	dojo.widget.SwtWidget.prototype.display = new Display();
	dojo.widget.SwtWidget.prototype.shell = new Shell(dojo.widget.SwtWidget.prototype.display);

	dojo.widget.manager.startShell = function(){
		var sh = dojo.widget.SwtWidget.prototype.shell;
		var d = dojo.widget.SwtWidget.prototype.display;
		sh.open();
		while(!sh.isDisposed()){
			dojo.widget.manager.doNext();
			if(!d.readAndDispatch()){
				d.sleep();
			}
		}
		d.dispose();
	};
}catch(e){
	// seems we didn't have the SWT classes in the environment. Log it.
	dojo.debug("dojo.widget.SwtWidget not loaded. SWT classes not available");
}

__CPAN_DIR__ src/widget/html
__CPAN_FILE__ src/widget/html/loader.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.html.loader");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.io.*");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.extras");

dojo.require("dojo.experimental");

// as this is a singleton dojo.declare doesn't buy us anything here
dojo.widget.html.loader = new (function(){
	// summary:
	// 	loading stuff moved out of contentpane to make it directly accessible by other widgets
	this.toString = function(){ return "dojo.widget.html.loader"; }
	var _loader = this;

	// back/forward tracking
	dojo.addOnLoad(function(){
		dojo.experimental(_loader.toString());
		var undo = dojo.evalObjPath("dojo.undo.browser");
		if(djConfig["preventBackButtonFix"] && undo && !undo.initialState){
			undo.setInitialState(new trackerObj);
		}
	});

	var logger = {};
	var trackerObj = function(id, data){
		this.id = id;
		this.data = data
	};
	trackerObj.prototype.handle = function(type){
		if(typeof dojo == 'undefined'){ return; } // wtf? how can dojo become undef?
		var wg = dojo.widget.byId(this.id);
		if(wg){ wg.setContent(this.data, true); }
	};

	this._log = function(widget, data){
		// if a loader widget B is a child of loader widget A
		// we need to destroy all of B's undo if we switch content
		if(widget.trackHistory){
			if(!logger[widget.widgetId]){
				logger[widget.widgetId] = { childrenIds: [], stack:[data] };
			}var children = logger[widget.widgetId].childrenIds;
			while(children && children.length){
				delete logger[children.pop()];
			}
			for(var child in widget.children){
				logger[widget.widgetId].childrenIds = child.widgetId;
			}
			dojo.undo.browser.addToHistory(new trackerObj(widget.widgetId, dojo.lang.shallowCopy(data, true)));
		}
	}

	// shortCuts
	var undef = dojo.lang.isUndefined;
	var isFunc = dojo.lang.isFunction;



	/************ private needed functions, no need to be part of widget API ***********/
	// useful if user wants to prevent default behaviour ie: _setContent("Error...")
	function handleDefaults(e, handler, useAlert){
		if(!handler){ handler = "onContentError"; }
		if(dojo.lang.isString(e)){ e = {_text: e}; }
		if(!e._text){ e._text = e.toString(); }
		e.toString = function(){ return this._text; };
		if(typeof e.returnValue != "boolean"){
			e.returnValue = true; 
		}
		if(typeof e.preventDefault != "function"){
			e.preventDefault = function(){ this.returnValue = false; };
		}
		// call our handler
		this[handler](e);
		if(e.returnValue){
			if(useAlert){
				alert(e.toString());
			}else{
				this.loader.callOnUnLoad.call(this, false);
				this.onSetContent(e.toString());
			}
		}
	};

	// set up downloader, used by both scripts and content
	function downloader(bindArgs) {
		for(var x in this.bindArgs){
			bindArgs[x] = (undef(bindArgs[x]) ? this.bindArgs[x] : undefined);
		}
		var cache = this.cacheContent;
		if(undef(bindArgs.useCache)){ bindArgs.useCache = cache; }
		if(undef(bindArgs.preventCache)){ bindArgs.preventCache = !cache; }
		if(undef(bindArgs.mimetype)){ bindArgs.mimetype = "text/html"; }
		this.loader.bindObj = dojo.io.bind(bindArgs);
	};

	// runs addOnLoad/addOnUnLoad functions
	function stackRunner(st){
		var err = "", func = null;
		var scope = this.scriptScope || dojo.global();
		while(st.length){
			func = st.shift();
			try{
				func.call(scope);
			}catch(e){
				err += "\n"+func+" failed: "+e;
			}
		}
		if(err.length){
			var name = (st== this.loader.addOnLoads) ? "addOnLoad" : "addOnUnLoad";
			handleDefaults.call(this, name+" failure\n "+err, "onExecError", true);
		}
	};

	// push addOnLoad and addOnUnLoad functions onto stack
	function stackPusher(st, obj, func){
		if(typeof func == 'undefined') {
			st.push(obj);
		}else{
			st.push(function(){ obj[func](); });
		}
	};

	// code saver, collects onLoad, onResized and isLoaded
	function refreshed(){
		this.onResized();
		this.onLoad();
		this.isLoaded = true;
	};

	// runs scripts and starts the content parser
	function asyncParse(data){
		if(this.executeScripts){
			this.onExecScript.call(this, data.scripts);
		}
		if(this.parseContent){
			this.onContentParse.call(this);
		}
		refreshed.call(this);
	};

	// run java function
	function runHandler(){
		//FIXME: current behaviour is to return false if handler is there; is that intended?
		if(dojo.lang.isFunction(this.handler)) {
			this.handler(this, this.containerNode||this.domNode);
			refreshed.call(this);
			return false;
		}
		return true;
	};

	// divided up splitAndFixPaths in different parts
	this.htmlContentBasicFix = function(/*string*/s, /*string||dojo.uri.Uri*/url){
		// summary:
		//	strips out <style, <link rel=stylesheet and <title tags
		//	intended to take out tags that might cause DOM faults
		var titles = [], styles = [];
		/************** <title> ***********/
		// khtml can't attach a <style> or <title> node as child of body
		var regex = /<title[^>]*>([\s\S]*?)<\/title>/i;
		var match, attr;
		while(match = regex.exec(s)){
			titles.push(match[1]);
			s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
		};
		/****************  cut out all <style> and <link rel="stylesheet" href=".."> **************/
		regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i;
		while(match = regex.exec(s)){
			if(match[1] && match[1].toLowerCase() == "style"){
				styles.push(dojo.html.fixPathsInCssText(match[2],url));
			}else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){
				styles.push({path: attr[2]});
			}
			s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
		};
		return {'s': s, 'titles': titles, 'styles': styles};//object
	};

	this.htmlContentAdjustPaths = function(/*string*/s, /*string||dojo.uri.Uri*/url){
		// summary:
		//	adjusts relative paths in content to be relative to current page
		var tag = "", str = "", tagFix = "", path = "";
		var attr = [], origPath = "", fix = "";

		// attributepaths one tag can have multiple paths example:
		// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
		// strip out the tag and run fix on that.
		// this guarantees that we won't run replace on another tag's attribute + it was easier do
		var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i;
		var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i;
		// these are the supported protocols, all other is considered relative
		var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/;

		while(tag = regexFindTag.exec(s)){
			str += s.substring(0, tag.index);
			s = s.substring((tag.index + tag[0].length), s.length);
			tag = tag[0];

			// loop through attributes
			tagFix = '';
			while(attr = regexFindAttr.exec(tag)){
				path = ""; origPath = attr[3];
				switch(attr[1].toLowerCase()){
					case "src":// falltrough
					case "href":
						if(regexProtocols.exec(origPath)){
							path = origPath;
						} else {
							path = (new dojo.uri.Uri(url, origPath).toString());
						}
						break;
					case "style":// style
						path = dojo.html.fixPathsInCssText(origPath, url);
						break;
					default:
						path = origPath;
				}

				fix = " " + attr[1] + "=" + attr[2] + path + attr[2];

				// slices up tag before next attribute check
				tagFix += tag.substring(0, attr.index) + fix;
				tag = tag.substring((attr.index + attr[0].length), tag.length);
			}
			str += tagFix + tag;
		}
		return str+s; // string
	};


	this.htmlContentScripts = function(/*string*/s, /*boolean*/collectScripts){
		// summary:
		// 	handles scripts and dojo .require(...) etc calls
		// NOTE: we need to go through here even if we have executeScripts=false
		//		 and if we have parseWidgets true 
		var scripts = [], requires = [], match = [];
		var attr = "", tmp = null, tag = "", sc = "", str = "";
		
		/***************** cut out all <script> tags, push them into scripts array ***************/
		var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i;
		var regexSrc = /src=(['"]?)([^"']*)\1/i;
		var regexDojoJs = /.*(\bdojo\b\.js(?:\.uncompressed\.js)?)$/;
		var regexInvalid = /(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g;
		var regexRequires = /dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix)|defineNamespace)\((['"]).*?\1\)\s*;?/;

		while(match = regex.exec(s)){
			if(this.executeScripts && match[1]){
				if(attr = regexSrc.exec(match[1])){
					// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
					// we declare all files named dojo.js as bad, regardless of path
					if(regexDojoJs.exec(attr[2])){
						dojo.debug("Security note! inhibit:"+attr[2]+" from  beeing loaded again.");
					}else{
						scripts.push({path: attr[2]});
					}
				}
			}
			if(match[2]){
				// remove all invalid variables etc like djConfig and dojo.hostenv.writeIncludes()
				sc = match[2].replace(regexInvalid, "");
				if(!sc){ continue; }

				// cut out all dojo .require (...) calls, if we have execute 
				// scripts false widgets don't get their require calls
				// takes out possible widgetpackage registration as well
				while(tmp = regexRequires.exec(sc)){
					requires.push(tmp[0]);
					sc = sc.substring(0, tmp.index) + sc.substr(tmp.index + tmp[0].length);
				}
				if(collectScripts){
					scripts.push(sc);
				}
			}
			s = s.substr(0, match.index) + s.substr(match.index + match[0].length);
		}
		/******** scan for scriptScope in html eventHandlers 
					and replace with link to this widget *********/
		if(collectScripts){
			var regex = /(<[a-zA-Z][a-zA-Z0-9]*\s[^>]*\S=(['"])[^>]*[^\.\]])scriptScope([^>]*>)/;
			str = "";
			while(tag = regex.exec(s)){
				tmp = ((tag[2]=="'") ? '"': "'");
				str += s.substring(0, tag.index);
				s = s.substr(tag.index).replace(regex, "$1dojo.widget.byId("+ tmp + this.widgetId + tmp + ").scriptScope$3");
			}
			s = str + s;
		}
		return {'s': s, 'requires': requires, 'scripts': scripts}; // object
	};

		
	this.splitAndFixPaths = function(/*object*/args){
		// summary:
		//	pathfixes, require calls, css stuff and neccesary content clean
		// args:
		//	content 		string
		//	url 			string? or dojo.uri.Uri that that pulled the content in, for path adjust
		//	adjustPaths		boolean, if true adjust relative paths in content to match this page
		//	collectScripts	boolean, if true it takes out all <script and <script src=.. tags and collects
		//					 dojo.require calls in a separate array, useful for eval
		//	collectRequires	boolean, if true and collectScripts is false it still collects scripts along with
		//					 dojo.require calls
		//	bodyExtract		boolean, if true only return content inside of the body tag

		// return:			{xml: string,
		//					styles: array, remote style get object {path: /*string*/url}
		//					requires: array,
		//					scripts: array, remote scripts get object {path: /*string*/url}
		//					url: string}
		if(!args.url) { args.url = "./"; } // point to this page if not set
		// make sure back/forward buttons don't mess up url.
		url = new dojo.uri.Uri(location, args.url).toString();
		var ret = {'xml': 	"",
				'styles':	[],
				'titles':	[],
				'requires':	[],
				'scripts':	[],
				'url':		url };

		if(args.content){ // make sure we don't run regexes on empty content
			var tmp = null, content = args.content;
			if(args.adjustPaths){
				content = _loader.htmlContentAdjustPaths.call(this, content, url);
			}

			tmp = _loader.htmlContentBasicFix.call(this, content, url);
			content = tmp.s;
			ret.styles = tmp.styles;
			ret.titles = tmp.titles;

			if(args.collectRequires || args.collectScripts){
				tmp = _loader.htmlContentScripts.call(this, content, args.collectScripts);
				content = tmp.s;
				ret.requires = tmp.requires;
				ret.scripts = tmp.scripts;
			}

			/********* extract content *********/
			var match = [];
			if(args.bodyExtract){
				match = content.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
				if(match) { content = match[1]; }
			}
			ret.xml = content;
		}
		return ret;// object 
	};


	// the all important startup function
	this.hookUp = function(/*object*/args){
		// summary:
		// 	mixin or extend loader into a widget
		// args:
		//	widget: widget reference
		//	mixin: boolean, default false
		// 		if mixin true, it will only extend the current widget, not its prototype
		var widget = args.widget;
		if(dojo.lang.isString(widget)){
			if(args.mixin){	
				dojo.raise(this.toString()+", cant use mixin when widget is a string");
			 }
			widget = dojo.evalObjPath(widget);
		}
		if(!widget || !(widget instanceof dojo.widget.HtmlWidget)){
			dojo.raise(this.toString()+" Widget isn't defined or isn't a HtmlWidget instance"); 
		}
		// make sure we don't mixin more than once
		if(widget.loader && widget.setUrl){ return; }

		// extend widget prototype or mixin this widget instance
		var widgetProto = (args.mixin) ? widget : widget.constructor.prototype;
	
		/********************************************
		** per widgetImpl variables, mixin into widget 
		********************************************/
		// stuff it into a loader obj
		widget.loader = {
			isLoaded: false,
			styleNodes:  [],
			addOnLoads: [],
			addOnUnLoads: [],
			callOnUnLoad:(function(canCall){
							return function(after){ this.abort();
								if(canCall){ this.onUnLoad(); }
								canCall = after;
							};
						})(false),
			bindObj: null,
			// to disconnect widget
			unHook: (function(w, wg){
				var oldProps = {
					isContainer: w.isContainer,
					adjustPats: w.adjustPaths,
					href: w.href,
					extractContent: w.extractContent,
					parseContent: w.parseContent,
					cacheContent: w.cacheContent,
					bindArgs: w.bindArgs,
					preload: w.preload,
					refreshOnShow: w.refreshOnShow,
					handler: w.handler,
					trackHistory: w.trackHistory,
					executeScripts: w.executeScripts,
					scriptScope: w.scriptScope,
					// functions
					postCreate: w.postCreate,
					show: w.show,
					refresh: w.refresh,
					loadContents: w.loadContents,
					abort: w.abort,
					destroy: w.destroy,
					onLoad: w.onLoad,
					onUnLoad: w.onUnLoad,
					addOnLoad: w.addOnLoad,
					addOnUnLoad: w.addOnUnLoad,
					onDownloadStart: w.onDownloadStart,
					onDownloadEnd: w.onDownloadEnd,
					onDownloadError: w.onDownloadError,
					onContentError: w.onContentError,
					onExecError: w.onExecError,
					onSetContent: w.onSetContent,
					setUrl: w.setUrl,
					setContent: w.setContent,
					onContentParse: w.onContentParse,
					onExecScript: w.onExecScript,
					setHandler: w.setHandler
				};
				return function(){
					if(wg.abort){ wg.abort(); }
					// make sure we don't unhook prototype if there are more widgets of this type left
					if((w != wg) && (dojo.widget.byType(wg.widgetType).length>1)){ return; }
					for(var x in oldProps){
						if(oldProps[x]===undefined){
							delete w[x]; continue;
						}
						w[x] = oldProps[x];
					}
					delete wg._loader_defined;
					delete wg.loader;
				};
			})(widgetProto, widget)
		};

		// make sure we don't do this more than once per widget/widgetprototype
		if(widgetProto._loader_defined || widget._loader_defined){ return; }		

		/**************** private variables *********************/

		// loading options, prototype parts of widget's mixin to prototype
		dojo.mixin(widgetProto, {
			// always set to a containerwidget
			isContainer: true,
			// fix relative paths in content to fit into this page
			adjustPaths: 	undef(widgetProto.adjustPaths) ? true : widgetProto.adjustPaths,
			// only usable on construction, use setUrl or setContent after that
			href: 			undef(widgetProto.href) ? "" : widgetProto.href,
			// extract visible content from inside of <body> .... </body>
			extractContent: undef(widgetProto.extractContent) ? true : widgetProto.extractContent,
			// construct all widgets that is in content
			// FIXME: rename to parseWidgets?
			parseContent: 	undef(widgetProto.parseContent) ? true : widgetProto.parseContent,
			// use io binds javascript cache, or if false, prevent browsercache
			cacheContent: 	undef(widgetProto.cacheContent) ? true : widgetProto.cacheContent,
			// specify  specific  io.bind arguments such as transport and useCache
			bindArgs:		undef(widgetProto.bindArgs) ? {} : widgetProto.bindArgs,
			// force load even if widget isn't shown (lazyload setting)
			preload: 		undef(widgetProto.preload) ? false : widgetProto.preload,
			// reload content automatically onShow, use with cacheContent = flase
			refreshOnShow:	undef(widgetProto.refreshOnShow) ? false : widgetProto.refreshOnShow,
			// name of java function which should generate content
			handler: 		undef(widgetProto.handler) ? "" : widgetProto.handler,
			// if true scripts in content will be evaled after content is innerHTML'ed
			executeScripts: undef(widgetProto.executeScripts) ? false : widgetProto.executeScripts,
			// log contents (back/forward support)
			trackHistory:	undef(widgetProto.tracHistory) ? false : widgetProto.trackHistory,
			scriptScope: null // always overwrite
		});

		/****************************************************
		******* public functions, becomes part of widget's API
		*****************************************************/

		/*********** Public functions that wigets cant overide **********/
		// set up postCreate, call originalcode before our own
		widgetProto.postCreate = (function(postCreate){
			return function(){
				if(widgetProto.constructor.superclass.postCreate != postCreate){
					postCreate.apply(this, arguments);
				}else{
					widgetProto.constructor.superclass.postCreate.apply(this, arguments);
				}
				if(this.handler!==""){ this.setHandler(this.handler); }
				if(this.isShowing() || this.preload){ 
					this.loadContents();
					if(!this.href){ // back/forward save initial state
						_loader._log(this,(this.domNode||this.containerNode).innerHTML);
					}
				}
			}
		})(widgetProto.postCreate);

		// set up onShow listener, call original code after this block
		widgetProto.show = (function(show){
			return function(){
				// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
				if(this.refreshOnShow){
					this.refresh();
				}else{ 
					this.loadContents();
				}
				if((widgetProto.constructor.superclass.show == show) || !isFunc(show)){
					widgetProto.constructor.superclass.show.apply(this, arguments);
				}else{
					show.apply(this, arguments);
				}
			};
		})(widgetProto.show);

		// destroy cleanups, original code in the middle
		widgetProto.destroy = (function(destroy){
			return function(destroy){
				this.onUnLoad();
				this.abort();
				this.loader.unHook();
				if((widgetProto.constructor.superclass.destroy != destroy) && isFunc(destroy)){
					destroy.apply(this, arguments);
				}else{
					widgetProto.constructor.superclass.destroy.apply(this, arguments);
				}
			}
		})(widgetProto.destroy);


		/******* Public functions that widgets can overide *****/
		// set up a refresh function
		if(!widgetProto.refresh){
			widgetProto.refresh = function(){
				this.loader.isLoaded = false;
				this.loadContents();
			};
		}

		// set up html loading contents
		if(!widgetProto.loadContents){
			widgetProto.loadContents = function(){
				if(this.loader.isLoaded){ return; }
				// javafunction
				if(isFunc(this.handler)){
					runHandler.call(this);
				}else if(this.href !== ""){
					handleDefaults.call(this, "Loading...", "onDownloadStart");
					var self = this, url = this.href;
					downloader.call(this, {
						url: url,
						load: function(type, data, xhr){
							self.onDownloadEnd.call(self, url, data);
						},
						error: function(type, err, xhr){
							// XHR insnt a normal JS object, copy esentials
							var e = {
								responseText: xhr.responseText,
								status: xhr.status,
								statusText: xhr.statusText,
								responseHeaders: (xhr.getAllResponseHeaders) ? xhr.getAllResponseHeaders():[],
								_text: "Error loading '" + url + "' (" + xhr.status + " "+  xhr.statusText + ")"
							};
							handleDefaults.call(self, e, "onDownloadError");
							self.onLoad();
						}
					});
				}
			};
		}

		// set up abort
		if(!widgetProto.abort){
			widgetProto.abort = function(){
				if(!this.loader || !this.loader.bindObj || !this.loader.bindObj.abort){ return; }
				this.loader.bindObj.abort();
				this.loader.bindObj = null;
			};
		}

		// onLoad
		if(!widgetProto.onLoad){
			widgetProto.onLoad = function(){
				stackRunner.call(this, this.loader.addOnLoads);
				this.loader.isLoaded = true;
			};
		}

		// onUnLoad, original code in the middle
		if(!widgetProto.onUnLoad){
			widgetProto.onUnLoad = function(){
				stackRunner.call(this, this.loader.addOnUnLoads);
				delete this.scriptScope;
			}
		}

		// add to onLoad queue
		if(!widgetProto.addOnLoad){
			widgetProto.addOnLoad = function(obj, func){
				stackPusher.call(this, this.loader.addOnLoads, obj, func);
			};
		}

		// add to onUnLoad queue 
		if(!widgetProto.addOnUnLoad){
			widgetProto.addOnUnLoad = function(obj, func){
				stackPusher.call(this, this.loader.addOnUnLoads, obj, func);
			}
		}

		// script or java errors, preventDefault-able
		if(!widgetProto.onExecError){
			widgetProto.onExecError = function(){/*stub*/};
		}
	
		// called on DOM faults, require fault etc in content, preventDefault-able
		if(!widgetProto.onContentError){
			widgetProto.onContentError = function(){/*stub*/};
		}
	
		// called when download error occurs, preventDefault-able
		if(!widgetProto.onDownloadError){
			widgetProto.onDownloadError = function(){/*stub*/};
		}
	
		// called before download starts, preventDefault-able
		if(!widgetProto.onDownloadStart){
			widgetProto.onDownloadStart = function(onDownloadStart){/*stub*/};
		}
	
		// called when download is finished successfully
		if(!widgetProto.onDownloadEnd){
			widgetProto.onDownloadEnd = function(url, data){
				var args =  {content: data,
							url: url,
							adjustPaths: this.adjustPaths,
							collectScripts: this.executeScripts,
							collectRequires: this.parseContent,
							bodyExtract: this.extractContent };
				data = _loader.splitAndFixPaths.call(this, args);
				this.setContent(data);
			}
		}

		// previously called _setContent, widget defined onSetContent can modify content or cancel
		if(!widgetProto.onSetContent){
			widgetProto.onSetContent = function(cont){
				this.destroyChildren();
		
				// remove old stylenodes from HEAD
				var styleNodes = this.loader.styleNodes;
				while(styleNodes.length){
					var st = styleNodes.pop();
					if(st && st.parentNode){
						st.parentNode.removeChild(st);
					}
				}
		
				var node = this.containerNode || this.domNode;
				while(node.firstChild){
					try{
						dojo.event.browser.clean(node.firstChild);
					}catch(e){}
					node.removeChild(node.firstChild);
				}
				try{
					if(typeof cont != "string"){
						node.appendChild(cont);
					}else{
						try{// hack to deal with domfaults, ie. appending div to tablenodes
							node.innerHTML = cont;
						}catch(e){var tmp;
							(tmp = dojo.doc().createElement("div")).innerHTML = cont;
							while(tmp.firstChild){
								node.appendChild(tmp.removeChild(tmp.firstChild));
							}
						}
					}
				}catch(e){
					e._text = "Could'nt load content: "+e;
					var useAlert = (this.loader._onSetContent_err == e._text); // make sure we don't loop
					this.loader._onSetContent_err = e._text;
					handleDefaults.call(this, e, "onContentError", useAlert);
				}
			};
		}

		if(!widgetProto.setUrl){
			widgetProto.setUrl = function(url){
				this.href = url;
				this.loader.isLoaded = false;
				if ( this.preload || this.isShowing() ){
					this.loadContents();
				}
			}
		}

		if(!widgetProto.setContent){
			widgetProto.setContent = function(data, don'tLog){
				this.loader.callOnUnLoad.call(this, true);
		
				if(!data||dojo.html.isNode(data)){
					this.onSetContent(data);
					refreshed.call(this);
				}else{
					// need to run splitAndFixPaths? ie. manually setting content
					// adjustPaths is taken care of inside splitAndFixPaths
					if(typeof data.xml != 'string'){
						this.href = ""; // so we can refresh safely
						var args =  {content: data,
							url: this.href,
							adjustPaths: this.adjustPaths,
							collectScripts: this.executeScripts,
							collectRequires: this.parseContent,
							bodyExtract: this.extractContent };
						data = _loader.splitAndFixPaths.call(this, args); 
					}else if(data.url!="./"){
						 this.url = data.url;// backbutton thing
					}
					this.onSetContent(data.xml);
	
					// insert styles from content (in same order they came in)
					for(var i = 0, styles = data.styles; i < styles.length; i++){
						if(styles[i].path){
							this.loader.styleNodes.push(dojo.html.insertCssFile(styles[i].path));
						}else{
							this.loader.styleNodes.push(dojo.html.insertCssText(styles[i]));
						}
					}
		
					if(this.parseContent){
						for(var i = 0, requires = data.requires; i < requires.length; i++){
							try{
								eval(requires[i]);
							} catch(e){
								e._text = "dojo.widget.html.loader.hookUp: error in package loading calls, "+(e.description||e);
								handleDefaults.call(this, e, "onContentError", true);
							}
						}
					}
					// need to allow async load, Xdomain uses it
					// NOTE: on Xdomain loads this can break the sync thread of setContent
					// 		if you you do any dojo. require(...) etc
					if(dojo.hostenv.isXDomain && data.requires.length){
						dojo.addOnLoad(function(){ 
							asyncParse.call(this, data);
							if(!don'tLog){
								_loader._log(this, data);
							}
						});// this opens a thread need abort undo
						don'tLog = true;
					}else{
						asyncParse.call(this, data);
					}
				}if(!don'tLog){
// 					_loader._log(this, data);
				}
			};
		}

		if(!widgetProto.onContentParse){
			widgetProto.onContentParse = function(){
				var node = this.containerNode || this.domNode;
				var parser = new dojo.xml.Parse();
				var frag = parser.parseElement(node, null, true);
				dojo.widget.getParser().createSubComponents(frag, this);
			};
		}

		// previously called _executeScripts
		if(!widgetProto.onExecScript){
			widgetProto.onExecScript = function(scripts){
				// loop through the scripts in the order they came in
				var self = this, tmp = "", code = "";
				for(var i = 0; i < scripts.length; i++){ // remotescript
					if(scripts[i].path){
						var url = scripts[i].path;
						downloader.call(this,{
							'url': 		url,
							'load': function(type, scriptStr){
								(function(){tmp = scriptStr; scripts[i] = scriptStr;}).call(self);
							},
							'error': function(type, error){
								error._text = type + " downloading remote script";
								handleDefaults.call(self, error, "onExecError", true);
							},
							'mimetype': "text/plain",
							'sync':     true
						});
						code += tmp;
					}else{
						code += scripts[i];
					}
				}

				try{
					// initialize a new anonymous container for our script, don't make it part of this widget's scope chain
					// instead send in a variable that points to this widget, useful to connect events to onLoad, onUnLoad etc..
					delete this.scriptScope;
					this.scriptScope = new (new Function('_container_', code+'; return this;'))(self);
				}catch(e){
					e._text = "Error running scripts from content:\n"+(e.description||e.toString());
					handleDefaults.call(this, e, "onExecError", true);
				}
			};
		}

		// Generate content from given java function
		if(!widgetProto.setHandler){
			widgetProto.setHandler = function(handler) {
				var fcn = dojo.lang.isFunction(handler) ? handler : window[handler];
				if(!isFunc(fcn)) {
					// FIXME: needs testing! somebody with java knowledge needs to try this
					handleDefaults.call(this, "Unable to set handler, '" + handler + "' not a function.", "onExecError", true);
					return;
				}
				this.handler = function() {
					return fcn.apply(this, arguments);
				};
			};
		}

		// make sure we extend this widget only once
		widgetProto._loader_defined = true;
	};


})();

__CPAN_FILE__ src/widget/html/stabile.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

// Maintain state of widgets when user hits back/forward button

dojo.provide("dojo.widget.html.stabile");

dojo.widget.html.stabile = {
	// Characters to quote in single-quoted regexprs
	_sqQuotables: new RegExp("([\\\\'])", "g"),

	// Current depth.
	_depth: 0,

	// Set to true when calling v.toString, to sniff for infinite
	// recursion.
	_recur: false,

	// Levels of nesting of Array and object displays.
	// If when >= depth, no display or array or object internals.
	depthLimit: 2
};





//// PUBLIC METHODS

// Get the state stored for the widget with the given ID, or undefined
// if none.
// 
dojo.widget.html.stabile.getState = function(id){
	dojo.widget.html.stabile.setup();
	return dojo.widget.html.stabile.widgetState[id];
}


// Set the state stored for the widget with the given ID.  If isCommit
// is true, commits all widget state to more stable storage.
// 
dojo.widget.html.stabile.setState = function(id, state, isCommit){
	dojo.widget.html.stabile.setup();
	dojo.widget.html.stabile.widgetState[id] = state;
	if(isCommit){
		dojo.widget.html.stabile.commit(dojo.widget.html.stabile.widgetState);
	}
}


// Sets up widgetState: a hash keyed by widgetId, maps to an object
// or array writable with "describe".  If there is data in the widget
// storage area, use it, otherwise initialize an empty object.
// 
dojo.widget.html.stabile.setup = function(){
	if(!dojo.widget.html.stabile.widgetState){
		var text = dojo.widget.html.stabile.getStorage().value;
		dojo.widget.html.stabile.widgetState = text ? dj_eval("("+text+")") : {};
	}
}


// Commits all widget state to more stable storage, so if the user
// navigates away and returns, it can be restored.
// 
dojo.widget.html.stabile.commit = function(state){
	dojo.widget.html.stabile.getStorage().value = dojo.widget.html.stabile.description(state);
}

// Return a JSON "description string" for the given value.
// Supports only core JavaScript types with literals, plus Date,
// and cyclic structures are unsupported.
// showAll defaults to false -- if true, this becomes a simple symbolic
// object dumper, but you cannot "eval" the output.
//
dojo.widget.html.stabile.description = function(v, showAll){
	// Save and later restore dojo.widget.html.stabile._depth;
	var depth = dojo.widget.html.stabile._depth;

	var describeThis = function() {
		 return this.description(this, true);
	} 
	
	try {

		if(v===void(0)){
			return "undefined";
		}
		if(v===null){
			return "null";
		}
		if(typeof(v)=="boolean" || typeof(v)=="number"
		    || v instanceof Boolean || v instanceof Number){
			return v.toString();
		}

		if(typeof(v)=="string" || v instanceof String){
			// Quote strings and their contents as required.
			// Replacing by $& fails in IE 5.0
			var v1 = v.replace(dojo.widget.html.stabile._sqQuotables, "\\$1"); 
			v1 = v1.replace(/\n/g, "\\n");
			v1 = v1.replace(/\r/g, "\\r");
			// Any other important special cases?
			return "'"+v1+"'";
		}

		if(v instanceof Date){
			// Create a data constructor.
			return "new Date("+d.getFullYear+","+d.getMonth()+","+d.getDate()+")";
		}

		var d;
		if(v instanceof Array || v.push){
			// "push" test needed for KHTML/Safari, don't know why -cp

			if(depth>=dojo.widget.html.stabile.depthLimit)
			  return "[ ... ]";

			d = "[";
			var first = true;
			dojo.widget.html.stabile._depth++;
			for(var i=0; i<v.length; i++){
				// Skip functions and undefined values
				// if(v[i]==undef || typeof(v[i])=="function")
				//   continue;
				if(first){
					first = false;
				}else{
					d += ",";
				}
				d+=arguments.callee(v[i], showAll);
			}
			return d+"]";
		}

		if(v.constructor==Object
		    || v.toString==describeThis){
			if(depth>=dojo.widget.html.stabile.depthLimit)
			  return "{ ... }";

			// Instanceof Hash is good, or if we just use Objects,
			// we can say v.constructor==Object.
			// IE (5?) lacks hasOwnProperty, but perhaps objects do not always
			// have prototypes??
			if(typeof(v.hasOwnProperty)!="function" && v.prototype){
				throw new Error("description: "+v+" not supported by script engine");
			}
			var first = true;
			d = "{";
			dojo.widget.html.stabile._depth++;
			for(var key in v){
				// Skip values that are functions or undefined.
				if(v[key]==void(0) || typeof(v[key])=="function")
					continue;
				if(first){
					first = false;
				}else{
					d += ", ";
				}
				var kd = key;
				// If the key is not a legal identifier, use its description.
				// For strings this will quote the stirng.
				if(!kd.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)){
					kd = arguments.callee(key, showAll);
				}
				d += kd+": "+arguments.callee(v[key], showAll);
			}
			return d+"}";
		}

		if(showAll){
			if(dojo.widget.html.stabile._recur){
				// Save the original definitions of toString;
				var objectToString = Object.prototype.toString;
				return objectToString.apply(v, []);
			}else{
				dojo.widget.html.stabile._recur = true;
				return v.toString();
			}
		}else{
			// log("Description? "+v.toString()+", "+typeof(v));
			throw new Error("Unknown type: "+v);
			return "'unknown'";
		}

	} finally {
		// Always restore the global current depth.
		dojo.widget.html.stabile._depth = depth;
	}

}



//// PRIVATE TO MODULE

// Gets an object (form field) with a read/write "value" property.
// 
dojo.widget.html.stabile.getStorage = function(){
	if (dojo.widget.html.stabile.dataField) {
		return dojo.widget.html.stabile.dataField;
	}
	var form = document.forms._dojo_form;
	return dojo.widget.html.stabile.dataField = form ? form.stabile : {value: ""};
}


__CPAN_FILE__ src/widget/html/layout.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.html.layout");

dojo.require("dojo.lang.common");
dojo.require("dojo.string.extras");
dojo.require("dojo.html.style");
dojo.require("dojo.html.layout");

/**
 * Layout a bunch of child dom nodes within a parent dom node
 * Input is an array of objects like:
 * @ container - parent node
 * @ layoutPriority - "top-bottom" or "left-right"
 * @ children an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
 */
dojo.widget.html.layout = function(container, children, layoutPriority) {
	dojo.html.addClass(container, "dojoLayoutContainer");

	// Copy children array and remove elements w/out layout.
	// Also record each child's position in the input array, for sorting purposes.
	children = dojo.lang.filter(children, function(child, idx){
		child.idx = idx;
		return dojo.lang.inArray(["top","bottom","left","right","client","flood"], child.layoutAlign)
	});

	// Order the children according to layoutPriority.
	// Multiple children w/the same layoutPriority will be sorted by their position in the input array.
	if(layoutPriority && layoutPriority!="none"){
		var rank = function(child){
			switch(child.layoutAlign){
				case "flood":
					return 1;
				case "left":
				case "right":
					return (layoutPriority=="left-right") ? 2 : 3;
				case "top":
				case "bottom":
					return (layoutPriority=="left-right") ? 3 : 2;
				default:
					return 4;
			}
		};
		children.sort(function(a,b){
			return (rank(a)-rank(b)) || (a.idx - b.idx);
		});
	}

	// remaining space (blank area where nothing has been written)
	var f={
		top: dojo.html.getPixelValue(container, "padding-top", true),
		left: dojo.html.getPixelValue(container, "padding-left", true)
	};
	dojo.lang.mixin(f, dojo.html.getContentBox(container));

	// set positions/sizes
	dojo.lang.forEach(children, function(child){
		var elm=child.domNode;
		var pos=child.layoutAlign;
		// set elem to upper left corner of unused space; may move it later
		with(elm.style){
			left = f.left+"px";
			top = f.top+"px";
			bottom = "auto";
			right = "auto";
		}
		dojo.html.addClass(elm, "dojoAlign" + dojo.string.capitalize(pos));

		// set size && adjust record of remaining space.
		// note that setting the width of a <div> may affect it's height.
		// TODO: same is true for widgets but need to implement API to support that
		if ( (pos=="top")||(pos=="bottom") ) {
			dojo.html.setMarginBox(elm, { width: f.width });
			var h = dojo.html.getMarginBox(elm).height;
			f.height -= h;
			if(pos=="top"){
				f.top += h;
			}else{
				elm.style.top = f.top + f.height + "px";
			}
		}else if(pos=="left" || pos=="right"){
			var w = dojo.html.getMarginBox(elm).width;
			// width needs to be set for Firefox (#941)
			dojo.html.setMarginBox(elm, { width: w, height: f.height });

			f.width -= w;
			if(pos=="left"){
				f.left += w;
			}else{
				elm.style.left = f.left + f.width + "px";
			}
		} else if(pos=="flood" || pos=="client"){
			dojo.html.setMarginBox(elm, { width: f.width, height: f.height });
		}
		
		// TODO: for widgets I want to call resizeTo(), but for top/bottom
		// alignment I only want to set the width, and have the size determined
		// dynamically.  (The thinner you make a div, the more height it consumes.)
		if(child.onResized){
			child.onResized();
		}
	});
};

// This is essential CSS to make layout work (it isn't "styling" CSS)
// make sure that the position:absolute in dojoAlign* overrides other classes
dojo.html.insertCssText(
	".dojoLayoutContainer{ position: relative; display: block; }\n" +
	"body .dojoAlignTop, body .dojoAlignBottom, body .dojoAlignLeft, body .dojoAlignRight { position: absolute; overflow: hidden; }\n" +
	"body .dojoAlignClient { position: absolute }\n" +
	".dojoAlignClient { overflow: auto; }\n"
);


__CPAN_DIR__ src/widget/Editor2Plugin
__CPAN_FILE__ src/widget/Editor2Plugin/SimpleSignalCommands.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*
 * This plugin adds save() and insertImage() to Editor2 widget, and two commands for each
 * of them. When the corresponding button is clicked in the toolbar, the added function in the
 * Editor2 widget is called. This mimics the original Editor2 behavior. If you want to have other
 * signals on the Editor2 widget, add them to dojo.widget.Editor2Plugin.SimpleSignalCommands.signals
 * NOTE: Please consider writing your own Editor2 plugin rather than using this backward compatible
 * plugin
 * ATTENTION: This plugin overwrites the new built-in insertImage dialog. (If this is not desired, set
 * dojo.widget.Editor2Plugin.SimpleSignalCommands.signals to not contain insertImage)
 */

//uncomment this line to add save only (do not overwrite the new built-in insertImage dialog
//this line should present before require dojo.widget.Editor2Plugin.SimpleSignalCommands
//dojo.widget.Editor2Plugin['SimpleSignalCommands'] = {signals: ['save']};

dojo.provide("dojo.widget.Editor2Plugin.SimpleSignalCommands");

dojo.require("dojo.widget.Editor2");

dojo.declare("dojo.widget.Editor2Plugin.SimpleSignalCommand", dojo.widget.Editor2Command,
	function(name){
		if(dojo.widget.Editor2.prototype[name] == undefined){
			dojo.widget.Editor2.prototype[name] = function(){ dojo.debug("Editor2::"+name); };
		}
	},
{
	execute: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();

		if(curInst){
			curInst[this._name]();
		}
	}
});

if(dojo.widget.Editor2Plugin['SimpleSignalCommands']){
	dojo.widget.Editor2Plugin['_SimpleSignalCommands']=dojo.widget.Editor2Plugin['SimpleSignalCommands'];
}

dojo.widget.Editor2Plugin.SimpleSignalCommands = {
	signals: ['save', 'insertImage'],
	Handler: function(name){
		if(name.toLowerCase() == 'save'){
			return new dojo.widget.Editor2ToolbarButton('Save');
		}else if(name.toLowerCase() == 'insertimage'){
			return new dojo.widget.Editor2ToolbarButton('InsertImage');
		}
	},
	registerAllSignalCommands: function(){
		for(var i=0;i<this.signals.length;i++){
			dojo.widget.Editor2Manager.registerCommand(this.signals[i],
				new dojo.widget.Editor2Plugin.SimpleSignalCommand(this.signals[i]));
		}
	}
};

if(dojo.widget.Editor2Plugin['_SimpleSignalCommands']){
	dojo.lang.mixin(dojo.widget.Editor2Plugin.SimpleSignalCommands, dojo.widget.Editor2Plugin['_SimpleSignalCommands']);
}

dojo.widget.Editor2Plugin.SimpleSignalCommands.registerAllSignalCommands();
dojo.widget.Editor2ToolbarItemManager.registerHandler(dojo.widget.Editor2Plugin.SimpleSignalCommands.Handler);
__CPAN_FILE__ src/widget/Editor2Plugin/FindReplaceDialog.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

ï»¿dojo.provide("dojo.widget.Editor2Plugin.FindReplaceDialog");

dojo.widget.defineWidget(
	"dojo.widget.Editor2FindDialog",
	dojo.widget.Editor2DialogContent,
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/Dialog/find.html"),

	find: function(){
		var findcmd = dojo.widget.Editor2Manager.getCommand('find');
		var option = 0;
	
		if(this["find_option_casesens"].checked){
			option |= findcmd.SearchOption.CaseSensitive;
		}
		if(this["find_option_backwards"].checked){
			option |= findcmd.SearchOption.SearchBackwards;
		}
	
		if(this["find_option_wholeword"].checked){
			option |= findcmd.SearchOption.WholeWord;
		}
		findcmd.find(this["find_text"].value, option);
	}
});

dojo.widget.defineWidget(
	"dojo.widget.Editor2ReplaceDialog",
	dojo.widget.Editor2DialogContent,
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/Dialog/replace.html"),

	replace: function(){
		alert("not implemented yet");
	},
	replaceAll: function(){
		alert("not implemented yet");
	}
});
__CPAN_FILE__ src/widget/Editor2Plugin/InsertImageDialog.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.InsertImageDialog");

dojo.widget.defineWidget(
	"dojo.widget.Editor2InsertImageDialog",
	dojo.widget.Editor2DialogContent,
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/Dialog/insertimage.html"),

	editableAttributes: ['src', 'alt', 'width', 'height', 'hspace', 'vspace', 'border', 'align'],
	loadContent: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		this.imageNode = dojo.withGlobal(curInst.window, "getSelectedElement", dojo.html.selection);
		if(!this.imageNode){
			this.imageNode = dojo.withGlobal(curInst.window, "getAncestorElement", dojo.html.selection, ['img']);
		}
		var imageAttributes = {};
		this.extraAttribText = "";
		if(this.imageNode){
			var attrs = this.imageNode.attributes;
			for(var i=0; i<attrs.length; i++) {
				if(dojo.lang.find(this.editableAttributes, attrs[i].name.toLowerCase())>-1){
					imageAttributes[attrs[i].name] = attrs[i].value;
				}else{
					this.extraAttribText += attrs[i].name + '="'+attrs[i].value+'" ';
				}
			}
		}
		for(var i=0; i<this.editableAttributes.length; ++i){
			name = this.editableAttributes[i];
			this["image_"+name].value = (imageAttributes[name] == undefined) ? "" : imageAttributes[name] ;
		}
		return true;
	},
	ok: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		var insertcmd = dojo.widget.Editor2Manager.getCommand('inserthtml');
		var option = 0;

		var attstr='';
		for(var i=0; i<this.editableAttributes.length; ++i){
			name = this.editableAttributes[i];
			var value = this["image_"+name].value;
			if(value.length > 0){
				attstr += name + '="'+value+'" ';
			}
		}
		if(this.imageNode){
			dojo.withGlobal(curInst.window, "selectElement", dojo.html.selection, [this.imageNode]);
		}
		insertcmd.execute('<img '+attstr+this.extraAttribText+'/>');

		this.cancel();
	}
});
__CPAN_FILE__ src/widget/Editor2Plugin/CreateLinkDialog.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.CreateLinkDialog");

dojo.widget.defineWidget(
	"dojo.widget.Editor2CreateLinkDialog",
	dojo.widget.Editor2DialogContent,
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/Dialog/createlink.html"),

	editableAttributes: ['href', 'target', 'class'],
	loadContent: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();

		curInst.saveSelection(); //save selection (none-activeX IE)

		this.linkNode = dojo.withGlobal(curInst.window, "getAncestorElement", dojo.html.selection, ['a']);
		var linkAttributes = {};
		this.extraAttribText = "";
		if(this.linkNode){
			var attrs = this.linkNode.attributes;
			for(var i=0; i<attrs.length; i++) {
				if(dojo.lang.find(this.editableAttributes, attrs[i].name.toLowerCase())>-1){
					linkAttributes[attrs[i].name] = attrs[i].value;
				}else{
					//IE lists all attributes, even default ones, filter them
					if(attrs[i].specified == undefined || attrs[i].specified){
						this.extraAttribText += attrs[i].name + '="'+attrs[i].value+'" ';
					}
				}
			}
		}else{
			var html = dojo.withGlobal(curInst.window, "getSelectedText", dojo.html.selection);
			if(html == null || html.length == 0){
				alert("Please select some text to create a link.");
				return false;//do not show the dialog
			}
		}

		for(var i=0; i<this.editableAttributes.length; ++i){
			name = this.editableAttributes[i];
			this["link_"+name].value = (linkAttributes[name] == undefined) ? "" : linkAttributes[name] ;
		}
		return true;
	},
	ok: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		curInst.restoreSelection(); //restore previous selection, required for none-activeX IE

		if(!this.linkNode){
			var html = dojo.withGlobal(curInst.window, "getSelectedHtml", dojo.html.selection);
		}else{
			var html = this.linkNode.innerHTML;
			dojo.withGlobal(curInst.window, "selectElement", dojo.html.selection, [this.linkNode]);
		}

		var attstr='';
		for(var i=0; i<this.editableAttributes.length; ++i){
			name = this.editableAttributes[i];
			var value = this["link_"+name].value;
			if(value.length > 0){
				attstr += name + '="'+value+'" ';
			}
		}

		curInst.execCommand('inserthtml', '<a '+attstr+this.extraAttribText+'>'+html+'</a>');

		this.cancel();
	}
});
__CPAN_FILE__ src/widget/Editor2Plugin/TableOperation.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.TableOperation");

dojo.require("dojo.widget.Editor2");

//subscribe to dojo.widget.RichText::init, not onLoad because after onLoad
//the stylesheets for the editing areas are already applied and the prefilters
//are executed, so we have to insert our own trick before that point
dojo.event.topic.subscribe("dojo.widget.RichText::init", function(editor){
	editor.__TableOperationShowBorder = false;

	if(dojo.render.html.ie){
		//add/remove a class to a table with border=0 to show the border when loading/saving
		editor.contentDomPreFilters.push(dojo.widget.Editor2Plugin.TableOperation.showIETableBorder);
		editor.contentDomPostFilters.push(dojo.widget.Editor2Plugin.TableOperation.removeIEFakeClass);
		//include the css file to show table border when border=0
//		editor.__TableOperationShowBorder = true;
//		editor.addStyleSheet(dojo.uri.dojoUri("src/widget/templates/Editor2/showtableborder_ie.css"));
//		editor.editingAreaStyleSheets.push(dojo.uri.dojoUri("src/widget/templates/Editor2/showtableborder_ie.css"));
	}
	dojo.event.connect(editor, "editorOnLoad", function(){
		dojo.widget.Editor2Plugin.TableOperation.toggleTableBorderCommand.execute(editor);
	});
});

dojo.widget.Editor2Plugin.TableOperation = {
	getToolbarItem: function(name){
		var name = name.toLowerCase();

		var item;
		switch(name){
			case 'inserttable':
			case 'toggletableborder':
				item = new dojo.widget.Editor2ToolbarButton(name);
		}

		return item;
	},
	getContextMenuGroup: function(name, contextmenuplugin){
		return new dojo.widget.Editor2Plugin.TableContextMenu(contextmenuplugin);
	},
	deleteTableCommand: {
		execute: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			var table = dojo.withGlobal(curInst.window, "getAncestorElement", dojo.html.selection, ['table']);
			if(table){
				dojo.withGlobal(curInst.window, "selectElement", dojo.html.selection, [table]);
				curInst.execCommand("inserthtml", " "); //Moz does not like an empty string, so a space here instead
			}
		},
		getState: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			var table = dojo.withGlobal(curInst.window, "hasAncestorElement", dojo.html.selection, ['table']);
			return table ? dojo.widget.Editor2Manager.commandState.Enabled : dojo.widget.Editor2Manager.commandState.Disabled;
		},
		destory: function(){}
	},
	toggleTableBorderCommand: {
		execute: function(instance){
			var curInst = instance || dojo.widget.Editor2Manager.getCurrentInstance();
			if(curInst.__TableOperationShowBorder){
				curInst.__TableOperationShowBorder = false;
				if(dojo.render.html.moz){
					curInst.removeStyleSheet(dojo.uri.dojoUri("src/widget/templates/Editor2/showtableborder_gecko.css"));
				}else if(dojo.render.html.ie){
					curInst.removeStyleSheet(dojo.uri.dojoUri("src/widget/templates/Editor2/showtableborder_ie.css"));
				}
			}else{
				curInst.__TableOperationShowBorder = true;
				if(dojo.render.html.moz){
					curInst.addStyleSheet(dojo.uri.dojoUri("src/widget/templates/Editor2/showtableborder_gecko.css"));
				}else if(dojo.render.html.ie){
					curInst.addStyleSheet(dojo.uri.dojoUri("src/widget/templates/Editor2/showtableborder_ie.css"));
				}
			}
		},
		getState: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			return curInst.__TableOperationShowBorder ? dojo.widget.Editor2Manager.commandState.Latched : dojo.widget.Editor2Manager.commandState.Enabled;
		},
		destory: function(){}
	},
	showIETableBorder: function(dom){
		var tables = dom.getElementsByTagName('table');
		dojo.lang.forEach(tables, function(t){
			dojo.html.addClass(t, "dojoShowIETableBorders");
		});
		return dom;
	},
	removeIEFakeClass: function(dom){
		var tables = dom.getElementsByTagName('table');
		dojo.lang.forEach(tables, function(t){
			dojo.html.removeClass(t, "dojoShowIETableBorders");
		});
		return dom;
	}
}

//register commands: toggletableborder, inserttable, deletetable
dojo.widget.Editor2Manager.registerCommand("toggletableborder", dojo.widget.Editor2Plugin.TableOperation.toggleTableBorderCommand);

dojo.widget.Editor2Manager.registerCommand("inserttable", new dojo.widget.Editor2DialogCommand('inserttable',
		{contentFile: "dojo.widget.Editor2Plugin.InsertTableDialog",
			contentClass: "Editor2InsertTableDialog",
			title: "Insert/Edit Table", width: "450px", height: "250px"}));

dojo.widget.Editor2Manager.registerCommand("deletetable", dojo.widget.Editor2Plugin.TableOperation.deleteTableCommand);

//register toggletableborder and inserttable as toolbar item
dojo.widget.Editor2ToolbarItemManager.registerHandler(dojo.widget.Editor2Plugin.TableOperation.getToolbarItem);

//add context menu support if dojo.widget.Editor2Plugin.ContextMenu is included before this plugin
if(dojo.widget.Editor2Plugin.ContextMenuManager){
	dojo.widget.Editor2Plugin.ContextMenuManager.registerGroup('Table', dojo.widget.Editor2Plugin.TableOperation.getContextMenuGroup);

	dojo.declare("dojo.widget.Editor2Plugin.TableContextMenu",
		dojo.widget.Editor2Plugin.SimpleContextMenu,
	{
		createItems: function(){
			this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Delete Table", command: 'deletetable'}));
			this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Table Property", command: 'inserttable', iconClass: "TB_Button_Icon TB_Button_Table"}));
		},
		checkVisibility: function(){
			var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
			var table = dojo.withGlobal(curInst.window, "hasAncestorElement", dojo.html.selection, ['table']);

			if(dojo.withGlobal(curInst.window, "hasAncestorElement", dojo.html.selection, ['table'])){
				this.items[0].show();
				this.items[1].show();
				return true;
			}else{
				this.items[0].hide();
				this.items[1].hide();
				return false;
			}
		}
	});
}
__CPAN_FILE__ src/widget/Editor2Plugin/FindReplace.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.FindReplace");

dojo.require("dojo.widget.Editor2");

//TODO replace, better GUI

dojo.declare("dojo.widget.Editor2Plugin.FindCommand", dojo.widget.Editor2DialogCommand,{
	SearchOption: {
		CaseSensitive: 4,
		SearchBackwards: 64,
		WholeWord: 2,
		WrapSearch: 128
	},
	find: function(text, option){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		if(curInst){
			curInst.focus();
			if(window.find){ //moz
				curInst.window.find(text, 
					option & this.SearchOption.CaseSensitive ? true : false,
					option & this.SearchOption.SearchBackwards ? true : false,
					option & this.SearchOption.WrapSearch ? true : false,
					option & this.SearchOption.WholeWord ? true : false
					);
			}else if(dojo.body().createTextRange){ //IE
				var range = curInst.document.body.createTextRange();
				var found = range.findText(text, (option&this.SearchOption.SearchBackwards)?1:-1, option );
				if(found){
					range.scrollIntoView() ;
					range.select() ;
				}else{
					alert("Can not find "+text+" in the document");
				}
			}else{
				alert("No idea how to search in this browser. Please submit patch if you know.");
			}
		}
	}
});

dojo.widget.Editor2Manager.registerCommand("Find", new dojo.widget.Editor2Plugin.FindCommand('find', 
		{contentFile: "dojo.widget.Editor2Plugin.FindReplaceDialog", 
			contentClass: "Editor2FindDialog",
			title: "Find", width: "350px", height: "150px", modal: false}));
dojo.widget.Editor2Manager.registerCommand("Replace", new dojo.widget.Editor2DialogCommand('replace', 
		{contentFile: "dojo.widget.Editor2Plugin.FindReplaceDialog", 
			contentClass: "Editor2ReplaceDialog",
			href: dojo.uri.dojoUri("src/widget/templates/Editor2/Dialog/replace.html"), 
			title: "Replace", width: "350px", height: "200px", modal: false}));

dojo.widget.Editor2Plugin.FindReplace = function(name){
	var name = name.toLowerCase();

	var item;
	if(name == 'replace'){
		item = new dojo.widget.Editor2ToolbarButton('Replace');
	}else if(name == 'find') {
		item = new dojo.widget.Editor2ToolbarButton('Find');
	}

	return item;
}

dojo.widget.Editor2ToolbarItemManager.registerHandler(dojo.widget.Editor2Plugin.FindReplace);
__CPAN_FILE__ src/widget/Editor2Plugin/InsertTableDialog.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.InsertTableDialog");

dojo.widget.defineWidget(
	"dojo.widget.Editor2InsertTableDialog",
	dojo.widget.Editor2DialogContent,
{
	templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/Dialog/inserttable.html"),

	editableAttributes: ['summery', 'height', 'cellspacing', 'cellpadding', 'border', 'align'],

	loadContent: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		this.tableNode = dojo.withGlobal(curInst.window, "getSelectedElement", dojo.html.selection);
		if(!this.tableNode || this.tableNode.tagName.toLowerCase() != 'table'){
			this.tableNode = dojo.withGlobal(curInst.window, "getAncestorElement", dojo.html.selection, ['table']);
		}

		var tableAttributes = {};
		this.extraAttribText = "";
		if(this.tableNode){
			this["table_rows"].value = this.tableNode.rows.length;
			this["table_rows"].disabled = true;
			this["table_cols"].value = this.tableNode.rows[0].cells.length;
			this["table_cols"].disabled = true;

			if (this.tableNode.caption){
				this["table_caption"].value = this.tableNode.caption.innerHTML;
			}else{
				this["table_caption"].value = "";
			}

			var width = this.tableNode.style.width || this.tableNode.width;
			if(width){
				this["table_width"].value = parseInt(width);
				if (width.indexOf('%') > -1){
					this["table_widthtype"].value = "percent";
				}else{
					this["table_widthtype"].value = "pixels";
				}
			}else{
				this["table_width"].value = "100";
			}

			var height = this.tableNode.style.height || this.tableNode.height;
			if(height){
				this["table_height"].value = parseInt(width);
			}else{
				this["table_height"].value = "";
			}

			var attrs = this.tableNode.attributes;
			for(var i=0; i<attrs.length; i++) {
				if(dojo.lang.find(this.editableAttributes, attrs[i].name.toLowerCase())>-1){
					tableAttributes[attrs[i].name] = attrs[i].value;
				}else{
					this.extraAttribText += attrs[i].name + '="'+attrs[i].value+'" ';
				}
			}
		}else{
			this["table_rows"].value = 3;
			this["table_rows"].disabled = false;
			this["table_cols"].value = 2;
			this["table_cols"].disabled = false;
			this["table_width"].value = 100;
			this["table_widthtype"].value = "percent";
			this["table_height"].value = "";
		}

		for(var i=0; i<this.editableAttributes.length; ++i){
			name = this.editableAttributes[i];
			this["table_"+name].value = (tableAttributes[name] == undefined) ? "" : tableAttributes[name];
			if(name == 'height' && tableAttributes[name] != undefined){
				this["table_"+name].value = tableAttributes[name];
			}
		}
		return true;
	},
	ok: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		var args = {};

		args['rows'] = this["table_rows"].value;
		args['cols'] = this["table_cols"].value;
		args['caption'] = this["table_caption"].value;
		args["tableattrs"] = "";
		if(this["table_widthtype"].value == "percent"){
			args["tableattrs"] += 'width="'+this["table_width"].value +'%" ';
		}else{
			args["tableattrs"] += 'width="'+this["table_width"].value +'px" ';
		}
		for(var i=0; i<this.editableAttributes.length; ++i){
			var name = this.editableAttributes[i];
			var value = this["table_"+name].value;
			if(value.length > 0){
				args["tableattrs"] += name + '="'+value+'" ';
			}
		}

		if(!args["tableattrs"]){
			args["tableattrs"] = "";
		}

		//show the border in IE by applying a custom class
		if(dojo.render.html.ie && !this["table_border"].value){
			args["tableattrs"] += 'class="dojoShowIETableBorders" ';
		}

		var html = "<table "+args["tableattrs"]+">";
		if(args['caption']){
			html += "<caption>"+args["caption"]+"</caption>";
		}
		var outertbody = "<tbody>";
		if(this.tableNode){
			//retain the content
			var tbody = this.tableNode.getElementsByTagName("tbody")[0];
			outertbody = tbody.outerHTML;
			if(!outertbody){
				var cnode = tbody.cloneNode(true);
				var tmpnode = tbody.ownerDocument.createElement("div");
				tmpnode.appendChild(cnode);
				outertbody = tmpnode.innerHTML;
			}
			//TODO: save current selection and restore it later
			dojo.withGlobal(curInst.window, "selectElement", dojo.html.selection, [this.tableNode]);
		}else{
			var cols = "<tr>";
			for (var i = 0; i < +args.cols; i++) { cols += "<td></td>"; }
			cols += "</tr>";
			for (var i = 0; i < args.rows; i++) { outertbody += cols; }
			outertbody += "</tbody>";
		}
		html += outertbody+"</table>";
		curInst.execCommand("inserthtml", html);

		this.cancel();
	}
});
__CPAN_FILE__ src/widget/Editor2Plugin/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [ "dojo.widget.Editor2", 
			 "dojo.widget.Editor2Toolbar"]
});
dojo.provide("dojo.widget.Editor2Plugin.*");

__CPAN_FILE__ src/widget/Editor2Plugin/ContextMenu.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.ContextMenu");

//ContextMenu plugin should be dojo.required-ed before all other plugins which
//support contextmenu, otherwise the menu for that plugin won't be shown

dojo.require("dojo.widget.Menu2");

dojo.event.topic.subscribe("dojo.widget.Editor2::onLoad", function(editor){
	var p = new dojo.widget.Editor2Plugin.ContextMenu(editor);
});
dojo.widget.Editor2Plugin.ContextMenuManager = {
	menuGroups: ['Generic', 'Link', 'Anchor', 'Image', 'List', 'Table'],
	_registeredGroups: {},
	registerGroup: function(name, handler){
		if(this._registeredGroups[name]){
			alert("dojo.widget.Editor2Plugin.ContextMenuManager.registerGroup: menu group "+name+"is already registered. Ignored.");
			return;
		}
		this._registeredGroups[name] = handler;
	},
	removeGroup: function(name){
		delete this._registeredGroups[name];
	},
	getGroup: function(name, contextmenuplugin){
		if(this._registeredGroups[name]){
			var item = this._registeredGroups[name](name, contextmenuplugin);
			if(item){
				return item;
			}
		}
		switch(name){
			case 'Generic':
			case 'Link':
			case 'Image':
				return new dojo.widget.Editor2Plugin[name+"ContextMenu"](contextmenuplugin);
			//TODO
			case 'Anchor':
			case 'List':
		}
	}
};

dojo.declare("dojo.widget.Editor2Plugin.ContextMenu", null,
	function(editor){
		this.groups = [];
		this.separators = [];
		this.editor = editor;
		this.editor.registerLoadedPlugin(this);
		this.contextMenu = dojo.widget.createWidget("PopupMenu2", {});
		dojo.body().appendChild(this.contextMenu.domNode);
		this.contextMenu.bindDomNode(this.editor.document.body);

		dojo.event.connect(this.contextMenu, "aboutToShow", this, "aboutToShow");
		dojo.event.connect(this.editor, "destroy", this, "destroy");

		this.setup();
	},
	{
	setup: function(){
		var gs = dojo.widget.Editor2Plugin.ContextMenuManager.menuGroups;
		for(var i in gs){
			var g = dojo.widget.Editor2Plugin.ContextMenuManager.getGroup(gs[i], this);
			if(g){
				this.groups.push(g);
			}
		}
	},
	aboutToShow: function(){
		var first = true;
		for(var i in this.groups){
			if(i>0 && this.separators.length != this.groups.length-1){
				this.separators.push(dojo.widget.createWidget("MenuSeparator2", {}));
				this.contextMenu.addChild(this.separators[this.separators.length-1]);
			}
			if(this.groups[i].refresh()){
				if(i>0){
					if(first){
						this.separators[i-1].hide();
					}else{
						this.separators[i-1].show();
					}
				}
				if(first){ first = false; }
			}else{
				if(i>0){
					this.separators[i-1].hide();
				}
			}
		}
	},
	destroy: function(){
		this.editor.unregisterLoadedPlugin(this);
		delete this.groups;
		delete this.separators;
		this.contextMenu.destroy();
		delete this.contextMenu;
	}
});

dojo.widget.defineWidget(
	"dojo.widget.Editor2ContextMenuItem",
	dojo.widget.MenuItem2, {
	command: null,
	postCreate: function(){
		if(!this.command){
			this.command = this.caption;
		}

		dojo.widget.Editor2ContextMenuItem.superclass.postCreate.apply(this, arguments);
	},
	setup: function(){
		this.cmd = dojo.widget.Editor2Manager.getCommand(this.command);
		if(!this.cmd){
			alert("command " + this.command + " is not recognized!");
		}
	},
	onClick: function(){
		if(!this.cmd){
			this.setup();
		}
		if(this.cmd){
			this.cmd.execute();
		}
	},
	refresh: function(){
		if(!this.cmd){
			this.setup();
		}
		if(this.cmd){
			if(this.cmd.getState() == dojo.widget.Editor2Manager.commandState.Disabled){
				this.disable();
				return false;
			}else{
				this.enable();
				return true;
			}
		}
	},
	//improve performance by skipping animation
	hide: function(){
		this.domNode.style.display = "none";
	},
	show: function(){
		this.domNode.style.display = "";
	}
});
dojo.declare("dojo.widget.Editor2Plugin.SimpleContextMenu", null,
	function(contextmenuplugin){
		this.contextMenu = contextmenuplugin.contextMenu;
		this.items = [];

		dojo.event.connect(contextmenuplugin, "destroy", this, "destroy");
	},
	{
	refresh: function(){
		if(!this.items.length){
			this.createItems();
			for(var i in this.items){
				this.contextMenu.addChild(this.items[i]);
			}
		}

		return this.checkVisibility();
	},
	destroy: function(){
		this.contextmenu = null;
		delete this.items;
		delete this.contextMenu;
	},
	//implement this to fill in the menu items
	createItems: function(){	},

	//overload this to show/hide items
	checkVisibility: function(){
		var show = false;
		for(var i in this.items){
			show = show || this.items[i].refresh();
		}
		var action = show ? "show" : "hide";
		for(var i in this.items){
			this.items[i][action]();
		}
		return show;
	}
});
dojo.declare("dojo.widget.Editor2Plugin.GenericContextMenu",
	dojo.widget.Editor2Plugin.SimpleContextMenu,
{
	createItems: function(){
		this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Cut", iconClass: "dojoE2TBIcon dojoE2TBIcon_Cut"}));
		this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Copy", iconClass: "dojoE2TBIcon dojoE2TBIcon_Copy"}));
		this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Paste", iconClass: "dojoE2TBIcon dojoE2TBIcon_Paste"}));
	}
});
dojo.declare("dojo.widget.Editor2Plugin.LinkContextMenu",
	dojo.widget.Editor2Plugin.SimpleContextMenu,
{
	createItems: function(){
		this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Modify Link", command: 'createlink', iconClass: "dojoE2TBIcon dojoE2TBIcon_Link"}));
		this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Remove Link", command: 'unlink', iconClass: "dojoE2TBIcon dojoE2TBIcon_UnLink"}));
	},
	checkVisibility: function(){
		var show = this.items[1].refresh();
		if(show){
			this.items[0].refresh();
			for(var i in this.items){
				this.items[i].show();
			}
		}else{
			for(var i in this.items){
				this.items[i].hide();
			}
		}

		return show;
	}
});
dojo.declare("dojo.widget.Editor2Plugin.ImageContextMenu",
	dojo.widget.Editor2Plugin.SimpleContextMenu,
{
	createItems: function(){
		this.items.push(dojo.widget.createWidget("Editor2ContextMenuItem", {caption: "Edit Image", command: 'insertimage', iconClass: "dojoE2TBIcon dojoE2TBIcon_Image"}));
	},
	checkVisibility: function(){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		var img = dojo.withGlobal(curInst.window, "getSelectedElement", dojo.html.selection);

		if(img && img.tagName.toLowerCase() == 'img'){
			this.items[0].show();
			return true;
		}else{
			this.items[0].hide();
			return false;
		}
	}
});
__CPAN_FILE__ src/widget/Editor2Plugin/ToolbarDndSupport.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*TODO:
 * Add a command to toggle DnD support for a toolbar
 * Save/restore order of toolbar/item
 */
dojo.provide("dojo.widget.Editor2Plugin.ToolbarDndSupport");
dojo.require("dojo.dnd.*");

dojo.event.topic.subscribe("dojo.widget.Editor2::preLoadingToolbar", function(editor){
	dojo.dnd.dragManager.nestedTargets = true;
	var p = new dojo.widget.Editor2Plugin.ToolbarDndSupport(editor);
});

dojo.declare("dojo.widget.Editor2Plugin.ToolbarDndSupport", null,{
	lookForClass: "dojoEditorToolbarDnd TB_ToolbarSet TB_Toolbar",
	initializer: function(editor){
		this.editor = editor;
		dojo.event.connect(this.editor, "toolbarLoaded", this, "setup");
		this.editor.registerLoadedPlugin(this);
	},

	setup: function(){
		dojo.event.disconnect(this.editor, "toolbarLoaded", this, "setup");
		var tbw = this.editor.toolbarWidget;
		dojo.event.connect("before", tbw, "destroy", this, "destroy");

		var nodes = dojo.html.getElementsByClass(this.lookForClass, tbw.domNode, null, dojo.html.classMatchType.ContainsAny);
		if(!nodes){
			dojo.debug("dojo.widget.Editor2Plugin.ToolbarDndSupport: No dom node with class in "+this.lookForClass);
			return;
		}
		for(var i=0; i<nodes.length; i++){
			var node = nodes[i];
			var droptarget = node.getAttribute("dojoETDropTarget");
			if(droptarget){
				(new dojo.dnd.HtmlDropTarget(node, [droptarget+tbw.widgetId])).vertical = true;
			}
			var dragsource = node.getAttribute("dojoETDragSource");
			if(dragsource){
				new dojo.dnd.HtmlDragSource(node, dragsource+tbw.widgetId);
			}
		}
	},

	destroy: function(){
		this.editor.unregisterLoadedPlugin(this);
	}
});

//let's have a command to enable DnD
/*dojo.declare("dojo.widget.Editor2Plugin.ToolbarDndCommand", dojo.widget.Editor2Command,{
	execute: function(text, option){
		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
		if(curInst){
		}
	},
	getState: function(){	
	}
});*/
__CPAN_FILE__ src/widget/Editor2Plugin/AlwaysShowToolbar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Editor2Plugin.AlwaysShowToolbar");

//dojo.widget.Editor2Manager.registerPerInstancePlugin("dojo.widget.Editor2Plugin.AlwaysShowToolbar");

dojo.event.topic.subscribe("dojo.widget.Editor2::onLoad", function(editor){
	if(editor.toolbarAlwaysVisible){
		var p = new dojo.widget.Editor2Plugin.AlwaysShowToolbar(editor);
	}
});
dojo.declare("dojo.widget.Editor2Plugin.AlwaysShowToolbar", null,
	function(editor){
		this.editor = editor;
		this.editor.registerLoadedPlugin(this);
		this.setup();
	},
	{
	_scrollSetUp: false,
	_fixEnabled: false,
	_scrollThreshold: false,
	_handleScroll: true,

	setup: function(){
		var tdn = this.editor.toolbarWidget;
		if(!tdn.tbBgIframe){
			tdn.tbBgIframe = new dojo.html.BackgroundIframe(tdn.domNode);
			tdn.tbBgIframe.onResized();
		}
		this.scrollInterval = setInterval(dojo.lang.hitch(this, "globalOnScrollHandler"), 100);

		dojo.event.connect("before", this.editor.toolbarWidget, "destroy", this, "destroy");
	},

	globalOnScrollHandler: function(){
		var isIE = dojo.render.html.ie;
		if(!this._handleScroll){ return; }
		var dh = dojo.html;
		var tdn = this.editor.toolbarWidget.domNode;
		var db = dojo.body();

		if(!this._scrollSetUp){
			this._scrollSetUp = true;
			var editorWidth =  dh.getMarginBox(this.editor.domNode).width; 
			this._scrollThreshold = dh.abs(tdn, true).y;
			// dojo.debug("threshold:", this._scrollThreshold);
			if((isIE)&&(db)&&(dh.getStyle(db, "background-image")=="none")){
				with(db.style){
					backgroundImage = "url(" + dojo.uri.dojoUri("src/widget/templates/images/blank.gif") + ")";
					backgroundAttachment = "fixed";
				}
			}
		}

		var scrollPos = (window["pageYOffset"]) ? window["pageYOffset"] : (document["documentElement"]||document["body"]).scrollTop;

		// FIXME: need to have top and bottom thresholds so toolbar doesn't keep scrolling past the bottom
		if(scrollPos > this._scrollThreshold){
			// dojo.debug(scrollPos);
			if(!this._fixEnabled){
				var tdnbox = dojo.html.getMarginBox(tdn);
				this.editor.editorObject.style.marginTop = tdnbox.height+"px";

				if(isIE){
					// FIXME: should we just use setBehvior() here instead?
					tdn.style.left = dojo.html.abs(tdn, dojo.html.boxSizing.MARGIN_BOX).x;
					dojo.body().appendChild(tdn);

					dojo.html.addClass(tdn, "IEFixedToolbar");
				}else{
					with(tdn.style){
						position = "fixed";
						top = "0px";
					}
				}

				tdn.style.width = tdnbox.width + "px";
				tdn.style.zIndex = 1000;
				this._fixEnabled = true;
			}
			// if we're showing the floating toolbar, make sure that if
			// we've scrolled past the bottom of the editor that we hide
			// the toolbar for this instance of the editor.

			// TODO: when we get multiple editor toolbar support working
			// correctly, ensure that we check this against the scroll
			// position of the bottom-most editor instance.
			if(!dojo.render.html.safari){
				// safari reports a bunch of things incorrectly here
				var eHeight = (this.height) ? parseInt(this.editor.height) : this.editor._lastHeight;
				if(scrollPos > (this._scrollThreshold+eHeight)){
					tdn.style.display = "none";
				}else{
					tdn.style.display = "";
				}
			}
		}else if(this._fixEnabled){
			(this.editor.object || this.editor.iframe).style.marginTop = null;
			with(tdn.style){
				position = "";
				top = "";
				zIndex = "";
				display = "";
			}
			if(isIE){
				tdn.style.left = "";
				dojo.html.removeClass(tdn, "IEFixedToolbar");
				dojo.html.insertBefore(tdn, this.editor.object||this.editor.iframe);
			}
			tdn.style.width = "";
			this._fixEnabled = false;
		}
	},

	destroy: function(){
		this._handleScroll = false;
		clearInterval(this.scrollInterval);
		this.editor.unregisterLoadedPlugin(this);

		if(dojo.render.html.ie){
			dojo.html.removeClass(this.editor.toolbarWidget.domNode, "IEFixedToolbar");
		}
	}
});
__CPAN_DIR__ src/widget/nls
__CPAN_FILE__ src/widget/nls/DropdownDatePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
		selectDate: "Select a date"
})

__CPAN_FILE__ src/widget/nls/validate.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
		invalidMessage: "* The value entered is not valid.",
		missingMessage: "* This value is required.",
		rangeMessage: "* This value is out of range."
})

__CPAN_FILE__ src/widget/nls/DropdownTimePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
		selectTime: "Select time"
})

__CPAN_FILE__ src/widget/nls/TimePicker.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
		any: "any"
})

__CPAN_DIR__ src/widget/nls/ja
__CPAN_FILE__ src/widget/nls/ja/validate.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
		invalidMessage: "* å…¥åŠ›ã�—ã�Ÿãƒ‡ãƒ¼ã‚¿ã�«è©²å½“ã�™ã‚‹ã‚‚ã�®ã�Œã�‚ã‚Šã�¾ã�›ã‚“ã€‚",
		missingMessage: "* å…¥åŠ›ã�Œå¿…é ˆã�§ã�™ã€‚",
		rangeMessage: "* å…¥åŠ›ã�—ã�Ÿæ•°å€¤ã�¯é�¸æŠžç¯„å›²å¤–ã�§ã�™ã€‚"
})

__CPAN_DIR__ src/widget/nls/zh-cn
__CPAN_FILE__ src/widget/nls/zh-cn/validate.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

ï»¿({
		invalidMessage: "* é�žæ³•çš„è¾“å…¥å€¼ã€‚",
		missingMessage: "* æ­¤å€¼æ˜¯å¿…é¡»çš„ã€‚",
		rangeMessage: "* è¾“å…¥æ•°æ�®è¶…å‡ºå€¼åŸŸã€‚"
})

__CPAN_DIR__ src/widget/nls/fr
__CPAN_FILE__ src/widget/nls/fr/validate.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
		invalidMessage: "* La valeur saisie est incorrecte.",
		missingMessage: "* Cette valeur est obligatoire.",
		rangeMessage: "* Cette valeur est hors limites."
})

__CPAN_DIR__ src/widget/demoEngine
__CPAN_FILE__ src/widget/demoEngine/DemoNavigator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.demoEngine.DemoNavigator");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.Button");
dojo.require("dojo.widget.demoEngine.DemoItem");
dojo.require("dojo.io.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.lang.common");

dojo.widget.defineWidget("my.widget.demoEngine.DemoNavigator", 
	dojo.widget.HtmlWidget, 
	{
		templatePath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoNavigator.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoNavigator.css"),
		postCreate: function() {
			dojo.html.addClass(this.domNode,this.domNodeClass);
			dojo.html.addClass(this.demoListWrapperNode,this.demoListWrapperClass);
			dojo.html.addClass(this.demoListContainerNode,this.demoListContainerClass);

			if (dojo.render.html.ie) {
				dojo.debug("render ie");
				dojo.html.hide(this.demoListWrapperNode); 
			} else {
				dojo.debug("render non-ie");
				dojo.lfx.html.fadeHide(this.demoListWrapperNode, 0).play();	
			}

			this.getRegistry(this.demoRegistryUrl);

			this.demoContainer = dojo.widget.createWidget("DemoContainer",{returnImage: this.returnImage},this.demoNode);
			dojo.event.connect(this.demoContainer,"returnToDemos", this, "returnToDemos");
			this.demoContainer.hide();
		},

		returnToDemos: function() {
			this.demoContainer.hide();
			if (dojo.render.html.ie) {
				dojo.debug("render ie");
				dojo.html.show(this.navigationContainer) ;
			} else {	
				dojo.debug("render non-ie");
				dojo.lfx.html.fadeShow(this.navigationContainer,250).play();
			}

			//if (dojo.render.html.ie) {
			//	dojo.html.setOpacity(this.navigationContainer);
			//}

			dojo.lang.forEach(this.categoriesChildren, dojo.lang.hitch(this, function(child){
				child.checkSize();
			}));

			dojo.lang.forEach(this.demoListChildren, dojo.lang.hitch(this, function(child){
				child.checkSize();
			}));
		},

		show: function() {
			//dojo.widget.demoEngine.DemoNavigator.superclass.show.call(this);
			dojo.html.show(this.domNode);
			dojo.html.setOpacity(this.domNode,1);
			//dojo.html.setOpacity(this.navigationContainer);	
			//dojo.html.show(this.navigationContainer);
			dojo.html.setOpacity(this.navigationContainer,1);

			dojo.lang.forEach(this.categoriesChildren, dojo.lang.hitch(this, function(child){
				child.checkSize();
			}));

			dojo.lang.forEach(this.demoListChildren, dojo.lang.hitch(this, function(child){
				child.checkSize();
			}));
		},
		getRegistry: function(url) {
			dojo.io.bind({
				url: url,
				load: dojo.lang.hitch(this,this.processRegistry),
				mimetype: "text/json"
			});
		},

		processRegistry: function(type,registry,e) {
			dojo.debug("Processing Registry");
			this.registry = registry;
			dojo.lang.forEach(this.registry.navigation, dojo.lang.hitch(this,this.addCategory)); 
		},

		addCategory: function(category) {
				var newCat = dojo.widget.createWidget("Button",{caption: category.name});

				if(!dojo.lang.isObject(this.registry.categories)) {
					this.registry.categories=function(){};
				}

				this.registry.categories[category.name] = category;
				this.categoriesChildren.push(newCat);
				this.categoriesButtonsNode.appendChild(newCat.domNode);	
				newCat.domNode.categoryName = category.name;
				dojo.event.connect(newCat,"onClick", this, "onSelectCategory");
		},

		addDemo: function(demoName) {
			var demo = this.registry.definitions[demoName];

			if (dojo.render.html.ie) {
				dojo.html.show(this.demoListWrapperNode) 
			} else {
				dojo.lfx.html.fadeShow(this.demoListWrapperNode, 250).play();
			}

			var newDemo = dojo.widget.createWidget("DemoItem",{viewDemoImage: this.viewDemoImage, name: demoName, description: demo.description, thumbnail: demo.thumbnail});
			this.demoListChildren.push(newDemo);
			this.demoListContainerNode.appendChild(newDemo.domNode);	
			dojo.event.connect(newDemo,"onSelectDemo",this,"onSelectDemo");
		},

		onSelectCategory: function(e) {
			catName = e.currentTarget.categoryName;	
			dojo.debug("Selected Category: " + catName);
			//Remove current list of demos
			dojo.lang.forEach(this.demoListChildren, function(child) {
					child.destroy();
			});
			this.demoListChildren=[];

			//add demos from this cat
			dojo.lang.forEach(this.registry.categories[catName].demos, dojo.lang.hitch(this,function(demoName){
				this.addDemo(demoName);
			}));
		},

		onSelectDemo: function(e) {
			//Attach to this to do something when a demo is selected
			dojo.debug("Demo Selected: " + e.target.name);

			if (dojo.render.html.ie) {
				dojo.debug("render ie");
				dojo.html.hide(this.navigationContainer) ;
				this.demoContainer.show();
				this.demoContainer.showDemo();
			} else {
				dojo.debug("render non-ie");
				dojo.lfx.html.fadeHide(this.navigationContainer,250,null,dojo.lang.hitch(this, function() {
					this.demoContainer.show();	
					this.demoContainer.showDemo();
				})).play();
			}

			this.demoContainer.loadDemo(this.registry.definitions[e.target.name].url);
			this.demoContainer.setName(e.target.name);
			this.demoContainer.setSummary(this.registry.definitions[e.target.name].description);
		}
		
	},
	"",
	function() {
		this.demoRegistryUrl="demoRegistry.json";
		this.registry=function(){};

		this.categoriesNode="";
		this.categoriesButtonsNode="";
		this.navigationContainer="";

		this.domNodeClass="demoNavigator";

		this.demoNode="";
		this.demoContainer="";

		this.demoListWrapperNode="";
		this.demoListWrapperClass="demoNavigatorListWrapper";
		this.demoListContainerClass="demoNavigatorListContainer";

		this.returnImage="images/dojoDemos.gif";
		this.viewDemoImage="images/viewDemo.png";
		this.demoListChildren = [];
		this.categoriesChildren = [];
	}
);

__CPAN_FILE__ src/widget/demoEngine/DemoContainer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.demoEngine.DemoContainer");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.demoEngine.DemoPane");
dojo.require("dojo.widget.demoEngine.SourcePane");
dojo.require("dojo.widget.TabContainer");

dojo.widget.defineWidget("my.widget.demoEngine.DemoContainer", 
	dojo.widget.HtmlWidget, 
	{
		templatePath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoContainer.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoContainer.css"),
		postCreate: function() {
			dojo.html.addClass(this.domNode,this.domNodeClass);
			dojo.html.addClass(this.tabNode, this.tabClass);
			dojo.html.addClass(this.returnImageNode, this.returnClass);
			this.returnImageNode.src=this.returnImage;

			this.tabContainer = dojo.widget.createWidget("TabContainer",{},this.tabNode);

			this.demoTab = dojo.widget.createWidget("DemoPane",{});
			this.tabContainer.addChild(this.demoTab);

			this.sourceTab= dojo.widget.createWidget("SourcePane",{});
			this.tabContainer.addChild(this.sourceTab);

			dojo.html.setOpacity(this.domNode,0);
			dojo.html.hide(this.domNode);
		},

		loadDemo: function(url) {
			this.demoTab.setHref(url);
			this.sourceTab.setHref(url);
			this.showDemo();
		},

		setName: function(name) {
			dojo.html.removeChildren(this.demoNameNode);
			this.demoNameNode.appendChild(document.createTextNode(name));
		},

		setSummary: function(summary) {
			dojo.html.removeChildren(this.summaryNode);
			this.summaryNode.appendChild(document.createTextNode(summary));
		},

		showSource: function() {
			dojo.html.removeClass(this.demoButtonNode,this.selectedButtonClass);
			dojo.html.addClass(this.sourceButtonNode,this.selectedButtonClass);
			this.tabContainer.selectTab(this.sourceTab);	
		},

		showDemo: function() {
			dojo.html.removeClass(this.sourceButtonNode,this.selectedButtonClass);
			dojo.html.addClass(this.demoButtonNode,this.selectedButtonClass);
			this.tabContainer.selectTab(this.demoTab);
		},

		returnToDemos: function() {
			dojo.debug("Return To Demos");
		},

		show: function() {
			dojo.html.setOpacity(this.domNode,1);
			dojo.html.show(this.domNode);
			this.tabContainer.checkSize();
		}
	},
	"",
	function() {
		dojo.debug("DemoPane Init");
		this.domNodeClass="demoContainer";

		this.tabContainer="";
		this.sourceTab="";
		this.demoTab="";

		this.headerNode="";
		this.returnNode="";
	
		this.returnImageNode="";
		this.returnImage="images/dojoDemos.gif";
		this.returnClass="return";
		
		this.summaryNode="";
		this.demoNameNode="";
		this.tabControlNode="";

		this.tabNode="";
		this.tabClass = "demoContainerTabs";

		this.sourceButtonNode="";
		this.demoButtonNode="";

		this.selectedButtonClass="selected";
	}
);

__CPAN_FILE__ src/widget/demoEngine/DemoItem.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.demoEngine.DemoItem");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("my.widget.demoEngine.DemoItem", 
	dojo.widget.HtmlWidget, 
	{
		templatePath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoItem.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoItem.css"),
		postCreate: function() {
			dojo.html.addClass(this.domNode,this.domNodeClass);
			dojo.html.addClass(this.summaryBoxNode, this.summaryBoxClass);
			dojo.html.addClass(this.screenshotTdNode, this.screenshotTdClass);
			dojo.html.addClass(this.summaryContainerNode, this.summaryContainerClass);
			dojo.html.addClass(this.summaryNode, this.summaryClass);
			dojo.html.addClass(this.viewDemoLinkNode, this.viewDemoLinkClass);

			this.nameNode.appendChild(document.createTextNode(this.name));
			this.descriptionNode.appendChild(document.createTextNode(this.description));
			this.thumbnailImageNode.src = this.thumbnail;
			this.thumbnailImageNode.name=this.name;
			this.viewDemoImageNode.src = this.viewDemoImage;
			this.viewDemoImageNode.name=this.name;
		},
		onSelectDemo: function() {
			//Attach to this to do something when a demo is selected
		}
	},
	"",
	function() {
		this.demo = "";

		this.domNodeClass="demoItemWrapper";

		this.summaryBoxNode="";
		this.summaryBoxClass="demoItemSummaryBox";

		this.nameNode="";
		this.thumbnailImageNode="";
		this.viewDemoImageNode="";

		this.screenshotTdNode="";
		this.screenshotTdClass="demoItemScreenshot";

		this.summaryContainerNode="";
		this.summaryContainerClass="demoItemSummaryContainer";

		this.summaryNode="";
		this.summaryClass="demoItemSummary";

		this.viewDemoLinkNode="";
		this.viewDemoLinkClass="demoItemView";

		this.descriptionNode="";

		this.name="Some Demo";
		this.description="This is the description of this demo.";
		this.thumbnail="images/test_thumb.gif";
		this.viewDemoImage="images/viewDemo.png";
	}
);

__CPAN_FILE__ src/widget/demoEngine/SourcePane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.demoEngine.SourcePane");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.io.*");

dojo.widget.defineWidget("my.widget.demoEngine.SourcePane", 
	dojo.widget.HtmlWidget, 
	{
		templatePath: dojo.uri.dojoUri("src/widget/demoEngine/templates/SourcePane.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/demoEngine/templates/SourcePane.css"),
		postCreate: function() {
			dojo.html.addClass(this.domNode,this.domNodeClass);
			dojo.debug("PostCreate");
		},
	
		getSource: function() {
			if (this.href) {
				dojo.io.bind({
					url: this.href,
					load: dojo.lang.hitch(this, "fillInSource"),
					mimetype: "text/plain"
				});
			}
		},	

		fillInSource: function(type, source, e) {
			this.sourceNode.value=source;
		},

		setHref: function(url) {
			this.href = url;
			this.getSource();
		}
	},
	"",
	function() {
		dojo.debug("SourcePane Init");
		this.domNodeClass="sourcePane";
		this.sourceNode = "";
		this.href = "";
	}
);

__CPAN_FILE__ src/widget/demoEngine/DemoPane.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.demoEngine.DemoPane");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("my.widget.demoEngine.DemoPane", 
	dojo.widget.HtmlWidget, 
	{
		templatePath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoPane.html"),
		templateCssPath: dojo.uri.dojoUri("src/widget/demoEngine/templates/DemoPane.css"),
		postCreate: function() {
			dojo.html.addClass(this.domNode,this.domNodeClass);
			dojo.debug("PostCreate");
			this._launchDemo();
		},
		
		_launchDemo: function() {
			dojo.debug("Launching Demo");
			dojo.debug(this.demoNode);
			this.demoNode.src=this.href;
		},

		setHref: function(url) {
			this.href = url;
			this._launchDemo();
		}
	},
	"",
	function() {
		dojo.debug("DemoPane Init");
		this.domNodeClass="demoPane";
		this.demoNode = "";
		this.href = "";
	}
);

__CPAN_FILE__ src/widget/demoEngine/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	browser: [
		"dojo.widget.demoEngine.DemoItem",
		"dojo.widget.demoEngine.DemoNavigator",
		"dojo.widget.demoEngine.DemoPane",
		"dojo.widget.demoEngine.SourcePane",
		"dojo.widget.demoEngine.DemoContainer"
	]
});
dojo.provide("dojo.widget.demoEngine.*");

__CPAN_DIR__ src/widget/demoEngine/templates
__CPAN_FILE__ src/widget/demoEngine/templates/DemoContainer.html
<div dojoAttachPoint="domNode">
	<table width="100%" cellspacing="0" cellpadding="5">
		<tbody>
			<tr dojoAttachPoint="headerNode">
				<td dojoAttachPoint="returnNode" valign="middle" width="1%">
					<img dojoAttachPoint="returnImageNode" dojoAttachEvent="onclick: returnToDemos"/>
				</td>
				<td>
					<h1 dojoAttachPoint="demoNameNode"></h1>
					<p dojoAttachPoint="summaryNode"></p>
				</td>
				<td dojoAttachPoint="tabControlNode" valign="middle" align="right" nowrap>
					<span dojoAttachPoint="sourceButtonNode" dojoAttachEvent="onclick: showSource">source</span>
					<span dojoAttachPoint="demoButtonNode" dojoAttachEvent="onclick: showDemo">demo</span>
				</td>
			</tr>
			<tr>
				<td colspan="3">
					<div dojoAttachPoint="tabNode">
					</div>
				</td>
			</tr>
		</tbody>
	</table>
</div>

__CPAN_FILE__ src/widget/demoEngine/templates/SourcePane.html
<div dojoAttachPoint="domNode">
	<textarea dojoAttachPoint="sourceNode" rows="100%"></textarea>
</div>

__CPAN_FILE__ src/widget/demoEngine/templates/general.css
.demoListWrapper {
	border:1px solid #dcdbdb;
	background-color:#f8f8f8;
	padding:2px;
}

.demoListContainer {
	border:1px solid #f0f0f0;
	background-color:#fff;
	padding:1em;
}

.demoSummaryBox {
	background: #efefef;
	border:1px solid #dae3ee;
}

.screenshot {
	padding:0.65em;
	width:175px;
	border-right:1px solid #fafafa;
	text-align:center;
}

.demoSummary {
	margin-bottom:1em;
}

.demoSummary a:link, .demoSummary a:visited {
	color:#a6238f;
	text-decoration:none;
}

.summaryContainer {
	border-left:1px solid #ddd;
}

.summaryContainer h1 {
	background-color:#e8e8e8;
	border-bottom: 1px solid #e6e6e6;
	color:#738fb9;
	margin:1px;
	padding:0.5em;
	font-family:"Lucida Grande", "Tahoma", serif;
	font-size:1.25em;
	font-weight:normal;
}

.summaryContainer h1 .packageSummary {
	display:block;
	color:#000;
	font-size:10px;
	margin-top:2px;
}

.summaryContainer .summary {
	padding:1em;
}

.summaryContainer .summary p {
	font-size:0.85em;
	padding:0;
	margin:0;
}

.reflection {
	background: url("images/demoBoxReflection.gif") repeat-x top left;
	height:25px;
}

.view {
	text-align:right;
}

__CPAN_FILE__ src/widget/demoEngine/templates/DemoNavigator.html
<div dojoAttachPoint="domNode">
	<table width="100%" cellspacing="0" cellpadding="5">
		<tbody>
			<tr dojoAttachPoint="navigationContainer">
				<td dojoAttachPoint="categoriesNode" valign="top" width="1%">
					<h1>Categories</h1>
					<div dojoAttachPoint="categoriesButtonsNode"></div>
				</td>

				<td dojoAttachPoint="demoListNode" valign="top">
					<div dojoAttachPoint="demoListWrapperNode">
						<div dojoAttachPoint="demoListContainerNode">
						</div>
					</div>
				</td>
			</tr>
			<tr>
				<td colspan="2">
					<div dojoAttachPoint="demoNode"></div>
				</td>
			</tr>
		</tbody>
	</table>
</div>

__CPAN_FILE__ src/widget/demoEngine/templates/DemoItem.html
<div dojoAttachPoint="domNode">
	<div dojoAttachPoint="summaryBoxNode">
		<table width="100%" cellspacing="0" cellpadding="0">
			<tbody>
				<tr>
					<td dojoAttachPoint="screenshotTdNode" valign="top" width="1%">
						<img dojoAttachPoint="thumbnailImageNode" dojoAttachEvent="onclick: onSelectDemo" />
					</td>
					<td dojoAttachPoint="summaryContainerNode" valign="top">
						<h1 dojoAttachPoint="nameNode">
						</h1>
						<div dojoAttachPoint="summaryNode">
							<p dojoAttachPoint="descriptionNode"></p>
							<div dojoAttachPoint="viewDemoLinkNode"><img dojoAttachPoint="viewDemoImageNode"/ dojoAttachEvent="onclick: onSelectDemo"></div>
						</div>
					</td>
				</tr>
			</tbody>
		</table>
	</div>
</div>

__CPAN_FILE__ src/widget/demoEngine/templates/DemoPane.html
<div dojoAttachPoint="domNode">
	<iframe dojoAttachPoint="demoNode"></iframe>
</div>

__CPAN_FILE__ src/widget/demoEngine/templates/DemoItem.css
.demoItemSummaryBox {
	background: #efefef;
	border:1px solid #dae3ee;
}

.demoItemScreenshot {
	padding:0.65em;
	width:175px;
	border-right:1px solid #fafafa;
	text-align:center;
	cursor: pointer;
}

.demoItemWrapper{
	margin-bottom:1em;
}

.demoItemWrapper a:link, .demoItemWrapper a:visited {
	color:#a6238f;
	text-decoration:none;
}

.demoItemSummaryContainer {
	border-left:1px solid #ddd;
}

.demoItemSummaryContainer h1 {
	background-color:#e8e8e8;
	border-bottom: 1px solid #e6e6e6;
	color:#738fb9;
	margin:1px;
	padding:0.5em;
	font-family:"Lucida Grande", "Tahoma", serif;
	font-size:1.25em;
	font-weight:normal;
}

.demoItemSummaryContainer h1 .packageSummary {
	display:block;
	color:#000;
	font-size:10px;
	margin-top:2px;
}

.demoItemSummaryContainer .demoItemSummary{
	padding:1em;
}

.demoItemSummaryContainer .demoItemSummary p {
	font-size:0.85em;
	padding:0;
	margin:0;
}

.demoItemView {
	text-align:right;
	cursor: pointer;
}

__CPAN_FILE__ src/widget/demoEngine/templates/SourcePane.css
.sourcePane {
	width: 100%;
	height: 100%;
	padding: 0px;
	margin: 0px;
	overflow: hidden;
}

.sourcePane textarea{
	width: 100%;
	height: 100%;
	border: 0px;
	overflow: auto;
	padding: 0px;
	margin:0px;
}

* html .sourcePane {
	overflow: auto;
}

__CPAN_FILE__ src/widget/demoEngine/templates/DemoContainer.css
.demoContainer{
	width: 100%;
	height: 100%;
	padding: 0px;
	margin: 0px;
}

.demoContainer .return {
	cursor: pointer;
}

.demoContainer span {
	margin-right: 10px;
	cursor: pointer;
}

.demoContainer .selected {
	border-bottom: 5px solid #95bfff;
}

.demoContainer table {
	background: #f5f5f5;
	width: 100%;
	height: 100%;
}

.demoContainerTabs {
	width: 100%;
	height: 400px;
}

.demoContainerTabs .dojoTabLabels-top {
	display: none;
}

.demoContainerTabs .dojoTabPaneWrapper {
	border: 0px;
}


__CPAN_FILE__ src/widget/demoEngine/templates/DemoPane.css
.demoPane {
	width: 100%;
	height: 100%;
	padding: 0px;
	margin: 0px;
	overflow: hidden;
}

.demoPane iframe {
	width: 100%;
	height: 100%;
	border: 0px;
	border: none;
	overflow: auto;
	padding: 0px;
	margin:0px;
	background: #ffffff;
}

__CPAN_FILE__ src/widget/demoEngine/templates/DemoNavigator.css
.demoNavigatorListWrapper {
	border:1px solid #dcdbdb;
	background-color:#f8f8f8;
	padding:2px;
}

.demoNavigatorListContainer {
	border:1px solid #f0f0f0;
	background-color:#fff;
	padding:1em;
}

.demoNavigator h1 {
	margin-top: 0px;
	margin-bottom: 10px;
	font-size: 1.2em;
	border-bottom:1px dotted #a9ccf5;
}

.demoNavigator .dojoButton {
	margin-bottom: 5px;
}

.demoNavigator .dojoButton .dojoButtonContents {
	font-size: 1.1em;
	width: 100px;
	color: black;
}

__CPAN_DIR__ src/widget/demoEngine/templates/images
__CPAN_FILE__ src/widget/demoEngine/templates/images/test_thumb.gif
GIF89a´�÷# ÞÞÞèèèêêêëëëíííéééçççäääæææåååðððìììîîî($%þþþñññúúúóóóÐÐÐÜÜÜYVWüüüýýý301¤¢¢òòòôôô845ÁÀÀ&"#VSTÙØÙ+'(÷÷÷”’“-**EAB<89ÖÖÖ'#$øøøûûû:78?<=GDEÜÛÛïîîõôõ%!",()gdeùùùb_`àßà\YZ1-.URS.*+öõõ>:;–””ããã¹¸¸öööolmÊÉÊÍÌÌB??OLMãââ�FCDFBC@=>^[[XUU)%&QNNáààéèè512411A>?…ƒ„�‹ŒIFFSPQWTT;88ßÞß¿¾¾ žŸˆ††ÎÍÍ¤££ŽŒŒ¡Ÿ ¬««âááLIJmkkljj•““TQRpmnPMM$ !*&'çæçhefxuvROP·µ¶nklÃÂÃ2./üûü956kii´³³0,-_\\LHIC@@=9:“‘’ÂÁÁœšš�››°®¯c`a»ººMJK²±±xvwZWXº¹¹ÚÙÙ`]^„�‚‹ˆ‰×××©§¨£¡¡734°¯¯ifg¢ ¡NKL�ŽŽàààèççš˜™µ³´ÈÇÇÌËËîíîdabª¨¨¥¤¤~|}khi|yz&##­¬¬‚€€ƒ��jgh„‚ƒ¾½½ÃÂÂ§¥¦trrRNO’�‘ËÊËØ×ØÏÎÎ«ªª~{|¸··rop—••KGHÆÅÅHEF‰‡‡ŒŠ‹XUVŸ�žÒÑÒ½¼½3/0ÅÄÄ‡……·¶¶ª©©eccÐÏÏ‘��ÛÚÚÊÉÉ,)*³²²���[XYÄÃÄÇÆÆ623}~˜–—]Z[zxxÉÈÈ?;</+,urs†„…ebb½»¼a^_ÝÝÝ—––_\]ÖÕÕÔÓÓŠˆˆ}z{ïïïÿÿÿ!ù,´�ÿË	H° Áƒ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±£Ç� CŠI²¤É“(Sª\É²¥Ë—0cÊœI³¦Í›8sêÜÉ³§ÏŸ@ƒrT ¨Ñ£H“*]Ê´©Ó§P£J�UÇæ²jÝÊµ«×¯`ÃŠK¶¬Ù³e\EË¶­Û·pã†U»«Ü»xóêmKW£Ý½€ÆÛ7ãßÁˆ+[ãáÅ�#n|ñ±äË˜áR¶h9³çÏc7Wìº´é¬¢)’>Í:sê‰«[Ë†üZbìÙ¸×Žx;·o½»!öþM<nð‡Ã‹+g{ÜaòåÐÉ6oø<ºõ¯ÓV¿Î]kö…Û»sÿÿ®0¼xëäš?==Âõì•»??>ñùëÛ÷�¿ þý¸õGÐÊ&à@ÈÚ�%¨ i–ãàƒ E8!…žYˆa|nx^‡vbˆ×�Hbt&ž¸\Š*Çb‹¿½cn2z–Cüñ	iäðÄŒ5fæ-`¤‘º¸nLq¤F¹$nj©CRÖåÛGâ@@–~ù†Å‘¼¦a¾Updœé˜oÎiÇnVæÛ
Gš°ƒ[<0Þ”³ái$@°uA¸âK‰€Ê&(J¤°Õ~Œ`é¥g|©UGàW°d ê¨|QÎiA~öè’jUC§�Úÿ°Õ0�²ÂÕ«°éª�¶ö(4hUG%k¬}H°ÕG’rÂV”�++ÀÀ«–¬YÐ	~.q$°Z] ä–K�~nÅEK$Â•âL ï¼€°`¯™ýÊ- âD9|,Œ©&ö@( ‡;0@Gò1°YD ÂŠlÑzøJŠ‘Y@ #�–WtpK–h’ÀVx˜RƒÁx]E  `T!­<˜GZ²•li²VrM~ü�
8¡i
üÑi
\I²ÇGüÐƒÈáÂµaz¦Á
F’ËV$¡ôÉæ@à-¥h•‰‘%ÈÿšÕéI¸o9ŽVª‰4v¼%G¶`WN™„
æ¨ ‡‘ºLž•iE›æ$@Â‘Ûh%�‘t0°Šûý™Ð€=»‘wt°‘H`È‘¼puÇ‘ÍdUG“•ÖFÂÕ4GNRí{ù�´‘�tÅÄ‘H<ðGÂÕÞ¬P·GÎ`Ž·ÐWÂt:A…Ž'FH§�t¥&ïæ<rdáàJ:õ	s€.}æPF§âÀ-4áHT ¶0ÓƒNáAG²‚9f`%Lpå3RÌ¶É
æèB§8Á•DáHE�`Ú0S¸#mŒ+ûÀ$Àƒ#q@Y[A€ÿ2ø˜ zæèÅ‘<`¯­Ð€]’!š2Ó�NmƒFRƒ#f¤Hq¥t8’$�>I8¢‘B0®<€GZƒß”™"IX¶Ð©$ÐM+ˆÄ‘B °àHe(ÇéŒD,q…KGš£�2I#á‡Gú€!:Õ‚:pe&€´p�CŠP�3’ Ð;I’œñÌ˜Ž4‡<~@}ücV@y¤&<¡”G
‚¸€F¶²S°�gÑ)MhïH9àÔ‘” ®h tFZ†y$9@!ƒl#WÐ€ÌÙÕ1‡èTŽi$WX£S?äJ9Àg$;A¦€D@ÿO0±+EXb2Uã™3t*‚ã<|�‡#aƒ•[�‚Ž¤sˆ ‡FB…9ZÐ©!p¥5R
ÏÔ¢Sƒ£÷"P‰%6Q+ÞH%Þ`Ž˜ñ„æ0C§Üµ•dáH83ç/c™² UYyã‘¦`ŽStª–[‘E§QS5@}_è¸b€†	$µ�g,Pˆ8²P+*àCž0üqGŠ„™`ðS#‰¢t‹@5>B<K¨3Ä :uˆ­P@¦Q "Ž”®4âHgøœŽd‹¬�ÌH{HWV˜%Âé�1åÀ&š°…¬X@5\wpR«PZÙŸèd
ÿDãHäÈ
ÔØÙ™ÃŠ'`§è™YtŠ
»…¸°ˆ#¡ÀY‘‹¡ŽgËÊ<�T­x}Ð CG‚†•7¥ñ¬b°Î€FlÜ0G8êA`ÂÒªÁ�´2¯[9Áöð
(p‚G7TÏä¢E¸B°ò€l¤á¥xÆ1’a-s�£ FÌ@…KqˆFºâV°
*,áe00‡6âÊF³oq³Ðáö|V<8ÒÕà
2Ð‘« ÿà*2€Ü€îF™Éñy�6@	)ˆA<ÔS2˜°ˆ#D	Ì?žQ�é¨f%I¹ÿÍ³	3œ1#ç9K¦Îv¦MšóLç=óùÎ~þ³žß,èá²¹Ðkž$¢ËE3Z™Žf0–#ÝgBSzÐ“¾tdð¬é»pºÓÆ	4¨	#êQËåÓ¦æK©SýT³ú,®~uZV-k´ÄºÖb¹5®Cë]K§×¾Î5°ƒÍkK»ÕÃ>vWt­lÔd„8@’Ž`�€€n#`ÚÄ€·»}4`!€ÆÝmp[ÜìF€�mƒ4€Ûñnw³�“ooàÜI@¿õ½oÂ¼Û	(ˆÀ~	ª8üá�¸Ä'Þ”K(È½^€Ž{üã ¹ÈGNò’›üä(ÿO¹ÊWžò‹ÿû é^w¼	@óšÛüæ8Ï¹ÎwÎóžûüç@ºÐ�Þïy×;!
Ø6»Àô¦;ýéP�ºÔ§Nõª[ýêXÏºÖ±ïrü!€`€²›ýìhO»Ú×Îö¶»ýíp�»Üçw$@(@FPŽ@ì¼àOøÂþðˆO¼âÏøÆ;þñƒôþu�@àò˜ç{@à ½èGOúÒ›þô¨O½êWÏúÖ�^ ô¾Ì_Þ#È½îw¿û4€œï¼�€âÿøÈO¾ò—Ïüæ;ÿùÐ�þÊNsàûž÷ØÏ=î³Ï}î—£›~[ÓŸ˜ÿüèO¿ú×Ïþö»ÿýï¿{à›üÙŸ»ûøß½P~�ßêŠwð—~ xPwsWyû·€Ø€ø€�8�X�x�˜�¸�Ø�X;
__CPAN_FILE__ src/widget/demoEngine/templates/images/viewDemo.png
‰PNG


IHDRX	ú#gAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<íIDATxÚì˜ÏkAÇ7µZBYõVôü<K²=y04®Ô“B@/z¬ñ(Bº� ¹ä(ºrð–%g)ÝazñdŽ¥µ5~_xSãgóÃK÷Ácggß›Ÿyóc§P©T¬¤½ýlbE‘uUecA¿"4l4ï™•ËÊÏ$I’}×u÷†Ãáóå³<©V«/ûýþ‹çß²)ÒÇü¶µ÷õz}§ÓéÜn·ÛïM
(
>=èDd«<—&4^a_}‘¦:CzN§ÓÿØ)—ËË”µ¸o[­Ö�n·ûÚÀ¾õ¨zoB¨ÍºJ9€îª¾r@¢þµžÉx<^¦¼"à¾B4ßÅ’Qû×áBìi�MRc"l|¤|UÄ—xôæÔ©ž¤#i‡Yå±ˆÈN8¯Éåºõª>Š~éks¾-ý7Ö1j€»W«Õ¾òi#UÐ€�­"µ©u $à
x¾ˆBWØ{"mýT^0.:àò	Ì'¦R
à±h‹Çð•Œ¸^²á›³6À$ƒÁà»�™‚ìpt&)6M-ò|‘vG³´UD_Ìíˆ¹ÞÙ#Þp@P~€tÄ³Ç‘#?`»@ùo®‰/ECÛ0ŠÔ†6Š£�àCQŽ- 'u“½ »*Š5ÿ,lI«3QðW
øZ‡~4´9"'bš·nú1œ!•Ä7ß0zmœ€—«�)ÙCz²@¿#^V”ÿå¬“€ãb±H¿¿?
�i÷µ¼ÐÇÐ#ÓVQcÐ¨X�Ò$à1�‘QlËN¦„¥­“VJ9$OÒå»)lØÑZÿÙr1[>¼‹xý"Þ�xJ|Ëï"Vÿ'G>çÁÍ•—“w¹'9JÃ�›™g^Wæ€³Ë8G—
ðvŸ-èMè9ôzÁÏsNŸÒÆš£åŸºMr]÷^ŸkÐë)ùö7Ã>ãeä'ˆé•œE07øŽ�`þ"Ä‹<VÓå�Õˆ€\à«IEND®B`‚
__CPAN_DIR__ src/widget/svg
__CPAN_FILE__ src/widget/svg/Chart.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.svg.Chart");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.Chart");
dojo.require("dojo.html.layout");
dojo.require("dojo.math");
dojo.require("dojo.svg");
dojo.require("dojo.gfx.color");

dojo.require("dojo.json");

dojo.widget.defineWidget(
	"dojo.widget.svg.Chart",
	[dojo.widget.HtmlWidget, dojo.widget.Chart],
	function(){
		//	summary
		//	initializes the SVG version of Chart.
		this.templatePath=null;
		this.templateCssPath=null;
		this._isInitialize=false;
		this.hasData=false;
		this.vectorNode=null;
		this.plotArea=null;
		this.dataGroup=null;
		this.axisGroup=null;
		this.properties={
			height:0,	//	defaults, will resize to the domNode.
			width:0,
			defaultWidth:600,
			defaultHeight:400,
			plotType:null,
			padding:{
				top:10,
				bottom:2,
				left:60,
				right:30
			},
			axes:{
				x:{
					plotAt:0,
					label:"",
					unitLabel:"",
					unitType:Number,
					nUnitsToShow:10,
					range:{
						min:0,
						max:200
					}
				},
				y:{
					plotAt:0,
					label:"",
					unitLabel:"",
					unitType:Number,
					nUnitsToShow:10,
					range:{
						min:0,
						max:200
					}
				}
			}
		};
	},
	{
		parseProperties:function(/* HTMLElement */node){
			//	summary
			//	Parse the properties off the main tag
			var bRangeX=false;
			var bRangeY=false;
			if (node.getAttribute("width")){ 
				this.properties.width=node.getAttribute("width");
			}
			if (node.getAttribute("height")){
				this.properties.height=node.getAttribute("height");
			}
			if (node.getAttribute("plotType")){
				this.properties.plotType=node.getAttribute("plotType");
			}
			if (node.getAttribute("padding")){
				if (node.getAttribute("padding").indexOf(",") > -1)
					var p=node.getAttribute("padding").split(","); 
				else var p=node.getAttribute("padding").split(" ");
				if (p.length==1){
					var pad=parseFloat(p[0]);
					this.properties.padding.top=pad;
					this.properties.padding.right=pad;
					this.properties.padding.bottom=pad;
					this.properties.padding.left=pad;
				} else if(p.length==2){
					var padV=parseFloat(p[0]);
					var padH=parseFloat(p[1]);
					this.properties.padding.top=padV;
					this.properties.padding.right=padH;
					this.properties.padding.bottom=padV;
					this.properties.padding.left=padH;
				} else if(p.length==4){
					this.properties.padding.top=parseFloat(p[0]);
					this.properties.padding.right=parseFloat(p[1]);
					this.properties.padding.bottom=parseFloat(p[2]);
					this.properties.padding.left=parseFloat(p[3]);
				}
			}
			if (node.getAttribute("rangeX")){
				var p=node.getAttribute("rangeX");
				if (p.indexOf(",")>-1) p=p.split(",");
				else p=p.split(" ");
				this.properties.axes.x.range.min=parseFloat(p[0]);
				this.properties.axes.x.range.max=parseFloat(p[1]);
				bRangeX=true;
			}
			if (node.getAttribute("rangeY")){
				var p=node.getAttribute("rangeY");
				if (p.indexOf(",")>-1) p=p.split(",");
				else p=p.split(" ");
				this.properties.axes.y.range.min=parseFloat(p[0]);
				this.properties.axes.y.range.max=parseFloat(p[1]);
				bRangeY=true;
			}
			return { rangeX:bRangeX, rangeY:bRangeY };
		},
		setAxesPlot:function(/* HTMLElement */table){
			//	summary
			//	figure out where to plot the axes
			if (table.getAttribute("axisAt")){
				var p=table.getAttribute("axisAt");
				if (p.indexOf(",")>-1) p=p.split(",");
				else p=p.split(" ");
				
				//	x axis
				if (!isNaN(parseFloat(p[0]))){
					this.properties.axes.x.plotAt=parseFloat(p[0]);
				} else if (p[0].toLowerCase()=="ymin"){
					this.properties.axes.x.plotAt=this.properties.axes.y.range.min;
				} else if (p[0].toLowerCase()=="ymax"){
					this.properties.axes.x.plotAt=this.properties.axes.y.range.max;
				}

				// y axis
				if (!isNaN(parseFloat(p[1]))){
					this.properties.axes.y.plotAt=parseFloat(p[1]);
				} else if (p[1].toLowerCase()=="xmin"){
					this.properties.axes.y.plotAt=this.properties.axes.x.range.min;
				} else if (p[1].toLowerCase()=="xmax"){
					this.properties.axes.y.plotAt=this.properties.axes.x.range.max;
				}
			} else {
				this.properties.axes.x.plotAt=this.properties.axes.y.range.min;
				this.properties.axes.y.plotAt=this.properties.axes.x.range.min;
			}
		},
		drawVectorNode:function(){
			//	summary
			//	Draws the main canvas for the chart
			dojo.svg.g.suspend();		
			if(this.vectorNode) this.destroy();
			this.vectorNode=document.createElementNS(dojo.svg.xmlns.svg, "svg");
			this.vectorNode.setAttribute("width", this.properties.width);
			this.vectorNode.setAttribute("height", this.properties.height);
			dojo.svg.g.resume();
		},
		drawPlotArea:function(){
			//	summary
			//	Draws the plot area for the chart
			dojo.svg.g.suspend();		
			if(this.plotArea){
				this.plotArea.parentNode.removeChild(this.plotArea);
				this.plotArea=null;
			}
			var defs = document.createElementNS(dojo.svg.xmlns.svg, "defs");
			var clip = document.createElementNS(dojo.svg.xmlns.svg, "clipPath");
			clip.setAttribute("id","plotClip"+this.widgetId);
			var rect = document.createElementNS(dojo.svg.xmlns.svg, "rect");		
			rect.setAttribute("x", this.properties.padding.left);
			rect.setAttribute("y", this.properties.padding.top);
			rect.setAttribute("width", this.properties.width-this.properties.padding.left-this.properties.padding.right);
			rect.setAttribute("height", this.properties.height-this.properties.padding.top-this.properties.padding.bottom);
			clip.appendChild(rect);
			defs.appendChild(clip);
			this.vectorNode.appendChild(defs);

			//	the plot background.
			this.plotArea = document.createElementNS(dojo.svg.xmlns.svg, "g");
			this.vectorNode.appendChild(this.plotArea);
			var rect = document.createElementNS(dojo.svg.xmlns.svg, "rect");		
			rect.setAttribute("x", this.properties.padding.left);
			rect.setAttribute("y", this.properties.padding.top);
			rect.setAttribute("width", this.properties.width-this.properties.padding.left-this.properties.padding.right);
			rect.setAttribute("height", this.properties.height-this.properties.padding.top-this.properties.padding.bottom);
			rect.setAttribute("fill", "#fff");
			this.plotArea.appendChild(rect);
			dojo.svg.g.resume();
		},
		drawDataGroup:function(){
			//	summary
			//	Draws the data group for the chart
			dojo.svg.g.suspend();		
			if(this.dataGroup){
				this.dataGroup.parentNode.removeChild(this.dataGroup);
				this.dataGroup=null;
			}
			this.dataGroup = document.createElementNS(dojo.svg.xmlns.svg, "g");
			this.dataGroup.setAttribute("style","clip-path:url(#plotClip"+this.widgetId+");");
			this.plotArea.appendChild(this.dataGroup);
			dojo.svg.g.resume();
		},
		drawAxes:function(){
			//	summary
			//	Draws the axes for the chart
			dojo.svg.g.suspend();		
			if(this.axisGroup){
				this.axisGroup.parentNode.removeChild(this.axisGroup);
				this.axisGroup=null;
			}
			//	axis group
			this.axisGroup = document.createElementNS(dojo.svg.xmlns.svg, "g");
			this.plotArea.appendChild(this.axisGroup);

			//	x axis
			var stroke=1;
			var line = document.createElementNS(dojo.svg.xmlns.svg, "line");
			var y=dojo.widget.svg.Chart.Plotter.getY(this.properties.axes.x.plotAt, this);
			line.setAttribute("y1", y);
			line.setAttribute("y2", y);
			line.setAttribute("x1",this.properties.padding.left-stroke);
			line.setAttribute("x2",this.properties.width-this.properties.padding.right);
			line.setAttribute("style","stroke:#000;stroke-width:"+stroke+";");
			this.axisGroup.appendChild(line);
			
			//	x axis units.
			//	(min and max)
			var textSize=10;
			var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
			text.setAttribute("x", this.properties.padding.left);
			text.setAttribute("y", this.properties.height-this.properties.padding.bottom+textSize+2);
			text.setAttribute("style", "text-anchor:middle;font-size:"+textSize+"px;fill:#000;");
			text.appendChild(document.createTextNode(dojo.math.round(parseFloat(this.properties.axes.x.range.min),2)));
			this.axisGroup.appendChild(text);
			
			var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
			text.setAttribute("x", this.properties.width-this.properties.padding.right-(textSize/2));
			text.setAttribute("y", this.properties.height-this.properties.padding.bottom+textSize+2);
			text.setAttribute("style", "text-anchor:middle;font-size:"+textSize+"px;fill:#000;");
			text.appendChild(document.createTextNode(dojo.math.round(parseFloat(this.properties.axes.x.range.max),2)));
			this.axisGroup.appendChild(text);	
			
			//	y axis
			var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
			var x=dojo.widget.svg.Chart.Plotter.getX(this.properties.axes.y.plotAt, this);
			line.setAttribute("x1", x);
			line.setAttribute("x2", x);
			line.setAttribute("y1", this.properties.padding.top);
			line.setAttribute("y2", this.properties.height-this.properties.padding.bottom);
			line.setAttribute("style", "stroke:#000;stroke-width:"+stroke+";");
			this.axisGroup.appendChild(line);

			//	y axis units
			var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
			text.setAttribute("x", this.properties.padding.left-4);
			text.setAttribute("y", this.properties.height-this.properties.padding.bottom);
			text.setAttribute("style", "text-anchor:end;font-size:"+textSize+"px;fill:#000;");
			text.appendChild(document.createTextNode(dojo.math.round(parseFloat(this.properties.axes.y.range.min),2)));
			this.axisGroup.appendChild(text);
			
			var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
			text.setAttribute("x", this.properties.padding.left-4);
			text.setAttribute("y", this.properties.padding.top+(textSize/2));
			text.setAttribute("style", "text-anchor:end;font-size:"+textSize+"px;fill:#000;");
			text.appendChild(document.createTextNode(dojo.math.round(parseFloat(this.properties.axes.y.range.max),2)));
			this.axisGroup.appendChild(text);	
			dojo.svg.g.resume();
		},

		init:function(){
			//	summary
			//	Initialize the chart
			if(!this.properties.width || !this.properties.height){
				var box=dojo.html.getContentBox(this.domNode);
				if(!this.properties.width){
					this.properties.width=(box.width<32)?this.properties.defaultWidth:box.width;
				}
				if(!this.properties.height){
					this.properties.height=(box.height<32)?this.properties.defaultHeight:box.height;
				}
			}

			//	set up the chart; each is a method so that it can be selectively overridden.
			this.drawVectorNode();
			this.drawPlotArea();
			this.drawDataGroup();
			this.drawAxes();

			//	this is last.
			this.domNode.appendChild(this.vectorNode);
			this.assignColors();
			this._isInitialized=true;
		},
		destroy:function(){
			//	summary
			//	Node cleanup
			while(this.domNode.childNodes.length>0){
				this.domNode.removeChild(this.domNode.childNodes.item(0));
			}
			this.vectorNode=this.plotArea=this.dataGroup=this.axisGroup=null;
		},
		render:function(){
			//	summary
			//	Draws the data on the chart
			dojo.svg.g.suspend();
			
			if (this.dataGroup){
				while(this.dataGroup.childNodes.length>0){
					this.dataGroup.removeChild(this.dataGroup.childNodes.item(0));
				}
			} else {
				this.init();
			}

			//	plot it.
			for(var i=0; i<this.series.length; i++){
				dojo.widget.svg.Chart.Plotter.plot(this.series[i], this);
			}
			dojo.svg.g.resume();
		},
		postCreate:function(){
			//	summary
			//	Parse any data if included with the chart, and kick off the rendering.
			var table=this.domNode.getElementsByTagName("table")[0];
			if (table){
				var ranges=this.parseProperties(table);
				var bRangeX=false;
				var bRangeY=false;
			
				//	fix the axes
				var axisValues = this.parseData(table);
				if(!bRangeX){
					this.properties.axes.x.range={min:axisValues.x.min, max:axisValues.x.max};
				}
				if(!bRangeY){
					this.properties.axes.y.range={min:axisValues.y.min, max:axisValues.y.max};
				}
				this.setAxesPlot(table);

				//	table values should be populated, now pop it off.
				this.domNode.removeChild(table);
			}
			if(this.series.length>0){
				this.render();
			}
		}
	}
);

dojo.widget.svg.Chart.Plotter=new function(){
	//	summary
	//	Singleton for plotting series of data.
	var self=this;
	var plotters = {};
	var types=dojo.widget.Chart.PlotTypes;
	
	this.getX=function(/* string||number */value, /* dojo.widget.Chart */chart){
		//	summary
		//	Calculate the x coord on the passed chart for the passed value
		var v=parseFloat(value);
		var min=chart.properties.axes.x.range.min;
		var max=chart.properties.axes.x.range.max;
		var ofst=0-min;
		min+=ofst; max+=ofst; v+=ofst;

		var xmin=chart.properties.padding.left;
		var xmax=chart.properties.width-chart.properties.padding.right;
		var x=(v*((xmax-xmin)/max))+xmin;
		return x;	// float
	};
	this.getY=function(/* string||number */value, /* dojo.widget.Chart */chart){
		//	summary
		//	Calculate the y coord on the passed chart for the passed value
		var v=parseFloat(value);
		var max=chart.properties.axes.y.range.max;
		var min=chart.properties.axes.y.range.min;
		var ofst=0;
		if(min<0)ofst+=Math.abs(min);
		min+=ofst; max+=ofst; v+=ofst;
		
		var ymin=chart.properties.height-chart.properties.padding.bottom;
		var ymax=chart.properties.padding.top;
		var y=(((ymin-ymax)/(max-min))*(max-v))+ymax;
		return y;	// float
	};

	this.addPlotter=function(/* string */name, /* function */func){
		//	summary
		//	add a custom plotter function to this object.
		plotters[name]=func;
	};
	this.plot=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series.
		if (series.values.length==0) return;	//	void
		if (series.plotType && plotters[series.plotType]){
			return plotters[series.plotType](series, chart);	//	void
		}
		else if (chart.plotType && plotters[chart.plotType]){
			return plotters[chart.plotType](series, chart);		//	void
		}
	};

	//	plotting
	plotters["bar"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a set of bars.
		var space=1;
		var lastW = 0;
		for (var i=0; i<series.values.length; i++){
			var x=self.getX(series.values[i].x, chart);
			var w;
			if (i==series.values.length-1){
				w=lastW;
			} else{
				w=self.getX(series.values[i+1].x, chart)-x-space;
				lastW=w;
			}
			x-=(w/2);

			var yA=self.getY(chart.properties.axes.x.plotAt, chart);
			var y=self.getY(series.values[i].value, chart);
			var h=Math.abs(yA-y);
			if (parseFloat(series.values[i].value)<chart.properties.axes.x.plotAt){
				var oy=yA;
				yA=y;
				y=oy;
			}

			var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
			bar.setAttribute("fill", series.color);
			bar.setAttribute("title", series.label + ": " + series.values[i].value);
			bar.setAttribute("stroke-width", "0");
			bar.setAttribute("x", x);
			bar.setAttribute("y", y);
			bar.setAttribute("width", w);
			bar.setAttribute("height", h);
			bar.setAttribute("fill-opacity", "0.9");
			chart.dataGroup.appendChild(bar);
		}
	};
	plotters["line"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a line with tensioning
		var tension=1.5;
		var line = document.createElementNS(dojo.svg.xmlns.svg, "path");
		line.setAttribute("fill", "none");
		line.setAttribute("stroke", series.color);
		line.setAttribute("stroke-width", "2");
		line.setAttribute("stroke-opacity", "0.85");
		line.setAttribute("title", series.label);
		chart.dataGroup.appendChild(line);

		var path = [];
		for (var i=0; i<series.values.length; i++){
			var x = self.getX(series.values[i].x, chart)
			var y = self.getY(series.values[i].value, chart);

			var dx = chart.properties.padding.left+1;
			var dy = chart.properties.height-chart.properties.padding.bottom;
			if (i>0){
				dx=x-self.getX(series.values[i-1].x, chart);
				dy=self.getY(series.values[i-1].value, chart);
			}
			
			if (i==0) path.push("M");
			else {
				path.push("C");
				var cx=x-(tension-1)*(dx/tension);
				path.push(cx+","+dy);
				cx=x-(dx/tension);
				path.push(cx+","+y);
			}
			path.push(x+","+y);
		}
		line.setAttribute("d", path.join(" "));
	};
	plotters["area"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as an area with tensioning.
		var tension=1.5;
		var line = document.createElementNS(dojo.svg.xmlns.svg, "path");
		line.setAttribute("fill", series.color);
		line.setAttribute("fill-opacity", "0.4");
		line.setAttribute("stroke", series.color);
		line.setAttribute("stroke-width", "1");
		line.setAttribute("stroke-opacity", "0.8");
		line.setAttribute("title", series.label);
		chart.dataGroup.appendChild(line);

		var path = [];
		for (var i=0; i<series.values.length; i++){
			var x = self.getX(series.values[i].x, chart)
			var y = self.getY(series.values[i].value, chart);

			var dx = chart.properties.padding.left+1;
			var dy = chart.properties.height-chart.properties.padding.bottom;
			if (i>0){
				dx=x-self.getX(series.values[i-1].x, chart);
				dy=self.getY(series.values[i-1].value, chart);
			}
			
			if (i==0) path.push("M");
			else {
				path.push("C");
				var cx=x-(tension-1)*(dx/tension);
				path.push(cx+","+dy);
				cx=x-(dx/tension);
				path.push(cx+","+y);
			}
			path.push(x+","+y);
		}
		//	finish it off
		path.push("L");
		path.push(x + "," + self.getY(0, chart));
		path.push("L");
		path.push(self.getX(0, chart) + "," + self.getY(0, chart));
		path.push("Z");
		line.setAttribute("d", path.join(" "));
	},
	plotters["scatter"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a scatter chart
		var r=7;
		for (var i=0; i<series.values.length; i++){
			var x=self.getX(series.values[i].x, chart);
			var y=self.getY(series.values[i].value, chart);
			var point = document.createElementNS(dojo.svg.xmlns.svg, "path");
			point.setAttribute("fill", series.color);
			point.setAttribute("stroke-width", "0");
			point.setAttribute("title", series.label + ": " + series.values[i].value);
			point.setAttribute("d",
				"M " + x + "," + (y-r) + " " +
				"Q " + x + "," + y + " " + (x+r) + "," + y + " " +
				"Q " + x + "," + y + " " + x + "," + (y+r) + " " +
				"Q " + x + "," + y + " " + (x-r) + "," + y + " " +
				"Q " + x + "," + y + " " + x + "," + (y-r) + " " +
				"Z"
			);
			chart.dataGroup.appendChild(point);
		}
	};
	plotters["bubble"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a series of bubbles (scatter with 3rd dimension)
		//	added param for series[n].value: size
		var minR=1;
		
		//	do this off the x axis?
		var min=chart.properties.axes.x.range.min;
		var max=chart.properties.axes.x.range.max;
		var ofst=0-min;
		min+=ofst; max+=ofst;

		var xmin=chart.properties.padding.left;
		var xmax=chart.properties.width-chart.properties.padding.right;
		var factor=(max-min)/(xmax-xmin)*25;
		
		for (var i=0; i<series.values.length; i++){
			var size = series.values[i].size;
			if (isNaN(parseFloat(size))) size=minR;
			var point=document.createElementNS(dojo.svg.xmlns.svg, "circle");
			point.setAttribute("stroke-width", 0);
			point.setAttribute("fill", series.color);
			point.setAttribute("fill-opacity", "0.8");
			point.setAttribute("r", (parseFloat(size)*factor)/2);
			point.setAttribute("cx", self.getX(series.values[i].x, chart));
			point.setAttribute("cy", self.getY(series.values[i].value, chart));
			point.setAttribute("title", series.label + ": " + series.values[i].value + " (" + size + ")");
			chart.dataGroup.appendChild(point);
		}
	};
}();

__CPAN_DIR__ src/widget/templates
__CPAN_FILE__ src/widget/templates/Slider.html
<table _="weird end tag formatting is to prevent whitespace from becoming &nbsp;" 
	class="sliderMain" 
	dojoAttachPoint="focusNode" 
	dojoAttachEvent="onmousedown:_setFocus; onkey:_handleKeyEvents; onkeyup:_buttonReleased; onmouseup:_buttonReleased; onmousewheel:_mouseWheeled;"
	tabindex="0" cols=3 cellpadding=0 cellspacing=0 style="">
	<tr valign=middle align=center>
		<td class="sliderComponent" colspan=3 dojoAttachPoint=topBorderNode style=""
			><img class="sliderOutsetButton sliderButtonY"
				dojoAttachPoint=topButtonNode 
				dojoAttachEvent="onmousedown:_topButtonPressed; onmousemove:_discardEvent; ondblclick:_topButtonDoubleClicked;"
				src="${this.topButtonSrc}" 
				style="${this.buttonStyleY}"
		></td>
	</tr>
	<tr valign=middle align=center>
		<td class="sliderComponent" dojoAttachPoint=leftBorderNode style=""
			><img class="sliderOutsetButton sliderButtonX"
				dojoAttachPoint=leftButtonNode
				dojoAttachEvent="onmousedown:_leftButtonPressed; onmousemove:_discardEvent; ondblclick:_leftButtonDoubleClicked;"
				src="${this.leftButtonSrc}" 
				style="${this.buttonStyleX}"
		></td>
		<td dojoAttachPoint=constrainingContainerNode 
			class="sliderComponent sliderBackground"
			style="${this.backgroundStyle}"
			><img src="${this.handleSrc}" 
				class=sliderHandle
				dojoAttachPoint=sliderHandleNode
				style="${this.handleStyle}"
			><img src="${this.progressBackgroundSrc}"
				class="sliderBackgroundSizeOnly sliderProgressBackground"
				dojoAttachPoint=progressBackgroundNode
				style="${this.backgroundSize}"
			><img src="${this.backgroundSrc}" 
				class=sliderBackgroundSizeOnly
				dojoAttachPoint=sliderBackgroundNode
				style="${this.backgroundSize}"
		></td>
		<td class="sliderComponent" dojoAttachPoint=rightBorderNode style=""
			><img class="sliderOutsetButton sliderButtonX"
				dojoAttachPoint=rightButtonNode
				dojoAttachEvent="onmousedown:_rightButtonPressed; onmousemove:_discardEvent; ondblclick:_rightButtonDoubleClicked;"
				src="${this.rightButtonSrc}" 
				style="${this.buttonStyleX}"
		></td>
	</tr>
	<tr valign=middle align=center>
		<td class="sliderComponent" colspan=3 dojoAttachPoint=bottomBorderNode style=""
			><img class="sliderOutsetButton sliderButtonY"
				dojoAttachPoint=bottomButtonNode 
				dojoAttachEvent="onmousedown:_bottomButtonPressed; onmousemove:_discardEvent; ondblclick:_bottomButtonDoubleClicked;"
				src="${this.bottomButtonSrc}" 
				style="${this.buttonStyleY}"
		></td>
	</tr>
</table>

__CPAN_FILE__ src/widget/templates/Menu.css
.dojoMenu {
	border:1px solid #000000;
	list-style-type:none;
	margin:0;
	padding:0;
	padding-bottom: 1px;
	background-color:#f4f4f4;
	font-size: 8pt;
}

.dojoMenuSeparator {
	list-style-type:none;
	margin:0;
	padding:1px 0;
	border-bottom:1px solid #000000;
	line-height:1px;
	height:1px;
}

li:hover.dojoMenuSeparator {
	background-color:#e5e5e5;
	cursor:default;
}




.dojoContextMenu {
	position: absolute;
	display: none;
	border: 2px solid;
	border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
	list-style-type: none;
	margin: 0;
	padding: 1px;
	background-color: ThreeDFace;
	font-size: 8pt;
}

.dojoMenuItem {
	white-space: nowrap;
	padding: 2px;
	font: menu;
	color: WindowText;
}

.dojoMenuItem a {
	text-decoration: none;
	color: WindowText;
	font: inherit;
}

.dojoMenuItemHover {
	padding: 2px;
	background-color: blue;
	cursor: pointer;
	_cursor: hand;
	background-color: Highlight;
	color: HighlightText;
}
__CPAN_FILE__ src/widget/templates/ButtonTemplate.css
/* ---- button --- */
.dojoButton {
	padding: 0 0 0 0;
	font-size: 8pt;
	white-space: nowrap;
	cursor: pointer;
	font-family: Myriad, Tahoma, Verdana, sans-serif;
}

.dojoButton .dojoButtonContents {
	padding: 2px 2px 2px 2px;
	text-align: center;		/* if icon and label are split across two lines, center icon */
	color: white;
}

.dojoButtonLeftPart .dojoButtonContents {
	padding-right: 8px;
}

.dojoButtonDisabled {
	cursor: url("images/no.gif"), default;
}


.dojoButtonContents img {
	vertical-align: middle;	/* if icon and label are on same line, center them */
}

/* -------- colors ------------ */

.dojoButtonHover .dojoButtonContents {
}

.dojoButtonDepressed .dojoButtonContents {
	color: #293a4b;
}

.dojoButtonDisabled .dojoButtonContents {
	color: #aaa;
}


/* ---------- drop down button specific ---------- */

/* border between label and arrow (for drop down buttons */
.dojoButton .border {
	width: 1px;
	background: gray;
}

/* button arrow */
.dojoButton .downArrow {
	padding-left: 10px;
	text-align: center;
}

.dojoButton.disabled .downArrow {
	cursor : default;
}
__CPAN_FILE__ src/widget/templates/TreeDocIcon.css

/* CSS for TreeDocIconExtension */


/* long vertical line under docIcon, connecting w/ children */
.TreeStateChildrenYes-ExpandOpen .TreeIconContent {
    background-image : url('../templates/images/TreeV3/i_long.gif');
    background-repeat : no-repeat;
    background-position: 18px 9px;
}

/* close has higher priority */
.TreeStateChildrenYes-ExpandClosed .TreeIconContent {
    background-image : url();
}

/* higher priotity: same length and appear after background-definition */
.TreeStateChildrenNo-ExpandLeaf .TreeIconContent {
    background-image : url();
}

.TreeStateChildrenNo-ExpandClosed .TreeIconContent {
    background-image : url();
}

.TreeStateChildrenNo-ExpandOpen .TreeIconContent {
    background-image : url();
}


/* highest priority */
.TreeIconDocument {
    background-image: url('../templates/images/TreeV3/document.gif');
}

.TreeExpandOpen .TreeIconFolder {
    background-image: url('../templates/images/TreeV3/open.gif');
}

.TreeExpandClosed .TreeIconFolder {
    background-image: url('../templates/images/TreeV3/closed.gif');
}

/* generic class for docIcon */
.TreeIcon {
    width: 18px;
    height: 18px;
    float: left;
    display: inline;
    background-repeat : no-repeat;
}

div.TreeContent {
    margin-left: 36px;
}

__CPAN_FILE__ src/widget/templates/MonthlyCalendar.css
.datePickerContainer {
	margin:0.5em 2em 0.5em 0;
	/*width:10em;*/
	float:left;
}

.previousMonth {
	background-color:#bbbbbb;
}

.currentMonth {
	background-color:#8f8f8f;
}

.nextMonth {
	background-color:#eeeeee;
}

.currentDate {
	text-decoration:underline;
	font-style:italic;
}

.selectedItem {
	background-color:#3a3a3a;
	color:#ffffff;
}

.calendarContainer {
	border-collapse:collapse;
	border-spacing:0;
	border-bottom:1px solid #e6e6e6;
	overflow: hidden;
	text-align: right;
}

.calendarContainer thead{
	border-bottom:1px solid #e6e6e6;
}

.calendarContainer tbody * td {
        height: 100px;
        border: 1px solid gray;
}

.calendarContainer td {
        width: 100px;
        padding: 2px;
	vertical-align: top;
}

.monthLabel {
	font-size:0.9em;
	font-weight:400;
	margin:0;
	text-align:center;
}

.monthLabel .month {
	padding:0 0.4em 0 0.4em;
}

.yearLabel {
	font-size:0.9em;
	font-weight:400;
	margin:0.25em 0 0 0;
	text-align:right;
	color:#a3a3a3;
}

.yearLabel .selectedYear {
	color:#000;
	padding:0 0.2em;
}

.nextYear, .previousYear {
	cursor:pointer;cursor:hand;
}

.incrementControl {
	cursor:pointer;cursor:hand;
	width:1em;
}

.dojoMonthlyCalendarEvent {
	font-size:0.7em;
	overflow: hidden;
	font-color: grey;
	white-space: nowrap;
	text-align: left;
}

__CPAN_FILE__ src/widget/templates/ComboBox.html
<span _="whitespace and CR's between tags adds &nbsp; in FF"
	class="dojoComboBoxOuter"
	><input style="display:none"  tabindex="-1" name="" value="" 
		dojoAttachPoint="comboBoxValue"
	><input style="display:none"  tabindex="-1" name="" value="" 
		dojoAttachPoint="comboBoxSelectionValue"
	><input type="text" autocomplete="off" class="dojoComboBox"
		dojoAttachEvent="key:_handleKeyEvents; keyUp: onKeyUp; compositionEnd; onResize;"
		dojoAttachPoint="textInputNode"
	><img hspace="0"
		vspace="0"
		class="dojoComboBox"
		dojoAttachPoint="downArrowNode"
		dojoAttachEvent="onMouseUp: handleArrowClick; onResize;"
		src="${this.buttonSrc}"
></span>

__CPAN_FILE__ src/widget/templates/decrementMonth.gif
GIF89a	Äÿÿÿ000ÖÖÖWWWõõõóóóøøøÎÎÎØØØaaaéééyyyýýýððð222žžž¶¶¶:::………FFFúúú!ù,	#  Äh6eŠRð¬ˆDŠ™ø2Bx�“nÀ(ŽH�!;
__CPAN_FILE__ src/widget/templates/Checkbox.html
<span style="display: inline-block;" tabIndex="${this.tabIndex}" waiRole="checkbox" id="${this.id}">
	<img dojoAttachPoint="imageNode" class="dojoHtmlCheckbox" src="${dojoRoot}src/widget/templates/images/blank.gif" alt="" />
	<input type="checkbox" name="${this.name}" style="display: none" value="${this.value}"
		dojoAttachPoint="inputNode">
</span>
__CPAN_FILE__ src/widget/templates/SlideShow.css
.slideShowImg {
	position: absolute;
	left: 0px;
	top: 0px; 
	border: 2px solid #4d4d4d;
	padding: 0px;
	margin: 0px;
}


__CPAN_FILE__ src/widget/templates/EditorToolbar.css
.StyleDropdownContainer {
	position: absolute;
	z-index: 1000;
	overflow: auto;
	cursor: default;
	width: 250px;
	height: 250px;
	background-color: white;
	border: 1px solid black;
}

.ColorDropdownContainer {
	position: absolute;
	z-index: 1000;
	overflow: auto;
	cursor: default;
	width: 250px;
	height: 150px;
	background-color: white;
	border: 1px solid black;
}

.EditorToolbarDomNode {
	background-image: url(buttons/bg-fade.png);
	background-repeat: repeat-x;
	background-position: 0px -50px;
}

.EditorToolbarSmallBg {
	background-image: url(images/toolbar-bg.gif);
	background-repeat: repeat-x;
	background-position: 0px 0px;
}

/*
body {
	background:url(images/blank.gif) fixed;
}*/

.IEFixedToolbar {
	position:absolute;
	/* top:0; */
	top: expression(eval((document.documentElement||document.body).scrollTop));
}

div.bigIcon {
	width: 40px;
	height: 40px; 
	/* background-color: white; */
	/* border: 1px solid #a6a7a3; */
	font-family: Verdana, Trebuchet, Tahoma, Arial;
}

.iconContainer {
	font-family: Verdana, Trebuchet, Tahoma, Arial;
	font-size: 13px;
	float: left;
	height: 18px;
	display: block;
	/* background-color: white; */
	cursor: pointer;
	padding: 1px 4px 1px 1px; /* almost the same as a transparent border */
	border: 0px;
}

.dojoE2TBIcon {
	display: block;
	text-align: center;
	min-width: 18px;
	width: 18px;
	height: 18px;
	/* background-color: #a6a7a3; */
	background-repeat: no-repeat;
	background-image: url(buttons/aggregate.gif);
}


.dojoE2TBIcon[class~=dojoE2TBIcon] {
}

.ToolbarButtonLatched {
    border: #316ac5 1px solid; !important;
    padding: 0px 3px 0px 0px; !important; /* make room for border */
    background-color: #c1d2ee;
}

.ToolbarButtonHighlighted {
    border: #316ac5 1px solid; !important;
    padding: 0px 3px 0px 0px; !important; /* make room for border */
    background-color: #dff1ff;
}

.ToolbarButtonDisabled{
    filter: gray() alpha(opacity=30); /* IE */
    opacity: 0.30; /* Safari, Opera and Mozilla */
}

.headingContainer {
	width: 150px;
	height: 30px;
	margin: 0px;
	/* padding-left: 5px; */
	overflow: hidden;
	line-height: 25px;
	border-bottom: 1px solid black;
	border-top: 1px solid white;
}

.EditorToolbarDomNode select {
	font-size: 14px;
}
 
.dojoE2TBIcon_Sep { width: 5px; min-width: 5px; max-width: 5px; background-position: 0px 0px}
.dojoE2TBIcon_Backcolor { background-position: -18px 0px}
.dojoE2TBIcon_Bold { background-position: -36px 0px}
.dojoE2TBIcon_Cancel { background-position: -54px 0px}
.dojoE2TBIcon_Copy { background-position: -72px 0px}
.dojoE2TBIcon_Link { background-position: -90px 0px}
.dojoE2TBIcon_Cut { background-position: -108px 0px}
.dojoE2TBIcon_Delete { background-position: -126px 0px}
.dojoE2TBIcon_TextColor { background-position: -144px 0px}
.dojoE2TBIcon_BackgroundColor { background-position: -162px 0px}
.dojoE2TBIcon_Indent { background-position: -180px 0px}
.dojoE2TBIcon_HorizontalLine { background-position: -198px 0px}
.dojoE2TBIcon_Image { background-position: -216px 0px}
.dojoE2TBIcon_NumberedList { background-position: -234px 0px}
.dojoE2TBIcon_Table { background-position: -252px 0px}
.dojoE2TBIcon_BulletedList { background-position: -270px 0px}
.dojoE2TBIcon_Italic { background-position: -288px 0px}
.dojoE2TBIcon_CenterJustify { background-position: -306px 0px}
.dojoE2TBIcon_BlockJustify { background-position: -324px 0px}
.dojoE2TBIcon_LeftJustify { background-position: -342px 0px}
.dojoE2TBIcon_RightJustify { background-position: -360px 0px}
.dojoE2TBIcon_left_to_right { background-position: -378px 0px}
.dojoE2TBIcon_list_bullet_indent { background-position: -396px 0px}
.dojoE2TBIcon_list_bullet_outdent { background-position: -414px 0px}
.dojoE2TBIcon_list_num_indent { background-position: -432px 0px}
.dojoE2TBIcon_list_num_outdent { background-position: -450px 0px}
.dojoE2TBIcon_Outdent { background-position: -468px 0px}
.dojoE2TBIcon_Paste { background-position: -486px 0px}
.dojoE2TBIcon_Redo { background-position: -504px 0px}
dojoE2TBIcon_RemoveFormat { background-position: -522px 0px}
.dojoE2TBIcon_right_to_left { background-position: -540px 0px}
.dojoE2TBIcon_Save { background-position: -558px 0px}
.dojoE2TBIcon_Space { background-position: -576px 0px}
.dojoE2TBIcon_StrikeThrough { background-position: -594px 0px}
.dojoE2TBIcon_Subscript { background-position: -612px 0px}
.dojoE2TBIcon_Superscript { background-position: -630px 0px}
.dojoE2TBIcon_Underline { background-position: -648px 0px}
.dojoE2TBIcon_Undo { background-position: -666px 0px}
.dojoE2TBIcon_WikiWord { background-position: -684px 0px}


__CPAN_FILE__ src/widget/templates/ValidationTextbox.html
<span style='float:${this.htmlfloat};'>
	<input dojoAttachPoint='textbox' type='${this.type}' dojoAttachEvent='onblur;onfocus;onkeyup'
		id='${this.widgetId}' name='${this.name}' size='${this.size}' maxlength='${this.maxlength}'
		value='${this.value}' class='${this.className}' style=''>
	<span dojoAttachPoint='invalidSpan' class='${this.invalidClass}'>${this.messages.invalidMessage}</span>
	<span dojoAttachPoint='missingSpan' class='${this.missingClass}'>${this.messages.missingMessage}</span>
	<span dojoAttachPoint='rangeSpan' class='${this.rangeClass}'>${this.messages.rangeMessage}</span>
</span>

__CPAN_FILE__ src/widget/templates/ShowSlide.css
.dojoShowSlideTitle {
	height: 100px;
	background: #369;
}
.dojoShowSlideTitle h1 {
	margin-top: 0;
	line-height: 100px;
	margin-left: 30px;
}
.dojoShowSlideBody {
	margin: 15px;
}
__CPAN_FILE__ src/widget/templates/Spinner.css
/* inline the table holding the <input> and buttons (method varies by browser) */
.ie .dojoSpinner, .safari .dojoSpinner {
	display: inline;
}

.moz .dojoSpinner {
	display: -moz-inline-box;
}

.opera .dojoSpinner {
	display: inline-table;
}

/* generic stuff for the table */
.dojoSpinner td {
	padding:0px;
	margin:0px;
	vertical-align: middle;
}
table.dojoSpinner {
	border:0px;
	border-spacing:0px;
	line-height:0px;
	padding:0px;
	margin: 0px;
	vertical-align: middle;
}

/* the buttons */
.dojoSpinner img {
	display: block;
	border-width:0px 1px 1px 0px;
	border-style:outset;
}

__CPAN_FILE__ src/widget/templates/Dialog.html
<div id="${this.widgetId}" class="dojoDialog" dojoattachpoint="wrapper">
	<span dojoattachpoint="tabStartOuter" dojoonfocus="trapTabs" dojoonblur="clearTrap"	tabindex="0"></span>
	<span dojoattachpoint="tabStart" dojoonfocus="trapTabs" dojoonblur="clearTrap" tabindex="0"></span>
	<div dojoattachpoint="containerNode" style="position: relative; z-index: 2;"></div>
	<span dojoattachpoint="tabEnd" dojoonfocus="trapTabs" dojoonblur="clearTrap" tabindex="0"></span>
	<span dojoattachpoint="tabEndOuter" dojoonfocus="trapTabs" dojoonblur="clearTrap" tabindex="0"></span>
</div>

__CPAN_FILE__ src/widget/templates/Toaster.css
.dojoToasterClip {
	position: absolute;
	overflow: hidden;
}

.dojoToasterContainer {
	display: block;
	position: absolute;
	width: 17.5em;
	z-index: 5000;
	margin: 0px;
	font:0.75em Tahoma, Helvetica, Verdana, Arial;
}

.dojoToasterContent{
	padding:1em;
	padding-top:0.25em;
	background:#73c74a;
}

.dojoToasterMessage{ 
	color:#fff;
}
.dojoToasterWarning{ }
.dojoToasterError,
.dojoToasterFatal{
	font-weight:bold;
	color:#fff;
}


.dojoToasterWarning .dojoToasterContent{
	padding:1em;
	padding-top:0.25em;
	background:#d4d943;
} 

.dojoToasterError .dojoToasterContent{
	padding:1em;
	padding-top:0.25em;
	background:#c46600;
} 

__CPAN_FILE__ src/widget/templates/TimePicker.css
/*Time Picker */
.timePickerContainer {
	width:122px;
	font-family:Tahoma, Myriad, Helvetica, Arial, Verdana, sans-serif;
	font-size:16px;
}

.timeContainer {
	border-collapse:collapse;
	border-spacing:0;
}

.timeContainer thead {
	color:#293a4b;
	font-size:0.9em;
	font-weight:700;
}

.timeContainer thead td {
	padding:0.25em;
	font-size:0.80em;
	border-bottom:1px solid #6782A8;
}

.timeCorner {
	width:10px;
}

.cornerTopLeft {
	background: url("images/dpCurveTL.png") top left no-repeat;
}

.cornerTopRight {
	background: url("images/dpCurveTR.png") top right no-repeat;
}

.timeLabelContainer {
	background: url("images/dpMonthBg.png") top left repeat-x;
}

.hours, .minutes, .timeBorder {
	background: #7591bc url("images/dpBg.gif") top left repeat-x;

}

.hours td, .minutes td {
	padding:0.2em;
	text-align:center;
	font-size:0.7em;
	font-weight:bold;
	cursor:pointer;
	cursor:hand;
	color:#fff;
}

.minutes {
	border-left:1px solid #f5d1db;
}

.hours {
	border-right:1px solid #6782A8;
}

.hourSelector {
	border-right:1px solid #6782A8;
	padding:5px;
	padding-right:10px;
}

.minutesSelector {
	padding:5px;
	border-left:1px solid #f5c7d4;
	text-align:center;
}

.minutesHeading {
	padding-left:9px !important;
}

.timeOptions {
	background-color:#F9C9D7;
}

.timeContainer .cornerBottomLeft, .timeContainer .cornerBottomRight, .timeContainer .timeOptions {
	border-top:1px solid #6782A8;
}

.timeContainer .cornerBottomLeft {
	background: url("images/dpCurveBL.png") bottom left no-repeat !important;
	width:9px !important;
	padding:0;
	margin:0;
}

.timeContainer .cornerBottomRight {
	background: url("images/dpCurveBR.png") bottom right no-repeat !important;
	width:9px !important;
	padding:0;
	margin:0;
}

.timeOptions {
	color:#fff;
	background:url("images/dpYearBg.png") top left repeat-x;

}

.selectedItem {
	background-color:#fff;
	color:#6782a8 !important;
}

.timeOptions .selectedItem {
	color:#fff !important;
	background-color:#9ec3fb !important;
}

.anyTimeContainer {
	text-align:center;
	font-weight:bold;
	font-size:0.7em;
	padding:0.1em;
	cursor:pointer;
	cursor:hand;
	color:#fff !important;
}

.amPmContainer {
	width:100%;
}

.amPmContainer td {
	text-align:center;
	font-size:0.7em;
	font-weight:bold;
	cursor:pointer;
	cursor:hand;
	color:#fff;
}



/*.timePickerContainer {
	margin:1.75em 0 0.5em 0;
	width:10em;
	float:left;
}

.timeContainer {
	border-collapse:collapse;
	border-spacing:0;
}

.timeContainer thead td{
	border-bottom:1px solid #e6e6e6;
	padding:0 0.4em 0.2em 0.4em;
}

.timeContainer td {
	font-size:0.9em;
	padding:0 0.25em 0 0.25em;
	text-align:left;
	cursor:pointer;cursor:hand;
}

.timeContainer td.minutesHeading {
	border-left:1px solid #e6e6e6;
	border-right:1px solid #e6e6e6;	
}

.timeContainer .minutes {
	border-left:1px solid #e6e6e6;
	border-right:1px solid #e6e6e6;
}

.selectedItem {
	background-color:#3a3a3a;
	color:#ffffff;
}*/

__CPAN_FILE__ src/widget/templates/ComboBox.css
.dojoComboBoxOuter {
	border: 0px !important;
	margin: 0px !important;
	padding: 0px !important;
	background: transparent !important;
	white-space: nowrap !important;
}

.dojoComboBox {
	border: 1px inset #afafaf;
	margin: 0px;
	padding: 0px;
	vertical-align: middle !important;
	float: none !important;
	position: static !important;
	display: inline !important;
}

/* the input box */
input.dojoComboBox {
	border-right-width: 0px !important; 
	margin-right: 0px !important;
	padding-right: 0px !important;
}

/* the down arrow */
img.dojoComboBox {
	border-left-width: 0px !important;
	padding-left: 0px !important;
	margin-left: 0px !important;
}

/* IE vertical-alignment calculations can be off by +-1 but these margins are collapsed away */
.dj_ie img.dojoComboBox {
	margin-top: 1px; 
	margin-bottom: 1px; 
}

/* the drop down */
.dojoComboBoxOptions {
	font-family: Verdana, Helvetica, Garamond, sans-serif;
	/* font-size: 0.7em; */
	background-color: white;
	border: 1px solid #afafaf;
	position: absolute;
	z-index: 1000; 
	overflow: auto;
	cursor: default;
}

.dojoComboBoxItem {
	padding-left: 2px;
	padding-top: 2px;
	margin: 0px;
}

.dojoComboBoxItemEven {
	background-color: #f4f4f4;
}

.dojoComboBoxItemOdd {
	background-color: white;
}

.dojoComboBoxItemHighlight {
	background-color: #63709A;
	color: white;
}

__CPAN_FILE__ src/widget/templates/TabContainer.html
<div id="${this.widgetId}" class="dojoTabContainer">
	<div dojoAttachPoint="tablistNode"></div>
	<div class="dojoTabPaneWrapper" dojoAttachPoint="containerNode" dojoAttachEvent="onKey" waiRole="tabpanel"></div>
</div>

__CPAN_FILE__ src/widget/templates/richtextframe.html
<!-- <?xml version="1.0" encoding="UTF-8"?> -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
	"DTD/xhtml1-strict.dtd">
<html>
	<head>
		<title></title>
		<script type="text/javascript">
			function init(){
				document.designMode = 'on';
				try{
					parentPageDomain = document.location.href.split('#')[1];
					if(parentPageDomain){
						document.domain = parentPageDomain;
					}
				}catch(e){ }
			}
			window.onload = init;
		</script>
	</head>
	<body>
		<br />
	</body>
</html>

__CPAN_FILE__ src/widget/templates/AccordionPane.html
<div dojoAttachPoint="domNode">
<div dojoAttachPoint="labelNode" dojoAttachEvent="onclick: onLabelClick" class="${this.labelNodeClass}">${this.label}</div>
<div dojoAttachPoint="containerNode" style="overflow: hidden;" class="${this.containerNodeClass}"></div>
</div>

__CPAN_FILE__ src/widget/templates/TimePicker.html
<div class="timePickerContainer" dojoAttachPoint="timePickerContainerNode">
	<table class="timeContainer" cellspacing="0" >
		<thead>
			<tr>
				<td class="timeCorner cornerTopLeft" valign="top">&nbsp;</td>
				<td class="timeLabelContainer hourSelector">${this.calendar.field-hour}</td>
				<td class="timeLabelContainer minutesHeading">${this.calendar.field-minute}</td>
				<td class="timeCorner cornerTopRight" valign="top">&nbsp;</td>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td valign="top" colspan="2" class="hours">
					<table align="center">
						<tbody dojoAttachPoint="hourContainerNode"  
							dojoAttachEvent="onClick: onSetSelectedHour;">
							<tr>
								<td>12</td>
								<td>6</td>
							</tr>
							<tr>
								<td>1</td>
								<td>7</td>
							</tr>
							<tr>
								<td>2</td>
								<td>8</td>
							</tr>
							<tr>
								<td>3</td>
								<td>9</td>
							</tr>
							<tr>
								<td>4</td>
								<td>10</td>
							</tr>
							<tr>
								<td>5</td>
								<td>11</td>
							</tr>
						</tbody>
					</table>
				</td>
				<td valign="top" class="minutes" colspan="2">
					<table align="center">
						<tbody dojoAttachPoint="minuteContainerNode" 
							dojoAttachEvent="onClick: onSetSelectedMinute;">
							<tr>
								<td>00</td>
								<td>30</td>
							</tr>
							<tr>
								<td>05</td>
								<td>35</td>
							</tr>
							<tr>
								<td>10</td>
								<td>40</td>
							</tr>
							<tr>
								<td>15</td>
								<td>45</td>
							</tr>
							<tr>
								<td>20</td>
								<td>50</td>
							</tr>
							<tr>
								<td>25</td>
								<td>55</td>
							</tr>
						</tbody>
					</table>
				</td>
			</tr>
			<tr>
				<td class="cornerBottomLeft">&nbsp;</td>
				<td valign="top" class="timeOptions">
					<table class="amPmContainer">
						<tbody dojoAttachPoint="amPmContainerNode" 
							dojoAttachEvent="onClick: onSetSelectedAmPm;">
							<tr>
								<td id="am">${this.calendar.am}</td>
								<td id="pm">${this.calendar.pm}</td>
							</tr>
						</tbody>
					</table>
				</td>
				<td class="timeOptions">
					<div dojoAttachPoint="anyTimeContainerNode" 
						dojoAttachEvent="onClick: onSetSelectedAnyTime;" 
						class="anyTimeContainer">${this.widgetStrings.any}</div>
				</td>
				<td class="cornerBottomRight">&nbsp;</td>
			</tr>
		</tbody>
	</table>
</div>

__CPAN_FILE__ src/widget/templates/CiviCrmDatePicker.html
<table cellpadding="0" cellspacing="0" border="0" width="400">
	<tr>
		<td id="dateHolderTd" width="200">
		</td>
		<td id="timeHolderTd" width="200">
		</td>
	</tr>
	<tr style="display: none;" id="formItemsTr">
		<td id="formItemsTd">&nbsp;</td>
		<td>&nbsp;</td>
	</tr>
</table>

__CPAN_FILE__ src/widget/templates/FloatingPane.css

/********** Outer Window ***************/

.dojoFloatingPane {
	/* essential css */
	position: absolute;
	overflow: visible;		/* so drop shadow is displayed */
	z-index: 10;

	/* styling css */
	border: 1px solid;
	border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
	background-color: ThreeDFace;
}


/********** Title Bar ****************/

.dojoFloatingPaneTitleBar {
	vertical-align: top;
	margin: 2px 2px 2px 2px;
	z-index: 10;
	background-color: #7596c6;
	cursor: default;
	overflow: hidden;
	border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
	vertical-align: middle;
}

.dojoFloatingPaneTitleText {
	float: left;
	padding: 2px 4px 2px 2px;
	white-space: nowrap;
	color: CaptionText;
	font: small-caption;
}

.dojoTitleBarIcon {
	float: left;
	height: 22px;
	width: 22px;
	vertical-align: middle;
	margin-right: 5px;
	margin-left: 5px;
}

.dojoFloatingPaneActions{
	float: right;
	position: absolute;
	right: 2px;
	top: 2px;
	vertical-align: middle;
}


.dojoFloatingPaneActionItem {
	vertical-align: middle;
	margin-right: 1px;
	height: 22px;
	width: 22px;
}


.dojoFloatingPaneTitleBarIcon {
	/* essential css */
	float: left;

	/* styling css */
	margin-left: 2px;
	margin-right: 4px;
	height: 22px;
}

/* minimize/maximize icons are specified by CSS only */
.dojoFloatingPaneMinimizeIcon,
.dojoFloatingPaneMaximizeIcon,
.dojoFloatingPaneRestoreIcon,
.dojoFloatingPaneCloseIcon {
	vertical-align: middle;
	height: 22px;
	width: 22px;
	float: right;
}
.dojoFloatingPaneMinimizeIcon {
	background-image: url(images/floatingPaneMinimize.gif);
}
.dojoFloatingPaneMaximizeIcon {
	background-image: url(images/floatingPaneMaximize.gif);
}
.dojoFloatingPaneRestoreIcon {
	background-image: url(images/floatingPaneRestore.gif);
}
.dojoFloatingPaneCloseIcon {
	background-image: url(images/floatingPaneClose.gif);
}

/* bar at bottom of window that holds resize handle */
.dojoFloatingPaneResizebar {
	z-index: 10;
	height: 13px;
	background-color: ThreeDFace;
}

/************* Client Area ***************/

.dojoFloatingPaneClient {
	position: relative;
	z-index: 10;
	border: 1px solid;
	border-color: ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow;
	margin: 2px;
	background-color: ThreeDFace;
	padding: 8px;
	font-family: Verdana, Helvetica, Garamond, sans-serif;
	font-size: 12px;
	overflow: auto;
}


__CPAN_FILE__ src/widget/templates/ResizableTextarea.css
div.statusBar {
	background-color: ThreeDFace;
	height: 28px;
	padding: 1px;
	overflow: hidden;
	font-size: 12px;
}

div.statusPanel {
	background-color: ThreeDFace;
	border: 1px solid;
	border-color: ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow;
	margin: 1px;
	padding: 2px 6px;
}

__CPAN_FILE__ src/widget/templates/ProgressBar.html
<div dojoAttachPoint="containerNode" style="position:relative;overflow:hidden">
	<div style="position:absolute;display:none;width:100%;text-align:center" dojoAttachPoint="backPercentLabel" class="dojoBackPercentLabel"></div>
	<div style="position:absolute;overflow:hidden;width:100%;height:100%" dojoAttachPoint="internalProgress">
	<div style="position:absolute;display:none;width:100%;text-align:center" dojoAttachPoint="frontPercentLabel" class="dojoFrontPercentLabel"></div></div>
</div>

__CPAN_FILE__ src/widget/templates/ResizeHandle.css
.dojoHtmlResizeHandle {
	float: right;
	position: absolute;
	right: 2px;
	bottom: 2px;
	width: 13px;
	height: 13px;
	z-index: 20;
	cursor: nw-resize;
	background-image: url(grabCorner.gif);
	line-height: 0px;
}
__CPAN_FILE__ src/widget/templates/check.gif
GIF89a`÷ÿÿÿýûÿªµÐ„—¼…”³‚šÄƒ›Å…�Ç¤Áó­Êü¦¾é´Ìø`x¡†¨Þˆªà‹­ãz—Æ~›Ë€�ÍœÌ}šÉl„­˜ºñ—¹ïœ¾õuŽ· Âù¦Èÿz“¼}–¿|•¾�ºë«ÈùªÇø©Æ÷o’Æt—Ìg…³~¡Öƒ¦Û…§Ü�²è�³ésœÖˆ£Ç‡¢Æ­Íø¥Áæ§Ãè‰ ¾©Äé°ÌñŽ¥Ã·Óø´Ðõ»×ü¹Õú¾Úÿ½Ùþ¼Øý ·Ö¨ÀßªÂá©Áà³Ëê”§Àš­ÆÇÞþÆÝýÅÜüÐäþzšÃ~ŸÇœÂñ¦Ìü�­Ö©Ïÿ¤Åï¡Âë§Èò¦Çñ¥Æð�©Ì’®Ò®ÏùŸ»ßžºÞ›·Ú‚™¶£¿ã¢¾â†�º­Éí¬Èì«Çë®Êî–®ÌÉáÿÊâÿºÎçÒæÿ¤´Ç·ÇÚ¶ÆÙµÅØÀÐãÑáõØèü×çûÏÛêâîýÈÔâ×ãñÝé÷íöÿàéñëôüêóûãìôâëóáêòöûþõúýôùüîóöêïò÷ýÿçíïøþÿ¾Á½ËÎÊ•—”‘“���Œ½¿¼¼¾»»½º¹»¸·¹¶µ·´³µ²«­ª¥§¤¤¦£¢¤¡ ¢Ÿž �ûýúúüùùûøøú÷÷ùöóõòòôññóððòïïñîîðíêìéçéææèåÝßÜÚÜÙÖØÕÔÖÓÓÕÒÒÔÑÑÓÐÐÒÏÏÑÎÊÌÉÉËÈÈÊÇÇÉÆÆÈÅÅÇÄÄÆÃÂÄÁ›�™ÁÃ¿ÀÂ¾°²®ÎÐÌþÿüÿÿÿ!ù¹,`ÿ=H° Áƒo)\È°¡Ã‡JœX‰”‹3J�ÂJ$PBŠ	%J)IT‘ZÉ²%©Q~F©Ré²æJU5jäè1§N�I<,P¢¨Ñ¢h�ÀÃ\P£JÅ%ÌU£àÌT¥u&œTJÍÌºµ+×­n	#¦­Û¶m”N9°ö­Ý¶(DðÂ¡¯_Mšü	Ä§À`¦*ÆE#I«R¯´¶‚%ù–€J&©zy3åÍ­\m65("¨S£.#×ŸIL«ž�úKl/Krçæ°�ƒ¨|²4}ºªJA¨2zæ+ÑªúP i&sèÏËºTJU„´QÏÿ�ª‡‚ïágÏ@`1ƒ{÷JFÈiMÇE–$ˆ/¦TÉÒŒ$°˜â
®´ÒŠ*¯ø�%~<É+èŠh‘½áL§¼òá½ fpñ‡é¥fÕ_(¡¢``TxÁçu±˜RJùw€+×q¦(Ê,‘ÀñÜu­ÀËsIÆY*­|0ƒFA•l@å‡ÐØÁ”T†)¦F€qÞ00Ç (1^tÂl8%Xb	&™`ò€§ðØÇ'±À‚	ž’LË-®À(„±L¡…°À‚Š+0°ÃÔ�ƒÇ	0D9@Q§¦;¤ªê<ð Lÿ€Dk,ˆ‹F@Uƒ*\{1H%À%z\Â§&Ä@Á�¡LgŠ(:Bˆ p¬òÊ�?
’-Úr‚_¾¡.n°VÉ5Ü€ƒH™FÀ/:Ð›ÃçÍB­	€‰hX�Â
*<AA@…g%{d"@wòÃ²ÜòJ³ÓQG!ŒR‹*±Tìq-‚2²Ç²¤²P8ÜU%¸À!Ã9Ø�W¦®2ð©Î;àÀCÍy9ÁiP…K ¡B
*ÀpOàyÉž˜h¢	'œlÒ«"ˆ"ªØ
Š!�R2µ|löÚl›}ˆ*´8Å@p}‡0�Ã
_ÿðå
@ã`ó»ïÚÐw¦$Þƒ¸`
(¤€ÂIHyd’‰&›lÂIžQÁ!p‚H"²X‚$B rˆé¬ÐB:"i¼nûí‰À�)(@Fk´ ï¼WNüñÈÿÁ,°pÂ	TœÑ@	Ï³€BDƒ%—h.€Ÿwâ‰'~aÀ"­ â:"b‹"ê#Ç"è+’íŠ¤üŠÌÿ�xA^8à	½+Ê(°¡¯wÄS€—°@$Ì z%`	LÐ<ç±@Hðü¥‰>dÍä_'|€„EÀ"
ñC„-$‘¿Ó)BŠhDélˆˆæ/Šˆ…"Å�°€%e!XB`ÄÜ@	ÚcbuÓD<1NXÀ 0ƒD!_€ÂÀ€Ãm@ã€…5b��V�@#d!n¡
mtD[¥a‹:R«!«ã!êHF1$R#°1vqˆ@fÐHJ2r—ì"]<ED` ŸD:Q~ èÀ<°ÊT~`•¥´…#fIKGÈr–¶Èå-i™ËZâ2—ŸH�ð$@ H¦(=IX†0™¥;
__CPAN_FILE__ src/widget/templates/incrementWeek.gif
GIF89aÄÿÿÿ000øøøúúúžžž¶¶¶cccÂÂÂÖÖÖyyyßßß………CCCâââÌÌÌFFFjjjmmmØØØ!ù, ÒäP�QâŒ@¸!�·N’… ;
__CPAN_FILE__ src/widget/templates/DocPane.html
<div class="dojoDocPane">
	<div dojoAttachPoint="containerNode" class="container"></div>

	<div dojoAttachPoint="dialog" class="dialog">
		<div class="container" dojoAttachPoint="dialogBg">
			<div class="docDialog" dojoAttachPoint="dialogFg">
				<h2>Log In</h2>
				<p><input id="dojoDocUserName" dojoAttachPoint="userName"><label for="dojoDocUserName">User Name:</label></p>
				<p><input id="dojoDocPassword" dojoAttachPoint="password" type="password"><label for="dojoDocPassword">Password:</label></p>
				<p><input type="button" dojoAttachPoint="cancel" value="cancel"> <input type="button" dojoAttachPoint="logIn" value="Log In"></p>
				<p></p>
			</div>
		</div>
	</div>

	<div dojoAttachPoint="nav" class="nav"><span>Detail</span> | <span>Source</span> | <span>Examples</span> | <span>Walkthrough</span></div>

	<div dojoAttachPoint="detail" class="detail">
		<h1>Detail: <span class="fn" dojoAttachPoint="fn">dojo.select</span></h1>
		<div class="description" dojoAttachPoint="description">Description</div>
		<div class="params" dojoAttachPoint="parameters">
			<h2>Parameters</h2>
			<div class="row" dojoAttachPoint="pRow">
				<span dojoAttachPoint="pOpt"><em>optional</em> </span>
				<span><span dojoAttachPoint="pType">type</span> </span>
				<a href="#" dojoAttachPoint="pLink">variable</a>
				<span> - <span dojoAttachPoint="pDesc"></span></span>
			</div>
		</div>
		<div class="variables" dojoAttachPoint="variables">
			<h2>Variables</h2>
			<div class"row" dojoAttachPoint="vRow">
				<a href="#" dojoAttachPoint="vLink">variable</a><span> - <span dojoAttachPoint="vDesc"></span></span>
			</div>
		</div>
		<div class="signature">
			<h2>Signature</h2>
			<div class="source">
				<span class="return" dojoAttachPoint="sType">returnType</span> 
				<span class="function" dojoAttachPoint="sName">foo</span>
				(<span class="params" dojoAttachPoint="sParams">
					<span class="type" dojoAttachPoint="sPType">type </span>
					<span class="name" dojoAttachPoint="sPName">paramName</span>
				</span>)
			</div>
		</div>
	</div>
	
	<div dojoAttachPoint="result" class="result">
		<h1>Search Results: <span dojoAttachPoint="count">0</span> matches</h1>
		<div class="row" dojoAttachPoint="row">
			<a href="#" dojoAttachPoint="fnLink">dojo.fnLink</a>
			<span> - <span class="summary" dojoAttachPoint="summary">summary</span></span>
		</div>
	</div>

	<div dojoAttachPoint="packag" class="package">
		<h1>Package: 
			<span class="pkg" dojoAttachPoint="pkg">dojo.package</span> 
			<span class="edit" dojoAttachPoint="edit">[edit]</span> 
			<span class="save" dojoAttachPoint="save">[save]</span>
		</h1>
		<div dojoAttachPoint="pkgDescription" class="description">Description</div>
		<div class="methods" dojoAttachPoint="methods">
			<h2>Methods</h2>
			<div class="row" dojoAttachPoint="mRow">
				<a href="#" dojoAttachPoint="mLink">method</a>
				<span> - <span class="description" dojoAttachPoint="mDesc"></span></span>
			</div>
		</div>
		<div class="requires" dojoAttachPoint="requires">
			<h2>Requires</h2>
			<div class="row" dojoAttachPoint="rRow">
				<h3 dojoAttachPoint="rH3">Environment</h3>
				<div dojoAttachPoint="rRow2"><a href="#" dojoAttachPoint="rLink" class="package">require</a></div>
			</div>
		</div>
	</div>
</div>

__CPAN_FILE__ src/widget/templates/EditorToolbarOneline.html
<div class="EditorToolbarDomNode EditorToolbarSmallBg">
	<table cellpadding="1" cellspacing="0" border="0">
		<tbody>
			<tr valign="top" align="left">
				<td>
					<!-- htmltoggle -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="htmltoggle">
						<span title="Toggle Rich Text and HTML Markup Editing Modes" class="dojoE2TBIcon" 
						style="background-image: none; width: 30px;" >&lt;h&gt;</span>
					</span>
				</td>
				<!-- wikiword -->
				<!--td>
					<span class="iconContainer" dojoAttachPoint="wikiwordButton"
						dojoOnClick="wikiwordClick; buttonClick;" style="display: none;">
						<span title="Toggle Wiki Word" class="dojoE2TBIcon dojoE2TBIcon_wikiword" 
						unselectable="on">&nbsp;</span>
					</span>
				</td-->
				<td>
					<!-- copy -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="copy">
						<span title="Copy (Ctrl-C)" class="dojoE2TBIcon dojoE2TBIcon_Copy">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- paste -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="paste">
						<span title="Paste (Ctrl-V)" class="dojoE2TBIcon dojoE2TBIcon_Paste">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- undo -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="undo">
						<!-- FIXME: should we have the text "undo" here? -->
						<span title="Undo (Ctrl-Z)" class="dojoE2TBIcon dojoE2TBIcon_Undo">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- redo -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="redo">
						<span title="Redo (Ctrl-R)" class="dojoE2TBIcon dojoE2TBIcon_Redo">&nbsp;</span>
					</span>
				</td>
				<td isSpacer="true">
					<!-- spacer -->
					<span class="iconContainer">
						<span class="dojoE2TBIcon dojoE2TBIcon_Sep"	style="width: 5px; min-width: 5px;"></span>
					</span>
				</td>
				<td>
					<!-- link -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="createlink">
						<span title="Create Link" class="dojoE2TBIcon dojoE2TBIcon_Link">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- insertimage -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="insertimage">
						<span title="Insert Image" class="dojoE2TBIcon dojoE2TBIcon_Image">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- inserthorizontalrule -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="inserthorizontalrule">
						<span title="Insert Horizontal Rule" class="dojoE2TBIcon dojoE2TBIcon_HorizontalLine ">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- bold -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="bold">
						<span title="Toggle Bold (Ctrl-B)" class="dojoE2TBIcon dojoE2TBIcon_Bold">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- italic -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="italic">
						<span title="Toggle Italic (Ctrl-I)" class="dojoE2TBIcon dojoE2TBIcon_Italic">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- underline -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="underline">
						<span title="Toggle Underline (Ctrl-U)" class="dojoE2TBIcon dojoE2TBIcon_Underline">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- strikethrough -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="strikethrough">
						<span title="Toggle Strike-Through" 
							class="dojoE2TBIcon dojoE2TBIcon_StrikeThrough">&nbsp;</span>
					</span>
				</td>
				<td isSpacer="true">
					<!-- spacer -->
					<span class="iconContainer">
						<span class="dojoE2TBIcon dojoE2TBIcon_Sep" 
							style="width: 5px; min-width: 5px;"></span>
					</span>
				</td>
				<td>
					<!-- insertunorderedlist -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="insertunorderedlist">
						<span title="Insert Bullet List" 
							class="dojoE2TBIcon dojoE2TBIcon_BulletedList">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- insertorderedlist -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="insertorderedlist">
						<span title="Insert Numbered List" 
							class="dojoE2TBIcon dojoE2TBIcon_NumberedList">&nbsp;</span>
					</span>
				</td>
				<td isSpacer="true">
					<!-- spacer -->
					<span class="iconContainer">
						<span class="dojoE2TBIcon dojoE2TBIcon_Sep" style="width: 5px; min-width: 5px;"></span>
					</span>
				</td>
				<td>
					<!-- indent -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="indent">
						<span title="Indent Selection" class="dojoE2TBIcon dojoE2TBIcon_Indent" 
							unselectable="on">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- outdent -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="outdent">
						<span title="Outdent Selection" class="dojoE2TBIcon dojoE2TBIcon_Outdent" 
							unselectable="on">&nbsp;</span>
					</span>
				</td>
				<td isSpacer="true">
					<!-- spacer -->
					<span class="iconContainer">
						<span class="dojoE2TBIcon dojoE2TBIcon_Sep" style="width: 5px; min-width: 5px;"></span>
					</span>
				</td>
				<td>
					<!-- forecolor -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="forecolor">
						<span title="Change Text Color" class="dojoE2TBIcon dojoE2TBIcon_TextColor" 
							unselectable="on">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- hilitecolor -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="hilitecolor">
						<span title="Change Background Color" class="dojoE2TBIcon dojoE2TBIcon_BackgroundColor" 
							unselectable="on">&nbsp;</span>
					</span>
				</td>
				<td isSpacer="true">
					<!-- spacer -->
					<span class="iconContainer">
						<span class="dojoE2TBIcon dojoE2TBIcon_Sep" style="width: 5px; min-width: 5px;"></span>
					</span>
				</td>
				<td>
					<!-- justify left -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="justifyleft">
						<span title="Justify Left" class="dojoE2TBIcon dojoE2TBIcon_LeftJustify">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- justify center -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="justifycenter">
						<span title="Center" class="dojoE2TBIcon dojoE2TBIcon_CenterJustify">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- justify right -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="justifyright">
						<span title="Justify Right" class="dojoE2TBIcon dojoE2TBIcon_RightJustify">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- justify full -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="justifyfull">
						<span title="Justify Both" class="dojoE2TBIcon dojoE2TBIcon_BlockJustify">&nbsp;</span>
					</span>
				</td>	
				<td>
					<!-- font select -->
					<select class="dojoEditorToolbarItem" dojoETItemName="plainformatblock">
						<!-- FIXME: using "p" here inserts a paragraph in most cases! -->
						<option value="">-- format --</option>
						<option value="p">Normal</option>
						<option value="pre">Fixed Font</option>
						<option value="h1">Main Heading</option>
						<option value="h2">Section Heading</option>
						<option value="h3">Sub-Heading</option>
						<!-- <option value="blockquote">Block Quote</option> -->
					</select>
				</td>
				<td><!-- uncomment to enable save button -->
					<!-- save -->
					<!--span class="iconContainer dojoEditorToolbarItem" dojoETItemName="save">
						<span title="Save" class="dojoE2TBIcon dojoE2TBIcon_Save">&nbsp;</span>
					</span-->
				</td>
				<td width="*">&nbsp;</td>
			</tr>
		</tbody>
	</table>
</div>

__CPAN_FILE__ src/widget/templates/ProgressBar.css
.backBar{
	border:1px solid #84a3d1;
}
.frontBar{
	background:url("images/bar.gif") repeat bottom left;
	background-attachment: fixed;
}
.h-frontBar{
	background:url("images/h-bar.gif") repeat bottom left;
	background-attachment: fixed;
}
.simpleFrontBar{
	background: red;
}
.frontPercent,.backPercent{
	font:bold 13px helvetica;
}
.backPercent{
	color:#293a4b;
}
.frontPercent{
	color:#fff;
}
__CPAN_FILE__ src/widget/templates/ComboButtonTemplate.html
<div class="dojoButton" style="position:relative;top:0px;left:0px; text-align:none;" dojoAttachEvent="onKey;onFocus">

	<div dojoAttachPoint="buttonNode" class="dojoButtonLeftPart" style="position:absolute;left:0px;top:0px;"
		dojoAttachEvent="onMouseOver; onMouseOut; onMouseDown; onMouseUp; onClick:buttonClick;">
		<div class="dojoButtonContents" dojoAttachPoint="containerNode" style="position:absolute;top:0px;right:0px;z-index:2;"></div>
		<img dojoAttachPoint="leftImage" style="position:absolute;left:0px;top:0px;">
		<img dojoAttachPoint="centerImage" style="position:absolute;right:0px;top:0px;z-index:1;">
	</div>

	<div dojoAttachPoint="rightPart" class="dojoButtonRightPart" style="position:absolute;top:0px;right:0px;"
		dojoAttachEvent="onMouseOver:rightOver; onMouseOut:rightOut; onMouseDown:rightDown; onMouseUp:rightUp; onClick:rightClick;">
		<img dojoAttachPoint="arrowBackgroundImage" style="position:absolute;top:0px;left:0px;z-index:1;">
		<img src="${dojoRoot}src/widget/templates/images/whiteDownArrow.gif"
		  		style="z-index:2;position:absolute;left:3px;top:50%;">
		<img dojoAttachPoint="rightImage" style="position:absolute;top:0px;right:0px;">
	</div>

</div>

__CPAN_FILE__ src/widget/templates/InlineEditBox.css
.editLabel {
	font-size : small;
	padding : 0 5px;
	display : none;
}

.editableRegionDisabled {
	cursor : pointer;
	_cursor : hand;
}

.editableRegion {
	background-color : #ffc !important;
	cursor : pointer;
	_cursor : hand;
}

.editableRegion .editLabel {
	display : inline;
}

.editableTextareaRegion .editLabel {
	display : block;
}

.inlineEditBox {
	/*background-color : #ffc;*/
	display : inline;
}

__CPAN_FILE__ src/widget/templates/CheckboxA11y.html
<span class='dojoHtmlCheckbox'>
	<input type="checkbox" name="${this.name}" tabIndex="${this.tabIndex}" id="${this.id}" value="${this.value}"
		 dojoAttachEvent="onClick: _onClick;" dojoAttachPoint="inputNode"> 
</span>

__CPAN_FILE__ src/widget/templates/SliderVertical.html
<div class="sliderMainVertical">
    <div class="sliderHandleVertical" dojoAttachPoint="sliderHandle"></div>
</div>

__CPAN_FILE__ src/widget/templates/SplitContainer.css
.dojoSplitContainer{
	position: relative;
	overflow: hidden;
}

.dojoSplitPane{
	position: absolute;
}

.dojoSplitContainerSizerH,
.dojoSplitContainerSizerV {
	font-size: 1px;
	cursor: move;
	cursor: w-resize;
	background-color: ThreeDFace;
	border: 1px solid;
	border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
	margin: 0;
}

.dojoSplitContainerSizerV {
	cursor: n-resize;
}

.dojoSplitContainerVirtualSizerH,
.dojoSplitContainerVirtualSizerV {
	font-size: 1px;
	cursor: move;
	cursor: w-resize;
	background-color: ThreeDShadow;
	-moz-opacity: 0.5;
	opacity: 0.5;
	filter: Alpha(Opacity=50);
	margin: 0;
}

.dojoSplitContainerVirtualSizerV {
	cursor: n-resize;
}

__CPAN_FILE__ src/widget/templates/DatePicker.html
<div class="datePickerContainer" dojoAttachPoint="datePickerContainerNode">
	<table cellspacing="0" cellpadding="0" class="calendarContainer">
		<thead>
			<tr>
				<td class="monthWrapper" valign="top">
					<table class="monthContainer" cellspacing="0" cellpadding="0" border="0">
						<tr>
							<td class="monthCurve monthCurveTL" valign="top"></td>
							<td class="monthLabelContainer" valign="top">
								<span dojoAttachPoint="increaseWeekNode" 
									dojoAttachEvent="onClick: onIncrementWeek;" 
									class="incrementControl increase">
									<img src="${dojoRoot}src/widget/templates/images/incrementMonth.png" 
									alt="&darr;" style="width:7px;height:5px;" />
								</span>
								<span 
									dojoAttachPoint="increaseMonthNode" 
									dojoAttachEvent="onClick: onIncrementMonth;" class="incrementControl increase">
									<img src="${dojoRoot}src/widget/templates/images/incrementMonth.png" 
										alt="&darr;"  dojoAttachPoint="incrementMonthImageNode">
								</span>
								<span 
									dojoAttachPoint="decreaseWeekNode" 
									dojoAttachEvent="onClick: onIncrementWeek;" 
									class="incrementControl decrease">
									<img src="${dojoRoot}src/widget/templates/images/decrementMonth.png" alt="&uarr;" style="width:7px;height:5px;" />
								</span>
								<span 
									dojoAttachPoint="decreaseMonthNode" 
									dojoAttachEvent="onClick: onIncrementMonth;" class="incrementControl decrease">
									<img src="${dojoRoot}src/widget/templates/images/decrementMonth.png" 
										alt="&uarr;" dojoAttachPoint="decrementMonthImageNode">
								</span>
								<span dojoAttachPoint="monthLabelNode" class="month"></span>
							</td>
							<td class="monthCurve monthCurveTR" valign="top"></td>
						</tr>
					</table>
				</td>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td colspan="3">
					<table class="calendarBodyContainer" cellspacing="0" cellpadding="0" border="0">
						<thead>
							<tr dojoAttachPoint="dayLabelsRow">
								<td></td>
								<td></td>
								<td></td>
								<td></td>
								<td></td>
								<td></td>
								<td></td>
							</tr>
						</thead>
						<tbody dojoAttachPoint="calendarDatesContainerNode" 
							dojoAttachEvent="onClick: _handleUiClick;">
							<tr dojoAttachPoint="calendarWeekTemplate">
								<td></td>
								<td></td>
								<td></td>
								<td></td>
								<td></td>
								<td></td>
								<td></td>
							</tr>
						</tbody>
					</table>
				</td>
			</tr>
		</tbody>
		<tfoot>
			<tr>
				<td colspan="3" class="yearWrapper">
					<table cellspacing="0" cellpadding="0" border="0" class="yearContainer">
						<tr>
							<td class="curveBL" valign="top"></td>
							<td valign="top">
								<h3 class="yearLabel">
									<span dojoAttachPoint="previousYearLabelNode"
										dojoAttachEvent="onClick: onIncrementYear;" class="previousYear"></span>
									<span class="selectedYear" dojoAttachPoint="currentYearLabelNode"></span>
									<span dojoAttachPoint="nextYearLabelNode" 
										dojoAttachEvent="onClick: onIncrementYear;" class="nextYear"></span>
								</h3>
							</td>
							<td class="curveBR" valign="top"></td>
						</tr>
					</table>
				</td>
			</tr>
		</tfoot>
	</table>
	
</div>

__CPAN_FILE__ src/widget/templates/Textbox.html
<span style='float:${this.htmlfloat};'>
	<input dojoAttachPoint='textbox' dojoAttachEvent='onblur;onfocus'
		id='${this.widgetId}' name='${this.name}'
		value='${this.value}' class='${this.className}' type='${this.type}' >
</span>

__CPAN_FILE__ src/widget/templates/ShowSlide.html
<div class="dojoShowSlide">
	<div class="dojoShowSlideTitle">
		<h1 dojoAttachPoint="htmlTitle">Title</h1>
	</div>
	<div class="dojoShowSlideBody" dojoAttachPoint="containerNode"></div>
</div>
__CPAN_FILE__ src/widget/templates/TaskBarItemTemplate.html
<div class="dojoTaskBarItem" dojoAttachEvent="onClick">
</div>
__CPAN_FILE__ src/widget/templates/EditorToolbar.html
<div dojoAttachPoint="domNode" class="EditorToolbarDomNode" unselectable="on">
	<table cellpadding="3" cellspacing="0" border="0">
		<!--
			our toolbar should look something like:

			+=======+=======+=======+=============================================+
			| w   w | style | copy  | bo | it | un | le | ce | ri |
			| w w w | style |=======|==============|==============|
			|  w w  | style | paste |  undo | redo | change style |
			+=======+=======+=======+=============================================+
		-->
		<tbody>
			<tr valign="top">
				<td rowspan="2">
					<div class="bigIcon" dojoAttachPoint="wikiWordButton"
						dojoOnClick="wikiWordClick; buttonClick;">
						<span style="font-size: 30px; margin-left: 5px;">
							W
						</span>
					</div>
				</td>
				<td rowspan="2">
					<div class="bigIcon" dojoAttachPoint="styleDropdownButton"
						dojoOnClick="styleDropdownClick; buttonClick;">
						<span unselectable="on"
							style="font-size: 30px; margin-left: 5px;">
							S
						</span>
					</div>
					<div class="StyleDropdownContainer" style="display: none;"
						dojoAttachPoint="styleDropdownContainer">
						<table cellpadding="0" cellspacing="0" border="0"
							height="100%" width="100%">
							<tr valign="top">
								<td rowspan="2">
									<div style="height: 245px; overflow: auto;">
										<div class="headingContainer"
											unselectable="on"
											dojoOnClick="normalTextClick">normal</div>
										<h1 class="headingContainer"
											unselectable="on"
											dojoOnClick="h1TextClick">Heading 1</h1>
										<h2 class="headingContainer"
											unselectable="on"
											dojoOnClick="h2TextClick">Heading 2</h2>
										<h3 class="headingContainer"
											unselectable="on"
											dojoOnClick="h3TextClick">Heading 3</h3>
										<h4 class="headingContainer"
											unselectable="on"
											dojoOnClick="h4TextClick">Heading 4</h4>
										<div class="headingContainer"
											unselectable="on"
											dojoOnClick="blahTextClick">blah</div>
										<div class="headingContainer"
											unselectable="on"
											dojoOnClick="blahTextClick">blah</div>
										<div class="headingContainer"
											unselectable="on"
											dojoOnClick="blahTextClick">blah</div>
										<div class="headingContainer">blah</div>
										<div class="headingContainer">blah</div>
										<div class="headingContainer">blah</div>
										<div class="headingContainer">blah</div>
									</div>
								</td>
								<!--
								<td>
									<span class="iconContainer" dojoOnClick="buttonClick;">
										<span class="icon justifyleft" 
											style="float: left;">&nbsp;</span>
									</span>
									<span class="iconContainer" dojoOnClick="buttonClick;">
										<span class="icon justifycenter" 
											style="float: left;">&nbsp;</span>
									</span>
									<span class="iconContainer" dojoOnClick="buttonClick;">
										<span class="icon justifyright" 
											style="float: left;">&nbsp;</span>
									</span>
									<span class="iconContainer" dojoOnClick="buttonClick;">
										<span class="icon justifyfull" 
											style="float: left;">&nbsp;</span>
									</span>
								</td>
								-->
							</tr>
							<tr valign="top">
								<td>
									thud
								</td>
							</tr>
						</table>
					</div>
				</td>
				<td>
					<!-- copy -->
					<span class="iconContainer" dojoAttachPoint="copyButton"
						unselectable="on"
						dojoOnClick="copyClick; buttonClick;">
						<span class="icon copy" 
							unselectable="on"
							style="float: left;">&nbsp;</span> copy
					</span>
					<!-- "droppable" options -->
					<span class="iconContainer" dojoAttachPoint="boldButton"
						unselectable="on"
						dojoOnClick="boldClick; buttonClick;">
						<span class="icon bold" unselectable="on">&nbsp;</span>
					</span>
					<span class="iconContainer" dojoAttachPoint="italicButton"
						dojoOnClick="italicClick; buttonClick;">
						<span class="icon italic" unselectable="on">&nbsp;</span>
					</span>
					<span class="iconContainer" dojoAttachPoint="underlineButton"
						dojoOnClick="underlineClick; buttonClick;">
						<span class="icon underline" unselectable="on">&nbsp;</span>
					</span>
					<span class="iconContainer" dojoAttachPoint="leftButton"
						dojoOnClick="leftClick; buttonClick;">
						<span class="icon justifyleft" unselectable="on">&nbsp;</span>
					</span>
					<span class="iconContainer" dojoAttachPoint="fullButton"
						dojoOnClick="fullClick; buttonClick;">
						<span class="icon justifyfull" unselectable="on">&nbsp;</span>
					</span>
					<span class="iconContainer" dojoAttachPoint="rightButton"
						dojoOnClick="rightClick; buttonClick;">
						<span class="icon justifyright" unselectable="on">&nbsp;</span>
					</span>
				</td>
			</tr>
			<tr>
				<td>
					<!-- paste -->
					<span class="iconContainer" dojoAttachPoint="pasteButton"
						dojoOnClick="pasteClick; buttonClick;" unselectable="on">
						<span class="icon paste" style="float: left;" unselectable="on">&nbsp;</span> paste
					</span>
					<!-- "droppable" options -->
					<span class="iconContainer" dojoAttachPoint="undoButton"
						dojoOnClick="undoClick; buttonClick;" unselectable="on">
						<span class="icon undo" style="float: left;" unselectable="on">&nbsp;</span> undo
					</span>
					<span class="iconContainer" dojoAttachPoint="redoButton"
						dojoOnClick="redoClick; buttonClick;" unselectable="on">
						<span class="icon redo" style="float: left;" unselectable="on">&nbsp;</span> redo
					</span>
				</td>	
			</tr>
		</tbody>
	</table>

__CPAN_FILE__ src/widget/templates/FisheyeList.css
.dojoHtmlFisheyeListItemLabel {
	font-family: Arial, Helvetica, sans-serif;
	background-color: #eee;
	border: 2px solid #666;
	padding: 2px;
	text-align: center;
	position: absolute;
	display: none;
}

.dojoHtmlFisheyeListItemLabel.selected {
	display: block;
}

.dojoHtmlFisheyeListItemImage {
	border: 0px;
	position: absolute;
}

.dojoHtmlFisheyeListItem {
	position: absolute;
	z-index: 2;
}

.dojoHtmlFisheyeListBar {
	position: relative;
}

__CPAN_FILE__ src/widget/templates/TaskBar.css
.dojoTaskBarItem {
	display: inline-block;
	background-color: ThreeDFace;
	border: outset 2px;
	margin-right: 5px;
	cursor: pointer;
	height: 35px;
	width: 100px;
	font-size: 10pt;
	white-space: nowrap;
	text-align: center;
	float: left;
	overflow: hidden;
}

.dojoTaskBarItem img {
	vertical-align: middle;
	margin-right: 5px;
	margin-left: 5px;	
	height: 32px;
	width: 32px;
}

.dojoTaskBarItem a {
	 color: black;
	text-decoration: none;
}



__CPAN_FILE__ src/widget/templates/TitlePane.html
<div dojoAttachPoint="domNode">
<div dojoAttachPoint="labelNode" dojoAttachEvent="onclick: onLabelClick"></div>
<div dojoAttachPoint="containerNode"></div>
</div>

__CPAN_FILE__ src/widget/templates/Slider.css
.sliderMain {
  border: 0px !important;
  border-spacing: 0px !important;
  line-height: 0px !important;
  padding: 0px !important;
  display: -moz-inline-table !important;
  display: inline !important;
  -moz-user-focus: normal !important;
}

.sliderComponent {
  border: 0px;
  padding: 0px;
  margin: 0px;
}

.sliderHandle { 
  top: 0px;
  left: 0px;
  z-index: 1000;
  position: absolute !important;
}

.sliderOutsetButton { 
  border-style: outset;
  border-width: 0px 1px 1px 0px;
  border-color: black;
}

.sliderInsetButton { 
  border-style: inset;
  border-width: 1px 0px 0px 1px;
  border-color: black;
}

.sliderButtonY {
  margin: 0px;
  padding: 0px;
  z-index: 900;
}

.sliderButtonX {
  margin: 0px;
  padding: 0px;
  z-index: 900;
}

.sliderBackground { 
  z-index: 0;
  display: block !important;
  position: relative !important;
}

.sliderProgressBackground { 
  z-index: 800;
  position: absolute !important;
  clip: rect(0px,0px,0px,0px);
}

.sliderBackgroundSizeOnly { 
}
__CPAN_FILE__ src/widget/templates/Validate.css
.dojoValidateEmpty{
	background-color: #00FFFF;
}
.dojoValidateValid{
	background-color: #cfc;
}
.dojoValidateInvalid{
	background-color: #fcc;
}
.dojoValidateRange{
	background-color: #ccf;
}
__CPAN_FILE__ src/widget/templates/Toolbar.css
.toolbarContainer {
	border-bottom : 0;
	background-color : #def;
	color : ButtonText;
	font : Menu;
	background-image: url(images/toolbar-bg.gif);
}

.toolbar {
	padding : 2px 4px;
	min-height : 26px;
	_height : 26px;
}

.toolbarItem {
	float : left;
	padding : 1px 2px;
	margin : 0 2px 1px 0;
	cursor : pointer;
}

.toolbarItem.selected, .toolbarItem.down {
	margin : 1px 1px 0 1px;
	padding : 0px 1px;
	border : 1px solid #bbf;
	background-color : #fafaff;
}

.toolbarButton img {
	vertical-align : bottom;
}

.toolbarButton span {
	line-height : 16px;
	vertical-align : middle;
}

.toolbarButton.hover {
	padding : 0px 1px;
	border : 1px solid #99c;
}

.toolbarItem.disabled {
	opacity : 0.3;
	filter : alpha(opacity=30);
	cursor : default;
}

.toolbarSeparator {
	cursor : default;
}

.toolbarFlexibleSpace {
}

__CPAN_FILE__ src/widget/templates/FloatingPane.html
<div id="${this.widgetId}" dojoAttachEvent="onMouseDown" class="dojoFloatingPane">
	<div dojoAttachPoint="titleBar" class="dojoFloatingPaneTitleBar"  style="display:none">
	  	<img dojoAttachPoint="titleBarIcon"  class="dojoFloatingPaneTitleBarIcon">
		<div dojoAttachPoint="closeAction" dojoAttachEvent="onClick:closeWindow"
   	  		class="dojoFloatingPaneCloseIcon"></div>
		<div dojoAttachPoint="restoreAction" dojoAttachEvent="onClick:restoreWindow"
   	  		class="dojoFloatingPaneRestoreIcon"></div>
		<div dojoAttachPoint="maximizeAction" dojoAttachEvent="onClick:maximizeWindow"
   	  		class="dojoFloatingPaneMaximizeIcon"></div>
		<div dojoAttachPoint="minimizeAction" dojoAttachEvent="onClick:minimizeWindow"
   	  		class="dojoFloatingPaneMinimizeIcon"></div>
	  	<div dojoAttachPoint="titleBarText" class="dojoFloatingPaneTitleText">${this.title}</div>
	</div>

	<div id="${this.widgetId}_container" dojoAttachPoint="containerNode" class="dojoFloatingPaneClient"></div>

	<div dojoAttachPoint="resizeBar" class="dojoFloatingPaneResizebar" style="display:none"></div>
</div>
__CPAN_FILE__ src/widget/templates/DemoEngine.html
<div dojoAttachPoint="domNode">
	<div dojoAttachPoint="navigationNode">
		<table border="0" cellspacing="0" cellpadding="0">
			<tr>
				<td width="1%" valign="top" class="navigationCell"><h1>Categories</h1><div dojoAttachPoint="menuNavigationNode"></div></td>
				<td width="99%" valign="top">
					<div dojoAttachPoint="demoNavigationNode">
					</div>
				</td>
			</tr>
		</table>
	</div>

	<div dojoAttachPoint="demoContainerNode">

		<div dojoAttachPoint="demoPaneNode">
		</div>

		<div dojoAttachPoint="demoHeaderNode">
			<span dojoAttachPoint="collapsedMenuNode" dojoAttachEvent="onclick: expandDemoNavigation"></span>
			<div dojoAttachPoint="aboutNode">About this Demo</div>
		</div>
	</div>
</div>

__CPAN_FILE__ src/widget/templates/MonthlyCalendar.html
<div class="datePickerContainer" dojoAttachPoint="datePickerContainerNode">
	<h3 class="monthLabel">
	<!--
	<span 
		dojoAttachPoint="decreaseWeekNode" 
		dojoAttachEvent="onClick: onIncrementWeek;" 
		class="incrementControl">
		<img src="${dojoRoot}src/widget/templates/decrementWeek.gif" alt="&uarr;" />
	</span>
	-->
	<span 
		dojoAttachPoint="decreaseMonthNode" 
		dojoAttachEvent="onClick: onIncrementMonth;" class="incrementControl">
		<img src="${dojoRoot}src/widget/templates/decrementMonth.gif" 
			alt="&uarr;" dojoAttachPoint="decrementMonthImageNode">
	</span>
	<span dojoAttachPoint="monthLabelNode" class="month">July</span>
	<span 
		dojoAttachPoint="increaseMonthNode" 
		dojoAttachEvent="onClick: onIncrementMonth;" class="incrementControl">
		<img src="${dojoRoot}src/widget/templates/incrementMonth.gif" 
			alt="&darr;"  dojoAttachPoint="incrementMonthImageNode">
	</span>
	<!--
		<span dojoAttachPoint="increaseWeekNode" 
			dojoAttachEvent="onClick: onIncrementWeek;" 
			class="incrementControl">
			<img src="${dojoRoot}src/widget/templates/incrementWeek.gif" 
			alt="&darr;" />
		</span>
	-->
	</h3>
	<table class="calendarContainer">
		<thead>
			<tr dojoAttachPoint="dayLabelsRow">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
		</thead>
		<tbody dojoAttachPoint="calendarDatesContainerNode" 
			dojoAttachEvent="onClick: onSetDate;">
			<tr dojoAttachPoint="calendarRow0">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
			<tr dojoAttachPoint="calendarRow1">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
			<tr dojoAttachPoint="calendarRow2">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
			<tr dojoAttachPoint="calendarRow3">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
			<tr dojoAttachPoint="calendarRow4">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
			<tr dojoAttachPoint="calendarRow5">
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
			</tr>
		</tbody>
	</table>
	<h3 class="yearLabel">
		<span dojoAttachPoint="previousYearLabelNode"
			dojoAttachEvent="onClick: onIncrementYear;" class="previousYear"></span>
		<span class="selectedYear" dojoAttachPoint="currentYearLabelNode"></span>
		<span dojoAttachPoint="nextYearLabelNode" 
			dojoAttachEvent="onClick: onIncrementYear;" class="nextYear"></span>
	</h3>
</div>

__CPAN_FILE__ src/widget/templates/RemoteTabControl.css
.dojoRemoteTabController {
	position: relative;
}

.dojoRemoteTab {
	position : relative;
	float : left;
	padding-left : 9px;
	border-bottom : 1px solid #6290d2;
	background : url(images/tab_left.gif) no-repeat left top;
	cursor: pointer;
	white-space: nowrap;
	z-index: 3;
}

.dojoRemoteTab div {
	display : block;
	padding : 4px 15px 4px 6px;
	background : url(images/tab_top_right.gif) no-repeat right top;
	color : #333;
	font-size : 90%;
}

.dojoRemoteTabPaneClose {
	position : absolute;
	bottom : 0px;
	right : 6px;
	height : 12px;
	width : 12px;
	background : url(images/tab_close.gif) no-repeat right top;
}

.dojoRemoteTabPaneCloseHover {
	background-image : url(images/tab_close_h.gif);
}

.dojoRemoteTabClose {
	display : inline-block;
	height : 12px;
	width : 12px;
	padding : 0 12px 0 0;
	margin : 0 -10px 0 10px;
	background : url(images/tab_close.gif) no-repeat right top;
	cursor : default;
}

.dojoRemoteTabCloseHover {
	background-image : url(images/tab_close_h.gif);
}

.dojoRemoteTab.current {
	padding-bottom : 1px;
	border-bottom : 0;
	background-position : 0 -150px;
}

.dojoRemoteTab.current div {
	padding-bottom : 5px;
	margin-bottom : -1px;
	background-position : 100% -150px;
}

__CPAN_FILE__ src/widget/templates/ButtonTemplate.html
<div dojoAttachPoint="buttonNode" class="dojoButton" style="position:relative;" dojoAttachEvent="onMouseOver; onMouseOut; onMouseDown; onMouseUp; onClick:buttonClick; onKey:onKey; onFocus;">
  <div class="dojoButtonContents" align=center dojoAttachPoint="containerNode" style="position:absolute;z-index:2;"></div>
  <img dojoAttachPoint="leftImage" style="position:absolute;left:0px;">
  <img dojoAttachPoint="centerImage" style="position:absolute;z-index:1;">
  <img dojoAttachPoint="rightImage" style="position:absolute;top:0px;right:0px;">
</div>

__CPAN_FILE__ src/widget/templates/Tree.css
.dojoTree {
	font: caption;
	font-size: 11px;
	font-weight: normal;
	overflow: auto;
}

.dojoTreeNodeLabel {
	padding: 1px 2px;
	color: WindowText;
	cursor: default;
}

.dojoTreeNodeLabel:hover {
	text-decoration: underline;
}

.dojoTreeNodeLabelSelected {
	background-color: Highlight;
	color: HighlightText;
}

.dojoTree div {
	white-space: nowrap;
}

.dojoTree img {
	vertical-align: middle;
}

__CPAN_FILE__ src/widget/templates/TooltipTemplate.css
.dojoTooltip {
	border: solid black 1px;
	background: beige;
	color: black;
	position: absolute;
	font-size: small;
	padding: 2px 2px 2px 2px;
	z-index: 10;
	display: block;
}

__CPAN_FILE__ src/widget/templates/Wizard.css
.WizardContainer {
	background: #EEEEEE;
	border: #798EC5 1px solid;
	padding: 2px;
}

.WizardTitle {
	color: #003366;
	padding: 8px 5px 15px 2px;
	font-weight: bold;
	font-size: x-small;
	font-style: normal;
	font-family: Verdana, Arial, Helvetica;
	text-align: left;
}

.WizardText {
	color: #000033;
	font-weight: normal;
	font-size: xx-small;
	font-family: Verdana, Arial, Helvetica;
	padding: 2 50; text-align: justify;
}

.WizardLightText {
	color: #666666;
	font-weight: normal;
	font-size: xx-small;
	font-family: verdana, arial, helvetica;
	padding: 2px 50px;
	text-align: justify;
}

.WizardButtonHolder {
	text-align: right;
	padding: 10px 5px;
}

.WizardButton {
	color: #ffffff;
	background: #798EC5;
	font-size: xx-small;
	font-family: verdana, arial, helvetica, sans-serif;
	border-right: #000000 1px solid;
	border-bottom: #000000 1px solid;
	border-left: #666666 1px solid;
	border-top: #666666 1px solid;
	padding-right: 4px;
	padding-left: 4px;
	text-decoration: none; height: 18px;
}

.WizardButton:hover {
	cursor: pointer;
}

.WizardButtonDisabled {
	color: #eeeeee;
	background-color: #999999;
	font-size: xx-small;
	FONT-FAMILY: verdana, arial, helvetica, sans-serif;
	border-right: #000000 1px solid;
	border-bottom: #000000 1px solid;
	border-left: #798EC5 1px solid;
	border-top: #798EC5 1px solid;
	padding-right: 4px;
	padding-left: 4px;
	text-decoration: none;
	height: 18px;
}



__CPAN_FILE__ src/widget/templates/TreeV3.css
 
/* indent for all tree children excepts root */
.TreeNode {
    background-image : url('../templates/images/TreeV3/i.gif');
    background-position : top left;
    background-repeat : repeat-y;
    margin-left: 19px;
    zoom: 1;
}
.TreeIsRoot {
    margin-left: 0;
}
 
/* left vertical line (grid) for all nodes */
.TreeIsLast {
    background-image: url('../templates/images/TreeV3/i_half.gif');
    background-repeat : no-repeat;
}
 


 
 
.TreeExpandOpen .TreeExpand {
    background-image: url('../templates/images/TreeV3/expand_minus.gif');
}
 
/* closed is higher priority than open */
.TreeExpandClosed .TreeExpand {
    background-image: url('../templates/images/TreeV3/expand_plus.gif');
}
 
/* highest priority */
.TreeExpandLeaf .TreeExpand {
    background-image: url('../templates/images/TreeV3/expand_leaf.gif');
}

/* 
should always override any expand setting, but do not touch children.
if I add .TreeExpand .TreeExpandLoading same time and put it to top/bottom, then it will take precedence over +- for all descendants or always fail
so I have to remove TreeExpand and process this one specifically
*/

.TreeExpandLoading   {
    width: 18px;
    height: 18px;
    float: left;
    display: inline;
    background-repeat : no-repeat;
    background-image: url('../templates/images/TreeV3/expand_loading.gif');
}

 
.TreeContent {
    min-height: 18px;
    min-width: 18px;
    margin-left:18px;
    cursor: default;
    /* can't make inline - multiline bugs */
}

.TreeIEContent {
	height: 18px;
}
 
.TreeExpand {
    width: 18px;
    height: 18px;
    float: left;
    display: inline;
    background-repeat : no-repeat;
}
 
 
/* same style as IE selection */
.TreeNodeEmphased {
    background-color: Highlight;
    color: HighlightText;
}
 
 
.TreeContent .RichTextEditable, .TreeContent .RichTextEditable iframe {
      background-color: #ffc;
      color: black;
}

/* don't use :focus due to opera's lack of support on div's */
.TreeLabelFocused {
      outline: 1px invert dotted;
}


__CPAN_FILE__ src/widget/templates/Spinner.html
<span _="weird end tag formatting is to prevent whitespace from becoming &nbsp;"
	style='float:${this.htmlfloat};'
	><table cellpadding=0 cellspacing=0 class="dojoSpinner">
		<tr>
			<td
				><input
					dojoAttachPoint='textbox' type='${this.type}'
					dojoAttachEvent='onblur;onfocus;onkey:_handleKeyEvents;onKeyUp:_onSpinnerKeyUp;onresize:resize'
					id='${this.widgetId}' name='${this.name}' size='${this.size}' maxlength='${this.maxlength}'
					value='${this.value}' class='${this.className}' autocomplete="off"
			></td>
			<td
				><img dojoAttachPoint="upArrowNode"
					dojoAttachEvent="onDblClick: _upArrowDoubleClicked;  onMouseDown: _upArrowPressed; onMouseUp: _arrowReleased; onMouseMove: _discardEvent;"
					src="${this.incrementSrc}" style="width: ${this.buttonSize.width}px; height: ${this.buttonSize.height}px;"
				><img dojoAttachPoint="downArrowNode"
					dojoAttachEvent="onDblClick: _downArrowDoubleClicked;  onMouseDown: _downArrowPressed; onMouseUp: _arrowReleased; onMouseMove: _discardEvent;"
					src="${this.decrementSrc}" style="width: ${this.buttonSize.width}px; height: ${this.buttonSize.height}px;"
			></td>
		</tr>
	</table
	><span dojoAttachPoint='invalidSpan' class='${this.invalidClass}'>${this.messages.invalidMessage}</span
	><span dojoAttachPoint='missingSpan' class='${this.missingClass}'>${this.messages.missingMessage}</span
	><span dojoAttachPoint='rangeSpan' class='${this.rangeClass}'>${this.messages.rangeMessage}</span
></span>

__CPAN_FILE__ src/widget/templates/DocPane.css
.dojoDocPane { padding:1em; font: 1em Georgia,Times,"Times New Roman",serif; }

.dojoDocPane .container{ }

.dojoDocPane .dialog{ }
.dojoDocPane .dialog .container{ padding: 0.5em; background: #fff; border: 2px solid #333; }
.dojoDocPane .dialog .docDialog{ background: transparent; width: 20em; }
.dojoDocPane .dialog .docDialog h2{ margin-top: 0; padding-top: 0; }
.dojoDocPane .dialog .docDialog input { float: right; margin-right: 1em; }
.dojoDocPane .dialog .docDialog p{ clear: both; }
#dojoDocUserName, #dojoDocPassword { width: 10em; }

.dojoDocPane .nav{ }
.dojoDocPane .nav span{ }

.dojoDocPane .detail{ }
.dojoDocPane .detail h1{ }
.dojoDocPane .detail h1 span.fn{ }
.dojoDocPane .detail .description{ }
.dojoDocPane .detail .params{ }
.dojoDocPane .detail .params .row{ }
.dojoDocPane .detail .params .row span{ }
.dojoDocPane .detail .variables{ }
.dojoDocPane .detail .variables .row{ }
.dojoDocPane .detail .signature{ }
.dojoDocPane .detail .signature .source{ white-space: pre; font: 0.8em Monaco, Courier, "Courier New", monospace; }
.dojoDocPane .detail .signature .source .return{ color:#369; }
.dojoDocPane .detail .signature .source .function{ color: #98543F; font-weight: bold; }
.dojoDocPane .detail .signature .source .params{ }
.dojoDocPane .detail .signature .source .params .type{ font-style: italic; color: #d17575; }
.dojoDocPane .detail .signature .source .params .name{ color: #d14040; }

.dojoDocPane .result{ }
.dojoDocPane .result h1{ }
.dojoDocPane .result .row{ }
.dojoDocPane .result .row .summary{ }

.dojoDocPane .package{ }
.dojoDocPane .package h1{ }
.dojoDocPane .package .row{ }
.dojoDocPane .package .row .summary{ }
.dojoDocPane .package .description{ }
.dojoDocPane .package .methods{ }
.dojoDocPane .package .methods h2{ }
.dojoDocPane .package .methods .row{ }
.dojoDocPane .package .methods .row .description{ }
.dojoDocPane .package .requires{ }
.dojoDocPane .package .requires h2{ }
.dojoDocPane .package .requires .row{ }

__CPAN_FILE__ src/widget/templates/ResizableTextarea.html
<div>
	<div style="border: 2px solid black; width: 90%; height: 200px;"
		dojoAttachPoint="rootLayoutNode">
		<div dojoAttachPoint="textAreaContainerNode" 
			style="border: 0px; margin: 0px; overflow: hidden;">
		</div>
		<div dojoAttachPoint="statusBarContainerNode" class="statusBar">
			<div dojoAttachPoint="statusLabelNode" 
				class="statusPanel"
				style="padding-right: 0px; z-index: 1;">drag to resize</div>
			<div dojoAttachPoint="resizeHandleNode"></div>
		</div>
	</div>
</div>

__CPAN_FILE__ src/widget/templates/Menu2.css

.dojoPopupMenu2 {
	position: absolute;
	border: 1px solid #7298d0;
	background:#85aeec url(images/soriaMenuBg.gif) repeat-x bottom left !important;
	padding: 1px;
	margin-top: 1px;
	margin-bottom: 1px;
}

.dojoMenuItem2{
	white-space: nowrap;
	font: menu;
	margin: 0;
}

.dojoMenuItem2Hover {
	background-color: #D2E4FD;
	cursor:pointer;
	cursor:hand;
}

.dojoMenuItem2Icon {
	position: relative;
	background-position: center center;
	background-repeat: no-repeat;
	width: 16px;
	height: 16px;
	padding-right: 3px;
}

.dojoMenuItem2Label {
	position: relative;
	vertical-align: middle;
}

/* main label text */
.dojoMenuItem2Label {
	position: relative;
	vertical-align: middle;
}

.dojoMenuItem2Accel {
	position: relative;
	vertical-align: middle;
	padding-left: 3px;
}

.dojoMenuItem2Disabled .dojoMenuItem2Label,
.dojoMenuItem2Disabled .dojoMenuItem2Accel {
	color: #607a9e;
}

.dojoMenuItem2Submenu {
	position: relative;
	background-position: center center;
	background-repeat: no-repeat;
	background-image: url(images/submenu_off.gif);
	width: 5px;
	height: 9px;
	padding-left: 3px;
}
.dojoMenuItem2Hover .dojoMenuItem2Submenu {
	background-image: url(images/submenu_on.gif);
}

.dojoMenuItem2Disabled .dojoMenuItem2Submenu {
	background-image: url(images/submenu_disabled.gif);
}

.dojoMenuSeparator2 {
	font-size: 1px;
	margin: 0;
}

.dojoMenuSeparator2Top {
	height: 50%;
	border-bottom: 1px solid #7a98c4;
	margin: 0px 2px;
	font-size: 1px;
}

.dojoMenuSeparator2Bottom {
	height: 50%;
	border-top: 1px solid #c9deff;
	margin: 0px 2px;
	font-size: 1px;
}

.dojoMenuBar2 {
	/*position: relative;*/
	background:#85aeec url(images/soriaBarBg.gif) repeat-x top left;
	border-bottom:1px solid #6b9fec;
	
}

.dojoMenuBar2Client {
	padding: 1px;
}

.dojoMenuBarItem2 {
	white-space: nowrap;
	font: menu;
	margin: 0;
	position: relative;
	vertical-align: middle;
	z-index: 1;
	padding: 3px 8px;
}

.dojoMenuBarItem2 span {
	margin: 0;
	position: relative;
	z-index: 2;
	cursor:pointer;
	cursor:hand;
}

.dojoMenuBarItem2Hover {
	background-color:#d2e4fd;
}

.dojoMenuBarItem2Disabled span {
	color: #4f6582;
}

__CPAN_FILE__ src/widget/templates/Wizard.html
<div class="WizardContainer" dojoAttachPoint="wizardNode">
    <div class="WizardText" dojoAttachPoint="wizardPanelContainerNode">
    </div>
    <div class="WizardButtonHolder" dojoAttachPoint="wizardControlContainerNode">
        <input class="WizardButton" type="button" dojoAttachPoint="previousButton"/>
        <input class="WizardButton" type="button" dojoAttachPoint="nextButton"/>
        <input class="WizardButton" type="button" dojoAttachPoint="doneButton" style="display:none"/>
        <input class="WizardButton" type="button" dojoAttachPoint="cancelButton"/>
    </div>
</div>

__CPAN_FILE__ src/widget/templates/Checkbox.css
.dojoHtmlCheckbox {
	border: 0px;
	width: 16px;
	height: 16px;
	margin: 2px;
	vertical-align: middle;
}

.dojoHtmlCheckboxOn {
	background: url(check.gif) 0px 0px;
}
.dojoHtmlCheckboxOff {
	background: url(check.gif) -16px 0px;
}
.dojoHtmlCheckboxDisabledOn {
	background: url(check.gif) -32px 0px;
}
.dojoHtmlCheckboxDisabledOff {
	background: url(check.gif) -48px 0px;
}
.dojoHtmlCheckboxOnHover {
	background: url(check.gif) -64px 0px;
}
.dojoHtmlCheckboxOffHover {
	background: url(check.gif) -80px 0px;
}
__CPAN_FILE__ src/widget/templates/InlineEditBox.html
<form class="inlineEditBox" style="display: none" dojoAttachPoint="form" dojoAttachEvent="onSubmit:saveEdit; onReset:cancelEdit; onKeyUp: checkForValueChange;">
	<input type="text" dojoAttachPoint="text" style="display: none;" />
	<textarea dojoAttachPoint="textarea" style="display: none;"></textarea>
	<input type="submit" value="Save" dojoAttachPoint="submitButton" />
	<input type="reset" value="Cancel" dojoAttachPoint="cancelButton" />
</form>

__CPAN_FILE__ src/widget/templates/Show.css
@media screen {
	html, body {
		margin: 0px;
		padding: 0px;
		width: 100%;
	}
	h1 {
		font-size: 50px;
	}
	p, li {
		font-size: 30px;
	}
	.dojoShowNav {
		background: #369;
		overflow: hidden;
		position: absolute;
		height: 5px;
		bottom: 0px;
		left: 0px;
		width: 100%;
		text-align: center;
	}
	.dojoShowNav input {
		margin: 0px;
	}
	.dojoShowHider {
		height: 5px;
		overflow: hidden;
		width: 100%;
	}
	.dojoShowPrint {
		position: absolute;
		left: 5px;
		top: 0px;
	}
	.dojoShow {
		display: none;
	}
}
@media print {
	.dojoShow {
		display: none !important;
	}
	.dojoShowPrint {
		display: block !important;
	}
	.dojoShowPrintSlide {
		border: 1px solid #aaa;
		padding: 10px;
		margin-bottom: 15px;
	}
	.dojoShowPrintSlide, ul {
	page-break-inside: avoid;
	}
	h1 {
		margin-top: 0;
		page-break-after: avoid;
	}
}
__CPAN_FILE__ src/widget/templates/TreeDisableWrap.css

/* CSS for TreeDisableWrapExtension */

.TreeDisableWrap {
	white-space: nowrap;
}
.TreeIEDisableWrap {
	width: expression( 5 + firstChild.offsetWidth );
}

__CPAN_FILE__ src/widget/templates/TabContainer.css
.dojoTabContainer {
	position : relative;
}

.dojoTabPaneWrapper {
	border : 1px solid #6290d2;
	_zoom: 1; /* force IE6 layout mode so top border doesnt disappear */
	display: block;
	clear: both;
}

.dojoTabLabels-top {
	position : relative;
	top : 0px;
	left : 0px;
	overflow : visible;
	margin-bottom : -1px;
	width : 100%;
	z-index: 2;	/* so the bottom of the tab label will cover up the border of dojoTabPaneWrapper */
}

.dojoTabNoLayout.dojoTabLabels-top .dojoTab {
	margin-bottom: -1px;
	_margin-bottom: 0px; /* IE filter so top border lines up correctly */
}

.dojoTab {
	position : relative;
	float : left;
	padding-left : 9px;
	border-bottom : 1px solid #6290d2;
	background : url(images/tab_left.gif) no-repeat left top;
	cursor: pointer;
	white-space: nowrap;
	z-index: 3;
}

.dojoTab div {
	display : block;
	padding : 4px 15px 4px 6px;
	background : url(images/tab_top_right.gif) no-repeat right top;
	color : #333;
	font-size : 90%;
}

.dojoTab .close {
	display : inline-block;
	height : 12px;
	width : 12px;
	padding : 0 12px 0 0;
	margin : 0 -10px 0 10px;
	cursor : default;
	font-size: small;
}

.dojoTab .closeImage {
	background : url(images/tab_close.gif) no-repeat right top;
}

.dojoTab .closeHover {
	background-image : url(images/tab_close_h.gif);
}

.dojoTab.current {
	padding-bottom : 1px;
	border-bottom : 0;
	background-position : 0 -150px;
}

.dojoTab.current div {
	padding-bottom : 5px;
	margin-bottom : -1px;
	background-position : 100% -150px;
}

/* bottom tabs */

.dojoTabLabels-bottom {
	position : relative;
	bottom : 0px;
	left : 0px;
	overflow : visible;
	margin-top : -1px;
	width : 100%;
	z-index: 2;
}

.dojoTabNoLayout.dojoTabLabels-bottom {
	position : relative;
}

.dojoTabLabels-bottom .dojoTab {
	border-top :  1px solid #6290d2;
	border-bottom : 0;
	background : url(images/tab_bot_left.gif) no-repeat left bottom;
}

.dojoTabLabels-bottom .dojoTab div {
	background : url(images/tab_bot_right.gif) no-repeat right bottom;
}

.dojoTabLabels-bottom .dojoTab.current {
	border-top : 0;
	background : url(images/tab_bot_left_curr.gif) no-repeat left bottom;
}

.dojoTabLabels-bottom .dojoTab.current div {
	padding-top : 4px;
	background : url(images/tab_bot_right_curr.gif) no-repeat right bottom;
}

/* right-h tabs */

.dojoTabLabels-right-h {
	overflow : visible;
	margin-left : -1px;
	z-index: 2;
}

.dojoTabLabels-right-h .dojoTab {
	padding-left : 0;
	border-left :  1px solid #6290d2;
	border-bottom : 0;
	background : url(images/tab_bot_right.gif) no-repeat right bottom;
	float : none;
}

.dojoTabLabels-right-h .dojoTab div {
	padding : 4px 15px 4px 15px;
}

.dojoTabLabels-right-h .dojoTab.current {
	border-left :  0;
	border-bottom :  1px solid #6290d2;
}

/* left-h tabs */

.dojoTabLabels-left-h {
	overflow : visible;
	margin-right : -1px;
	z-index: 2;
}

.dojoTabLabels-left-h .dojoTab {
	border-right :  1px solid #6290d2;
	border-bottom : 0;
	float : none;
	background : url(images/tab_top_left.gif) no-repeat left top;
}

.dojoTabLabels-left-h .dojoTab.current {
	border-right : 0;
	border-bottom :  1px solid #6290d2;
	padding-bottom : 0;
	background : url(images/tab_top_left.gif) no-repeat 0 -150px;
}

.dojoTabLabels-left-h .dojoTab div {
	background : 0;
	border-bottom :  1px solid #6290d2;
}

__CPAN_FILE__ src/widget/templates/PopUpButton.css
.PopUpButton {
	padding : 2px 6px 2px 9px;
	border : 1px outset #ccc;
	background : #f4f4f4;
	color : #333;
	text-decoration : none;
}

.PopUpButton .downArrow {
	margin-left: 0.5em;
	margin-bottom: 2px;
}

.downArrow.disabled {
	background-image : url(images/dropdownButtonsArrow-disabled.gif);
	cursor : default;
}

ul.dropdownButtons li a:hover,
ul.dropdownButtons li span.downArrow:hover {
	color : black;
	background-color : #ddd;
}

ul.dropdownButtons li .downArrow.pressed, ul.dropdownButtons li .downArrow:focus {
	border-style : inset;
	background-position : 5px 10px;
	padding : 2px 4px;
}

ul.dropdownButtons li a.disabled:hover,
ul.dropdownButtons li span.downArrow.disabled:hover {
	color : #999;
	background-color : #d2e4fd;
}

__CPAN_FILE__ src/widget/templates/incrementMonth.gif
GIF89a	Äÿÿÿ000ÖÖÖéééóóóøøøðððúúúžžžyyyÎÎÎFFFUUUõõõWWW222ýýý¶¶¶ØØØƒƒƒaaa:::!ù,	%`!Œ¤@@N ªK(«t²R4=TÁ#å4D`¤ƒ"Í;
__CPAN_FILE__ src/widget/templates/DropDownButtonTemplate.html
<button dojoAttachPoint="button" class="dojoButton dojoButtonNoHover" dojoAttachEvent="onMouseOver: ; onMouseOut: ; onClick: ;">
  <table dojoAttachPoint="table" style="margin:0 0 0 0;"><tr>
    <td class="label" dojoAttachPoint="labelCell"></td>
    <td class="border" dojoAttachPoint="borderCell"></td>
    <td class="downArrow" dojoAttachPoint="arrowCell">
      <img dojoAttachPoint="arrow">
    </td>
  </tr></table>
</button>
__CPAN_FILE__ src/widget/templates/decrementWeek.gif
GIF89aÄÿÿÿ000øøøfffúúú¶¶¶âââßßßÂÂÂyyyFFFˆˆˆÌÌÌCCCØØØžžžmmm   ÖÖÖjjj!ù, …(
C�i<ÀLN0	D‡‚;‘A;
__CPAN_FILE__ src/widget/templates/EditorToolbarLight.html
<div class="EditorToolbarDomNode EditorToolbarSmallBg" 
	unselectable="on" dojoOnMouseDown="preventSelect">
	<table cellpadding="1" cellspacing="0" border="0">
		<tbody>
			<tr valign="top" align="left" dojoAttachPoint="oneLineTr">
				<td>
					<!-- bold -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="bold">
						<span title="Toggle Bold (Ctrl-B)" class="dojoE2TBIcon dojoE2TBIcon_Bold">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- italic -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="italic">
						<span title="Toggle Italic (Ctrl-I)" class="dojoE2TBIcon dojoE2TBIcon_Italic">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- underline -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="underline">
						<span title="Toggle Underline (Ctrl-U)" class="dojoE2TBIcon dojoE2TBIcon_Underline">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- link -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="createlink">
						<span title="Create Link" class="dojoE2TBIcon dojoE2TBIcon_Link">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- insertimage -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="insertimage">
						<span title="Insert Image" class="dojoE2TBIcon dojoE2TBIcon_Image">&nbsp;</span>
					</span>
				</td>
				<td>
					<!-- save -->
					<span class="iconContainer dojoEditorToolbarItem" dojoETItemName="save">
						<span title="Save" class="dojoE2TBIcon dojoE2TBIcon_Save">&nbsp;</span>
					</span>
				</td>
				<td width="*">&nbsp;</td>
			</tr>
		</tbody>
	</table>
</div>

__CPAN_FILE__ src/widget/templates/TabContainerA11y.css
.dojoTabContainer {
	position : relative;
}

.dojoTabPaneWrapper {
	position : relative;
	border : 1px solid #6290d2;
	clear: both;
	_zoom: 1; /* force IE6 layout mode so top border doesnt disappear */
}

.dojoTabLabels-top {
	position : absolute;
	top : 0px;
	left : 0px;
	overflow : visible;
	margin-bottom : -1px;
	width : 100%;
	z-index: 2;	/* so the bottom of the tab label will cover up the border of dojoTabPaneWrapper */
}

.dojoTabNoLayout.dojoTabLabels-top {
	position : relative;
}

.dojoTabNoLayout.dojoTabLabels-top .dojoTab {
	margin-bottom: -1px;
	_margin-bottom: 0px; /* IE filter so top border lines up correctly */
}

.dojoTab {
	position : relative;
	float : left;
	padding-left : 9px;
	border-bottom : 1px solid #6290d2;
	cursor: pointer;
	white-space: nowrap;
	z-index: 3;
}

.dojoTab div {
	display : block;
	padding : 4px 15px 4px 6px;
	color : #333;
	font-size : 90%;
}

.dojoTabPanePaneClose {
	position : absolute;
	bottom : 0px;
	right : 6px;
	height : 12px;
	width : 12px;
	font-size : small;
}
.dojoTabPanePaneCloseImage {
}

.dojoTabPanePaneCloseHover {
}

.dojoTabClose {
	display : inline-block;
	height : 12px;
	width : 12px;
	padding : 0 12px 0 0;
	margin : 0 -10px 0 10px;
	cursor : default;
	font-size: small;
}

.dojoTabCloseImage {
}

.dojoTabCloseHover {
}

.dojoTab.current {
	padding-bottom : 1px;
	border-bottom : 0;
	background-position : 0 -150px;
}

.dojoTab.current div {
	padding-bottom : 5px;
	margin-bottom : -1px;
	background-position : 100% -150px;
}

/* bottom tabs */

.dojoTabLabels-bottom {
	position : absolute;
	bottom : 0px;
	left : 0px;
	overflow : visible;
	margin-top : -1px;
	width : 100%;
	z-index: 2;
}

.dojoTabNoLayout.dojoTabLabels-bottom {
	position : relative;
}

.dojoTabLabels-bottom .dojoTab {
	border-top :  1px solid #6290d2;
	border-bottom : 0;
}

.dojoTabLabels-bottom .dojoTab div {
}

.dojoTabLabels-bottom .dojoTab.current {
	border-top : 0;
}

.dojoTabLabels-bottom .dojoTab.current div {
	padding-top : 4px;
}

/* right-h tabs */

.dojoTabLabels-right-h {
	position : absolute;
	top : 0px;
	right : 0px;
	overflow : visible;
	margin-left : -1px;
	z-index: 2;
}

.dojoTabLabels-right-h .dojoTab {
	padding-left : 0;
	border-left :  1px solid #6290d2;
	border-bottom : 0;
	float : none;
}

.dojoTabLabels-right-h .dojoTab div {
	padding : 4px 15px 4px 15px;
}

.dojoTabLabels-right-h .dojoTab.current {
	border-left :  0;
	border-bottom :  1px solid #6290d2;
}

/* left-h tabs */

.dojoTabLabels-left-h {
	position : absolute;
	top : 0px;
	left : 0px;
	overflow : visible;
	margin-right : -1px;
	z-index: 2;
}

.dojoTabLabels-left-h .dojoTab {
	border-right :  1px solid #6290d2;
	border-bottom : 0;
	float : none;
}

.dojoTabLabels-left-h .dojoTab.current {
	border-right : 0;
	border-bottom :  1px solid #6290d2;
	padding-bottom : 0;
}

.dojoTabLabels-left-h .dojoTab div {
	background : 0;
	border-bottom :  1px solid #6290d2;
}

__CPAN_FILE__ src/widget/templates/Show.html
<div class="dojoShow">
	<div dojoAttachPoint="contentNode"></div>
	<div class="dojoShowNav" dojoAttachPoint="nav">
		<div class="dojoShowHider" dojoAttachPoint="hider"></div>
		<span dojoAttachEvent="onClick:previousSlide">&lt;</span>
		<select dojoAttachEvent="onClick:gotoSlideByEvent" dojoAttachPoint="select">
			<option dojoAttachPoint="option">Title</option>
		</select>
		<span dojoAttachEvent="onClick:nextSlide">&gt;</span>
	</div>
</div>
__CPAN_FILE__ src/widget/templates/SlideShow.html
<div style="position: relative; padding: 3px;">
		<div dojoAttachPoint="controlsContainer">
			<input type="button" value="pause" 
				dojoAttachPoint="startStopButton"
				dojoAttachEvent="onClick: togglePaused;">
		</div>
		<div style="position: relative; width: 800px; height: 600px;"
			dojoAttachPoint="imagesContainer"
			dojoAttachEvent="onClick: togglePaused;">
			<img dojoAttachPoint="img1" class="slideShowImg" 
				style="z-index: 1;"  />
			<img dojoAttachPoint="img2" class="slideShowImg" 
				style="z-index: 0;" />
		</div>	
</div>
__CPAN_FILE__ src/widget/templates/grabCorner.gif
GIF89a

‘djp†Ž–ÿÿÿ!ù,

”�©‹œ�RPy›ÊúEtÓZÞ¤u3¢á[!;
__CPAN_FILE__ src/widget/templates/DatePicker.css
.datePickerContainer {
	width:164px; /* needed for proper user styling */
}

.calendarContainer {
/*	border:1px solid #566f8f;*/
}

.calendarBodyContainer {
	width:100%; /* needed for the explode effect (explain?) */
	background: #7591bc url("images/dpBg.gif") top left repeat-x;
}

.calendarBodyContainer thead tr td {
	color:#293a4b;
	font:bold 0.75em Helvetica, Arial, Verdana, sans-serif;
	text-align:center;
	padding:0.25em;
	background: url("images/dpHorizLine.gif") bottom left repeat-x;
}

.calendarBodyContainer tbody tr td {
	color:#fff;
	font:bold 0.7em Helvetica, Arial, Verdana, sans-serif;
	text-align:center;
	padding:0.4em;
	background: url("images/dpVertLine.gif") top right repeat-y;
	cursor:pointer;
	cursor:hand;
}


.monthWrapper {
	padding-bottom:2px;
	background: url("images/dpHorizLine.gif") bottom left repeat-x;
}

.monthContainer {
	width:100%;
}

.monthLabelContainer {
	text-align:center;
	font:bold 0.75em Helvetica, Arial, Verdana, sans-serif;
	background: url("images/dpMonthBg.png") repeat-x top left !important;
	color:#293a4b;
	padding:0.25em;
}

.monthCurve {
	width:12px;
}

.monthCurveTL {
	background: url("images/dpCurveTL.png") no-repeat top left !important;
}

.monthCurveTR {
		background: url("images/dpCurveTR.png") no-repeat top right !important;
}


.yearWrapper {
	background: url("images/dpHorizLineFoot.gif") top left repeat-x;
	padding-top:2px;
}

.yearContainer {
	width:100%;
}

.yearContainer td {
	background:url("images/dpYearBg.png") top left repeat-x;
}

.yearContainer .yearLabel {
	margin:0;
	padding:0.45em 0 0.45em 0;
	color:#fff;
	font:bold 0.75em Helvetica, Arial, Verdana, sans-serif;
	text-align:center;
}

.curveBL {
	background: url("images/dpCurveBL.png") bottom left no-repeat !important;
	width:9px !important;
	padding:0;
	margin:0;
}

.curveBR {
	background: url("images/dpCurveBR.png") bottom right no-repeat !important;
	width:9px !important;
	padding:0;
	margin:0;
}


.previousMonth {
	background-color:#6782a8 !important;
}

.previousMonthDisabled {
	background-color:#a4a5a6 !important;
	cursor:default !important
}
.currentMonth {
}

.currentMonthDisabled {
	background-color:#bbbbbc !important;
	cursor:default !important
}
.nextMonth {
	background-color:#6782a8 !important;
}
.nextMonthDisabled {
	background-color:#a4a5a6 !important;
	cursor:default !important;
}

.currentDate {
	text-decoration:underline;
	font-style:italic;
}

.selectedItem {
	background-color:#fff !important;
	color:#6782a8 !important;
}

.yearLabel .selectedYear {
	padding:0.2em;
	background-color:#9ec3fb !important;
}

.nextYear, .previousYear {
	cursor:pointer;cursor:hand;
	padding:0;
}

.nextYear {
	margin:0 0 0 0.55em;
}

.previousYear {
	margin:0 0.55em 0 0;
}

.incrementControl {
	cursor:pointer;cursor:hand;
	width:1em;
}

.increase {
	float:right;
}

.decrease {
	float:left;
}

.lastColumn {
	background-image:none !important;
}



__CPAN_FILE__ src/widget/templates/AccordionPane.css
.dojoAccordionPane .label {
	color: #000;
	font-weight: bold;
	background: url("images/soriaAccordionOff.gif") repeat-x top left #85aeec;
	border:1px solid #d9d9d9;
	font-size:0.9em;
}

.dojoAccordionPane-selected .label {
	background: url("images/soriaAccordionSelected.gif") repeat-x top left #85aeec;
	border:1px solid #84a3d1;
}

.dojoAccordionPane .label :hover {
	cursor: pointer;
}

.dojoAccordionPane .accBody {
	background: #fff;
	overflow: auto;
	border:1px solid #84a3d1;
}
__CPAN_FILE__ src/widget/templates/SliderHorizontal.html
<div class="sliderMainHorizontal">
    <div class="sliderHandleHorizontal" dojoAttachPoint="sliderHandle"></div>
</div>

__CPAN_DIR__ src/widget/templates/images
__CPAN_FILE__ src/widget/templates/images/slider-button-horz.png
‰PNG


IHDRÞ„è,tEXtCreation TimeSat 24 Jun 2006 18:42:46 -0500º3„WtIMEÖ+öà4	pHYsÁÁÃiTSgAMA±�üaEPLTEÿÿÿŒ¥Ö„œÆŒ­ÞŒ­Öœ½ï”µç„¥Ö{”Æ”µï{œÆŒµç”½ï{œÎŒ­çœÆ÷„¥Þ¥Æÿ„¥Î{œÖsœÖÎÞÿÎçÿF'»%tRNS@æØf°IDATxÚeÐ[ƒ P
ÜEETÜÿRV˜†¿3—¢T­™™gÕ¯»§ ËMôš(¡œ�Œn„äå,B¸)#íiKSÎÝ¸�4�”NÁš‹‚Zñ…óÜ÷ÍOBˆ1D–v¸z‹áÈæ†¬Ì Á`ò\CÃ].ïƒëŒlùÑk8Úß`5V:>†ßnVPµ2´mÆÁg>ïgB1=l˜†T.'ÍHJ[<ÏèÐhõWo³/‚zÛ†ã8IEND®B`‚
__CPAN_FILE__ src/widget/templates/images/soriaActive-r.gif
GIF89a6wæz˜Ä¤Ãò™¼ïžÁõ|šÇ§Åóš¼ïž¿ñ©Çô«Éõ¦Èü­Êö¶ÑùªÈõ¿ØýžÂö¨Êý²Í÷¯Ì÷ Ã÷°Í÷¹ÔûÃÛþ¢ÂòÀÙý¥ÄóŸÀñ›½ð¤Çú¾×ü›¿óÁÙþ¥Èû¼Õü�¾ðœ¾ð³Îøž¾ð§Éü¸Òú¾Øü©Ëþ£Æù¡ÂòÂÚþ¢Äø®Ëö ÁñÃÜÿ½Öü¨ÆôÃÛÿ›½ïµÐù™½ñŸÃ÷�Àô»Ôû¹Óú³Ïø}›Ç~œÇ|›Ç~›Ç™¼ðžÁö�Àõœ¿ô›¾óš¾ò™½ò™¼ñ™»ð™»ï!ù,6wÿ€‚ƒ„…†‡ˆ‰‰0Œ�Ž��‘’“’=3—˜™š›œ�ž�=¢£¤¥¦§¨©¨=,­®¯°±²³´³=¸¹º»¼½¾¿¾=ÃÄÅÆÇÈÉÊÉ=ÎÏÐÑÒÓÔÕÔ=(ÙÚÛÜÝÞßàß=äåæçèéêëê=1ïðñòóôõöõ=!úûüýþÿì‘£ Áƒ*\Èpa�
#JœH±¢Å‹{èØÈ±£Ç� CŠùã„É“(Sª\É²%ËbÊœI³¦Í›8oþ¨Á³§ÏŸ@ƒ
*”ÇŽ£H“*]Ê´©Ó¦<HH�JµªÕ«X³bå¡«×¯`ÃŠKv,
hÓª]Ë¶­Û·nÿyH˜K·®Ý»xóêÍËÃ…ß¿€L¸0a+^Ì¸±ãÇ�óH@¹²åË˜3kÞ¬™GƒÏ C‹Mº´éÒ<¨^Íºµë×°cÃæ!£¶íÛ¸sëÞÍ{7�ÀƒN¼¸ñãÆydXÎ¼¹óçÐ£K�Î#€õëØ³kßÎ½;wÞÃ‹¿ÝÇ…óèÓ«_Ï¾½ûöVÈŸO¿¾ýûøóã'ð¢¿ÿÿ(à€H€&¨à‚6èàƒpÀ„Vhá…f¨a†”àá‡ †(âˆ$–H""¤¨âŠ,¶èâ‹0¾HÀ4Öhã�8æ¨ãŽ:°Á�@)ä�Did‘Ð äÿ’L6éä“PF	%Tiå•Xf©å–\nI€`†)æ˜d–iæ™f~‰æšl¶I&IÄ)çœtÖiç�xÞ	gž|öég�{þ)è €j¨¡�ª(Ÿ‰.êh¡�FJg£’>Ji¥‹^Šé¡šnJh§ž

j¨~ŽJ*£H¤ªêª¬¶êê«°¾J@¬´Öj««³Þªë®¸òê«¯¹þ*l­Ákl¯Ç&Ë*@4ëì³ÐF+í´ÔNËlµØf«m´×nëí·Ü!î¸ä–kî¹è¦‹.ê¶ëî»ç²ï¼ôÆ[ï½÷Ê‹ï¾îêËï¿ñÚ ðÀlðÁ'Œ0F4ìðÃG,ñÄOÌpÿÅg¬qÄoìñÇƒ,²È�l2Æ%Ÿ¬2ÇE´ìòË0Ç,óÌ4ÏL@Í8ç¬³Ì7ïìóÏ<-´Ð=mtÎE­4ÏD4íôÓPG-õÔTOM@ÕXg­µÔWoíõ×\ƒ-¶Øx`öÙh§­öÚl·Í6CÄ-÷Üt×m÷Ýxß
wÞ|÷íwÝ{ÿ-øà€n¸áà øâŒ7îøã�G9BTnùå˜g®ùæœoNyç ‡.zæŸ�núé¤ úê¬·îúë°Ç;²×nûí¯Äî¼÷îûïÀ/|ðºoüñÈÿ^|òÌ7¯üÐG/ýôÔWoýõÖpÃöÜwïý÷à‡/~�ø>L`þùè§¯þúì·Ï¾-Ä/ÿüô×oÿýøßïƒ
ü÷ïÿÿ (@pà€L ÈÀ:°�>�'HÁ
Zð‚Ì y €zðƒ ¡GHÂòÀ(L¡
WÈÂºð….äfHÃÚð†8Ì¡sÈƒøð‡@¢‡HÄ"‘ŠH¢—ˆˆ@;
__CPAN_FILE__ src/widget/templates/images/combo_box_arrow.png
‰PNG


IHDR�‘h6tEXtSoftwareAdobe ImageReadyqÉe<òIDAT8Ëc¨œv�$ÄÄ«Ž¾%5Î;Õ°âô?‚hÕ±÷�óNB5,;ñ‡ ZuIÃâc?	¢•Gß!4Ì?ô
ˆÚ–^*èÙ„†€‚Y
sö¢ž5·ulý5­¼áÈ
BdWy×8¦aÆî[>Y�—Zqä-BÃäío ¨oã÷ˆj È…K-?Œ¤¡ó8Êj_Ñ�ÙºY|ùá7
sO@5t­{G�kYd��,¾ì’†æå÷�Q^ïn B\zðuÃ˜†š…7" †z¸†²Ù—	¢%^ÕÏ9NZâƒj 	øÍÔ:ÄIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/slider_up_arrow.png
‰PNG


IHDR�‘h6tIMEÖ"
QŸ&	pHYsÂÂnÐu>gAMA±�üa	IDATxÚc¬œv��ÀÂÆÆ¦­©F¤êó¯°©_¿ÿ^ºý’ j-)�
Œ@ÀÆÆJ¬“Á;²èëgw�¤¨”2
Œ +ØÙþÿÿwöðZ Ã/¶Š‘‘	CÈM¬¬,p¡[—Ž¾{õÈxxë¬ªŽ%š& @-,0ðÿßŸÓ‡ÖCäNXäÂ¥  6°°@Ðùc[¿~~‘2€\¸BØf úòñõùcÛPþØ6  DÙÓÌÌ þ¯Ÿß]ü“Ñ
„È"<
¢ÀÈ*ªÎ(ø%Ff&f‚à/ÜF&f&â502üÿÇôë=a
Çÿøñ˜‰T
¾]P¡v„âIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/treenode_grid_z.gif
GIF89a€999!ù,Œ�©Ëí£œt‚zi¶¸kÏ}M;
__CPAN_FILE__ src/widget/templates/images/soriaActive-l.gif
GIF89a6wæ™¼ïžÁõ¤Ãòœ¾ðž¾ð©Çô«Éõ§Éü­Êö®Ëö¸Òú¿ØýŸÃ÷©Ëþ¨Êý¾Øü§Åó¹Ôû¢Äø²Í÷½Öü�ÀôÃÜÿÂÚþ¾×ü¶ÑùÃÛþ¤Çú¯Ì÷ Ã÷›½ð¹Óúž¿ñ¨Æô¦Èüš¼ïžÂöÁÙþ£ÆùÃÛÿ¢Âò ÁñŸÀñ¡Âò³Ïø�¾ð¥ÄóµÐùÀÙý»Ôû¥Èû›¿ó™½ñ³Îø›½ïªÈõ°Í÷¼Õü™¼ðžÁö�Àõ›¾óœ¿ôz˜Äš¾ò™½ò™¼ñ™»ð™»ï!ù,6wÿ€?‚ƒ„…†‡ˆ‰ŠŒ�Ž��‘’“’?'—˜™š›œ�ž�?¢£¤¥¦§¨©¨?­®¯°±²³´³?%¸¹º»¼½¾¿¾?0ÃÄÅÆÇÈÉÊÉ?ÎÏÐÑÒÓÔÕÔ?ÙÚÛÜÝÞßàß?äåæçèéêëê?ïðñòóôõöõ?9úûüýþÿü£ Áƒ*\Èpá�#JœH±¢Å‹|ØÈ±£Ç� CŠùC�É“(Sª\É²%ËbÊœI³¦Í›8oþxÁ³§ÏŸ@ƒ
*ô‹£H“*]Ê´©Ó¦?jH�JµªÕ«X³bý1¡«×¯`ÃŠKvìhÓª]Ë¶­Û·nÿp˜K·®Ý»xóêÍû#�ß¿€L¸0á+^Ì¸±ãÇ�ÿ0@¹²åË˜3kÞ¬ùÇ�Ï C‹Mº´éÒ?
¨^Íºµë×°cÃþ¢¶íÛ¸sëÞÍ{÷ÀƒN¼¸ñãÆ¸XÎ¼¹óçÐ£K�þC€õëØ³kßÎ½;÷êÞÃ‹¯ýŠóèÓ«_Ï¾½ûö?VÈŸO¿¾ýûøóãÿ‘¢¿ÿÿ(à€øƒ
&¨à‚6èàƒþÂ„Vhá…f¨a†?àá‡ †(âˆ$–Hâ-¤¨âŠ,¶èâ‹0¾øÃ4Öhã�8æ¨ãŽ:þàÁ�@)ä�Did‘?Ø äÿ’L6éä“PF	å#Tiå•Xf©å–\nù`†)æ˜d–iæ™f~‰æšl¶IæDÄ)çœtÖiç�xÞ	gž|öég�{þ)è €j¨¡�ª(Ÿ‰.êh¡�FJg£’>Ji¥‹^Šé¡šnJh§ž

j¨~ŽJ*£C¤ªêª¬¶êê«°¾úC¬´Öj««³Þªë®¸òê«¯¹þ*l­Ákl¯Ç&Ëê:4ëì³ÐF+í´ÔNËlµØf«m´×nëí·Ü
!î¸ä–kî¹è¦‹îê¶ëî»ç²ï¼ôÆ[ï½÷Ê‹ï¾îêËï¿ñÒ ðÀlðÁ'ŒðA4ìðÃG,ñÄOÌpÿÅg¬qÄoìñÇƒ,²È�l2Æ%Ÿ¬2Ç@´ìòË0Ç,óÌ4ÏüCÍ8ç¬³Ì7ïìóÏ<-´Ð=mtÎE­4Ï=4íôÓPG-õÔTOýCÕXg­µÔWoíõ×\ƒ-¶Ø?Ì`öÙh§­öÚl·Íö>Ä-÷Üt×m÷Ýxß
wÞ|÷íwÝ{ÿ-øà€n¸á?T øâŒ7îøã�Gù<Tnùå˜g®ùæœoNyç ‡.zæŸ�núé¤ úê¬·îúë°Çû²×nûí¯ÿ°Ãî¼÷îûïÀ/|ðºoüñÈÿ^|òÌ7¯<	ÐG/ýôÔWoýõÖÿÀÀöÜwïý÷à‡/~Žø?t`þùè§¯þúì·ÏþÄ/ÿüô×oÿýøßÿƒ	ü÷ïÿÿ (Àlà€L ÈÀ:°�?��'HÁ
Zð‚Ì  ‚zðƒ ¡GHÂþà(L¡
WÈÂºð….ü�fHÃÚð†8Ì¡søƒøð‡@¢‡HÄ"QHL¢;
__CPAN_FILE__ src/widget/templates/images/soriaAccordionOff.gif
GIF89a³þþþîîîøøøòòòüüüöööðððíííúúúôôôììì!ù,$J&Å»ÿ;
__CPAN_FILE__ src/widget/templates/images/dpMonthBg2.png
‰PNG


IHDRÈ@¹×ætEXtSoftwareAdobe ImageReadyqÉe<KIDATHÇíÔ+ ÐBvÿpn…+ŠdG:÷Òì£ÖÆ\8Õ‘*HŠ`sdOšT‰¾ .%q›”Ñ†aAÿQÃ0ŒlÿÅé¨A“žIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/treenode_node.gif
GIF89aÄ©Äí¨Äí¨ÃìªÅî©Åî©Åí§Ãì¤Çú–ºî‘´ê Ã÷yžÖ›¿ó‚¦Ý‹¯åªÅí!ù,@ $Ždižhª®éã¾0útM²¢ï:!3À ° C�F€,Ál2•§‡cJ�d�¬6+�-¾à¯A+³Îè´ú;
__CPAN_FILE__ src/widget/templates/images/bdYearBg.gif
GIF89a¢t‘»u‘»t�¹s�¸sŽ¸rŽ·s�¹t�º!ù,pþPC+x�Í‹ÿ	;
__CPAN_FILE__ src/widget/templates/images/soriaBarBg.gif
GIF89aÄ–¹î‡¨Ù›¾ò“¶ë™½ñƒ§Þ¤Ú§Êý¤Çú©Ìþ‘´ê”¸ír—Ðx�ÕušÒ¨Ëþ¥Èû‹¯ä{ ×�Àô£Åù˜»ð�±ç�³è¦Éü¡Äø‡«ážÁõ Ãö!ù,`ò„P·MQË \V¤†Ô8L;
__CPAN_FILE__ src/widget/templates/images/tab_right.gif
GIF89a�,Õ7b�Òåíøöùýèïùòõûýþþúûþíòúâë÷•¿ÿŸÆÿßéöÝçö­ÎÿØãô¸ÔÿÀÚÿÚåõÖâôÈÞÿÔáóÎâÿd‘Ó¨Âæh”Ô|¢Ù¹ÍëŽ¯ß�¦Ûûüþ£¾åçîø’²àãë÷k—ÕÓàóŽ´ìž½ëÊÚð¦ÀæŒ°å‹°æ½ÑìÆÖïÚæõ¸Òö•½ø“½ýÍáþ•´áºÓù¡½ä·Óþÿÿÿ”¾ÿÿÿÿ!ù7,�,ÿ@€pH,�È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vë´p.Ÿ›øV)›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûã0-%c‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ –2(7¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ¹)7ÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàØ4!
æçèéêëìíîïðñòóôõö÷øùúûüýþÿøHxP@° Áƒ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±£EˆI²¤É“(Sª\É²¥Ë—0cÊœI³¦Í›8sêÜIóÿ@ƒ
J´¨Ñ£H“*]Ê´©Ó§P£J�JµªÕ«X³N µ«×¯`ÃŠK¶¬Y²\Ïª]Ë¶­Û·pã&M+·®Ý»xóêUKw¯ß¿€¾Ûw°áÃˆ+fZx±ãÇ�#×m,¹²åË˜«RÎÌ¹³gÎ›?‹MzpèÒ¨S«v{zµë×°³¶ŽM»¶m¤³oëÞ;7ïßÀGûN¼xåáÆ“+?Œ|¹óçy›CŸN½­ôêØ³‡½®½»wÍßÃ‹ß>¾¼y«ÜÏ«Ÿ~½ûîíßË§¾ýåõïë'ž¿ÿÝýý' mhàj¨ i	.è`g
>(¡eNhác^¨!bnèÿa`~(¢^!Žhâd'¦èY‰*¶È—‹0JÆbŒ4~5c�8bucŽ<nÕã�~íä�J	Iä‘E‰ä’@)É$’N>Id”RIe•=^‰eŽZnYc—^Æf˜.ŽI¦ŠfžybšjŽÈf›¾	ç†rÎya�vNˆgžîÉç‚~þy` ‚Hh¡ÿŠè~Š.z_£ŽÎi¤ïMJéz–^z^¦š–Çi§â}
êw¢Ž
Ÿ©m–Š*vª®JŸ«d¶
ës²ÎŠŸ­[ÖŠ«qºîÊŸ¯Rö
ìoÂ ±K‹¬mÊ.K ³SB;d³ÒºFmµª]‹-jÚnË ·\‚‹c·â®X.�äž›ÿYºê^Æn»ÇÁÛâ»òBFo½ŽÝ‹¯búîË¡¿n,b¿FpÁ€Œp�k¨pÃÑAláÃÛEqÅr]Œ1\oÌšÇ€‚¬`Ç"¿X²¡'£œr¢+³Ü2£/Ãó£3Ó\³¤7ãœs¥;óÜ3¦?cÊÅÐDmôÑH'­ôÒL7íôÓPG-õÔTW
µ`Œq\wíõ×`‡-öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×�ö*Ì@Èôí÷ß€.øà„nøáˆ'®øâŒ7îøã�G.ùä”Wn9ã+€PÊ
tîùç ‡.úè¤—núé¨§®úê¬·îúë°Ç.ûì´×nÿ»ë1\pC¼÷îûïÀ/üðÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWß¼ÀÀöÜwïý÷à‡/þøä—oþùè§¯þúì·ïþûðÇ/ÿüô·Âä¯ÿþü÷ïÿÿ HÀð€L ÈÀ:ð�Œ h‚ à‚Ì 7ÈÁzðƒ ¡GHÂšð„(L¡
WÈÂºð…0L!D€Úð†8Ì¡wÈÃúð‡@¢‡HÄ"ñˆHL¢—ÈÄ&:‰€§HÅ*ZñŠXÌ¢·ÈÅ.zñ‹`£ÇHÆ2šñŒhL£×XFà�pŒ£çHÇ:ÚÿñŽxÌ£÷ÈÇ>úñ�€¤ IÈBò�ˆ$ÀÈF:ò‘�Œ¤$'IÉJZò’˜Ì¤&7ÉÉNzò“ ¥(GIÊR~H¥*WÉÊVºò•°Œ¥,gIËZÚò–¸Ì¥.wÉË^úò—À¦0y	ó˜ÈL¦2—ÉÌf:ó™ÐŒ¦4§IÍjZóšØÌ¦6·ÉÍnzó›Ù@ÆIÎršóœèL§:×ÉÎvºó�ðŒ§<çIÏzÚóžøÌ§>÷ÉO{ 
¨@JÐ‚ô M¨BÊÐ†:ô¡�¨D'JÑŠZô¢ÍèDÿ©ÑŽzô£ 
©HGJÒ’št¤=©JWÊÒ–ºô¥ÿ0�)BS*ÓšÚô¦8Í©NOJÓ�úô§@
ªPmÚÓ¡õ¨HMªRZÔ¥:õ©P�ªL›*ÕªZõªX¥(U³ÊÕ®z5«[ýªXÇJV¡†µ¬hM«Z[zÖµºõ­pÅh[ãJ×ºÚõ s½«^÷
×¼òõ¯€«_KØÂJu°†M¬b�ŠØÅ:ö±8m,d'KY–J¶²˜Í,H/«ÙÎzV«Ÿ
­hCÊÙÑšö´--jWZÕ²öµ™u-lgYÙÒö¶‰µ-nwXÝòö·wõ-p‡ÛWâ³Â=®rÇšÜå:—«Í}®t«ÝéZ×©Õ½®v�šÝíz¨Ýý®xsÞñšwªçMÿ¯WË«ÞöòÔ½ð=l|ç‹]úÚ©ì½¯~A»ßþî4¿þ
0SL`ôøÀlE°‚U
à¸Á&0„#à	S¸¿¾°~3¬aûr¸Ãóý0ˆá+â··Ä&N/ŠSlÞ³X¼.~±wc,cíÒ¸ÆÖ½1Ž¥«ã;·Ç>V.�ƒlÜ!y¸F>òo“¬äÝ2¹É·}2”g+å)¿¶ÊV^-–³|Ú-sy´^þrkÅ<â0“¹³f>slÕ¬á4³™²n~småá8Óy±v¾snõ¬à<ó™°~þso]à@z¯†>tp]aFû7ÑŽŽ+¤#ýÖISz­–¾tZ3­é²rºÓÌuˆoEßO“º«¦>5XU}bV«7Õ®¦n¬ÏëYCµÖ¶®o®¿‹ë]'µ×¾æn°·ìa›ÕØ×-6²ªìeÿ×Ù<†ös›-í›R»Ú5½6¶cªím¿´ÛÞNp¸‘<nr—{ÉçFwº�¼nv·;ÊïŽr;
__CPAN_FILE__ src/widget/templates/images/decrementMonth.gif
GIF89aÄBXq™²Ö­ÊõŸ»áÌÙì}’®q�¸ˆªÚ�¥Æ˜¼ò©Åï­ËöŸÌ­Éõ”·ë]wš®Ëö€ Î?Tm,=O5H]š¾ô™¾ô™½óÄÏß):K!ù,$`%2$Z( -èuY†®CÅ”r%O�ÃÄ—™"˜¤’;
__CPAN_FILE__ src/widget/templates/images/spinnerIncrement.gif
GIF89a		³‡¥Ò…¤Ñx—Æ� ÎžÌƒ¢Ï{šÉ“·ì›¾ò¡Äø€¤ÛušÒ§Éü):Ky–Á!ù,		$ÐÉ9»˜¹�zë‰S Hc’Îp˜ìálìJm+Ž°ìüBýŽ;
__CPAN_FILE__ src/widget/templates/images/tab_close_h.gif
GIF89aÕè��ì~~ä~~ï‚‚ðƒƒóŠŠÐmmò‰‰éŽŽêwwèvvÝvväyyÕeeç„„î††üññâ||ýòòà‡‡àˆˆÓddê~~ázzÕkkãŠŠúîîçuuÔnnÐiiØppä‹‹å~~ì‘‘ÝttÖggé��ÐnnüïïÒiiîÑjjüôôÑrrÓjjïƒƒÐhhí„„ë��â€€Ùiiç||Þxxé}}õ��ÔppáuuØmmæssýôôÀÿÿÿ!ù,VÀžpHòŽÈ¤�g+PÀÁ[�ÄÀˆT{¼ÖKB@.¢// €ívYN]Ó‘v*Jƒ¥ž�L7)j8#.%j14'+jI™E›BA;
__CPAN_FILE__ src/widget/templates/images/floatingPaneRestore.gif
GIF89aæ–¹í™¼ïÂÓì§Ç÷ªÉù®Íû¬Ëú°Ïüp‹³6FVr�µ„©à†ªáœ¾ï´Ñý¦Éü Ã÷¢ÅùÄÕí›¿óž¿ðmˆ°}¢Ù§Æõ±ÏûÃÕí¡Áò¤Äô®ÌùqŒ´¤ÇúÁÓë–¸ë‘´ê™»í¯Îú¨Êýn‰±³ÐüoŠ²v›ÓÁÓì‚¦Ý�°åyžÖl‡¯“·ìŽ²ç¬Êø©ÈöžÁõ–ºî‹¯å™¼ñœ¾ðqŒ³›»ê’´å•¶æq�´˜¸èo‹²r�´¢Ãô¥ÅõŸÀòlˆ°ž½ë�²ãÄÕîÃÔí‰®ä²Ðý³Ñþ“¶ë€¦ßr˜Ðlˆ²©ËþÆÖík…«):Kÿÿÿ!ù,ÿ€P‚ƒ„…†‚N‰Š‹ŒŒ
P$EO“”•–OE$�EIŸ ¡¡E�E&H«¬­­&E>PEQ¹º»½E;PE#»ÈQË#EP2É»Ø2Ð0QRãäãQè07P5F1âåäQ÷1F5P3F@æ™K6ä‚‘ü\ÙðC k86qÁ/„
A:”’€‡#!z@ya„‚�dôè `äÅ	(4Œ4@³æÆ9¡ñ’�‚
µFD„% ¨B‰Ó§P¡‚ "©+ŽhÝÊ•ë
*@a‘bÁ’³hÓ¦]�‚…X.É¥ô…(LòêÝË—o(ML˜p‹@;
__CPAN_FILE__ src/widget/templates/images/spinnerDecrement.gif
GIF89a		³‡¥Ò…¤Ñx—Æ� ÎžÌƒ¢Ï{šÉ“·ìŒ°æ€¤ÛušÒ¡Äø§Éü):Ky–Á!ù,		%ÐÉ9»˜¹°º_NÑŒdãGÙ� äëIÝÔ‰#(|¯P@G;
__CPAN_FILE__ src/widget/templates/images/treenode_grid_l.gif
GIF89a€rrr!ù,Œ€Ë¦
S„o®jÎ’k¯âH‚æ‰¦êÊz;
__CPAN_FILE__ src/widget/templates/images/tab_left_r.gif
GIF89a	–Ä–Àÿ Æÿ¸Ôÿ­ÎÿÀÚÿÈÞÿçîød‘ÓŸ»ã€¥Úáê÷h”Ôf“Ó“½þ�¹ù¬Íþ£¾å¹Íëš»ë³Ðùûüþ¨Âæ†°ì‡®æx ØµÏ÷‰®å‰«Ýb�Ò”¾ÿÿÿÿ!ù,	–¥ 'Ždgž&‡¢êšº/ÜºóZ³pwŸ{Lç=p(#þŠÈ£Òfd&�KÜSå5©Ð,vk�v«>íWæ–Çf¡÷ÌVƒÝdx:H¿¢ïíúZŽççí{zoƒq…s€~Š‡}Œ�„‰Ž‹‘”‚•�–™˜›†—�šŸœi
0©ª¯°
¶·¼½ÄÇÇÇ	"!;
__CPAN_FILE__ src/widget/templates/images/treenode_grid_t.gif
GIF89a€rrr!ù,!Œ€Ë¦
S„o®jÎ’k¯âH6[vZé´F-:q¾;
__CPAN_FILE__ src/widget/templates/images/dpCurveTL.png
‰PNG


IHDRÈ‹JétEXtSoftwareAdobe ImageReadyqÉe<ÓIDATxÚíÍÍ1`†ÑoF:P›ž1£?F:Ð‰DØ½¹1t�›±8‹çÙž‘dìºzú>®®«ì»?à¤zí~�éã×QõR¥«rÚ	ü"›ç*��é|³ªÒÙ¸œ¦»!ët7&µîÆd¶Jw‡A.î?Ò]!Ët7Îï–é®�Eºg·‹tWÈ{ºƒ@ �@ �@ �@ �@ ÈEnÞÒ�@ �@ �@ �@ dOmt-UHùaønIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/h-bar.gif
GIF89aA"÷œ¿ó˜»ð–¹î¤Çú�Àô�´éŒ°æ¥Èû”·ì¡ÄøžÁõ¢Åø™¼ð—»ï‡«â�±æ’¶ë›¾òŽ²çŠ®ä‹¯åŽ²è‰­ã�³è Ã÷“·ìˆ¬â“¶ë§Êý¦Èü§Éü„¨ß”¸í•¸í•¹î¨Êý£Åù•¹í�±çš½ò—ºï‚§Ý~£Úš½ñ™½ñ–ºî›¾ó†ªà›½ò£Æù€¥Ü˜¼ð‡«á…©à’µê–ºïŒ°å™¼ñ�³é…ªà}¢Ù‘µéyžÖp–Î�´êv›Ó�¦Ýr˜Ðˆ­ã�²èƒ§Þ†«áušÑ„©ß¡Ä÷žÂõŠ¯ä¢Åùš¾ò�³é�Áõ Ãö‰®ä€¤Ü¨Ëý|¡Ø{ ×zŸÖo”Í“·ë“¶ì| ×Š®ã£Æú†ªáœÀô‹¯äžÁô‰®ã‚¦Ý‚§Þ§Éý„©à¤Û€¥Û‡¬âŠ¯åˆ­âx�Õ¢Äøƒ¨Þ”¸ì�¦Ü‡¬áƒ§Ý¥Çû~¤Út™Ñ‹°å›¿ò�²çw�Ô¤Æú§Êü…©ß˜¼ñŸÂõ¦ÉüžÀõs™Ñ‘´ê�°æˆ¬ã—»ðyžÕœ¿ôu›Ò¨Ëþ¤ÇùušÒ¦Èû Ä÷{¡Ø›¿óŽ±çwœÔ’µë€¤Û˜»ïš¾ñŸÃö¦Éû| Ø”·í‰­â¤Ú ÂöŸÁõ¥Èú£Û†©à�µê�¥ÛŒ±æ‘¶ë’¶ê{Ÿ×žÀôr—Ð~£Ùƒ©Þw›Ô¡Åø–¹í�¥ÜžÁözŸ×}¢Ú{ ØvœÓx�Ô…ªß’¶ì—¹ï‘µë~¢Ù‰­ä£ÚxžÕŒ¯æ¡Å÷‘´é¡Ã÷vœÔ’·ë�ÁôŸÁö|¡×œÀóŽ³è�²çyŸÖ¤Æù¤ÇûŠ®åo•ÍŸÂö©Ëþ‘µê!ù,A"ÿë,ŠdÈJ,4FÌx¡AHÊ„^�)Ä„™B”À±£ÇŽ%BdÊÁ�E�=è5A
!^ÌAËŠ¡H‹ãe¥Ê™1I¼¤!2�‚ž€vñM7H�Jµê
!Þ�„Và‰(L ’ÆK’1gªXálÑ*6Wª¨�aä…E
@*¢š
-4ÞB`ƒÃˆ#žÅ­�´Ø€¦£¤°,hxaD†Š*WØ¼½â(×$2|èb†ÃD…/†Ñ‚p+`èÞÍ{÷
9·‚¤ÉLà`¦Ë2“r9
}E�3p>Ð°`ÔuA’²€ÿQ;ƒ'\XÏ¾½{'V0DI‚
$k�Æ8gð Ë˜ð°	Fì �Q¯€�‰@X+8áÂ!£À†vÈá0â‚+ôÑq@€KÈ…¥ÁFÀ±	Ò!ƒI8À…(u´50'Ü€,á‡3L6éd“~,Üq340$uU�\8�„2ÐÁÃ'2¤�ÄDP ÁR� aDªGÄ8ƒA#	ôéçŸ~6‚�3Ä@A%|,4&[ D‘D
2 ™‚*v1ñÀÐØòF	QÍPá#w.¡g¬,@Âª¬¶Êê¬$ÿ0è†>Bb–7”ð†-Ð<ñ›©Bénì‡à� €jÞ	©€3Q(ÑF1(2À¶ÜvË­"14Ñ†Q8£•œ0_® h
XÇnŒ‘Ð0a‚€ Â
ä�PL‹Aªê±Ì7ìðÃËèAÂ²šðwƒ @ ƒ	LXp„LI¼�8TÐCÿR’ƒ†©J Ãsp‰<÷ìsÏ—0Ç1P¬„3K„qHNä@ÉÆôP\¤ñB Ð 	\`yæ­ Þ)�XÌµÊàÜ�{ŒàöÛp¿½‡­Œ¸ÀXÒÉ)Ëÿ@!ØpÁ`hB(^h �°A	(ˆ-
pr0	7°6T<ãùç Nt@4	²rr.¬0
%lP$8ˆ¡ÁBk0�ƒ¡d!@À•<òEÔ*±ÀÍžàç�‡îü3TŒîÁž½¹Î„ñÅ#•'@¡H€kÐàLR4üþ²´§.ÐÅ0RÆ‰<¯"#”Áˆé] Ø V×´Ð¨À ˜@œ/}ëk_Àœ¿ƒÉ�~öÃŸþžÇ?ÿP€æ¢R˜À6ð�Âî€�‚B.ø^>Å`~øC8·AÐ�®`ÿÐˆ(¼‚_pA‰
!‚,A|RÐÀjp„5€a^A
!*;)ÀÃ–Úþ°˜ñŒh<ãþP7¢5AV–X�gPˆ€@p£Ã¦ø�l‡&pœœ"G¤#AAOX@º †uà‘�Œ$$¦‡.4a”¡p¥×-Jv& @vðbYÊb–³-øUëZÙò–,·.qaouéZW	Úõ®xÍ«^“€ƒjAÂâ¡�yX­á™
JðÅ¦IÍjRÓJ˜•öXÇ‚ùÇ>Âp ÔÂ
p˜l„#ñÈGR„D$#!IIOÊ'“¢4ÿ¥*uRK"à¼&1‘ÉL¦�R`Là(I©`6B°ê16ÊÑŽrÔƒA7U‚È˜Ä+`™
Ì�4|ÆpqD*Ð€š4HA
­yME„‘�ÙÌ3`,¨D†JÔ¢µÀ	@‹#Œã$j�Bžƒ†TL‡
AÈC2¬ÀƒÕÀ„ƒð€1%N�J(€¶ºõ­n¥D®’•F!çPƒá€�‰VHF‚PDä¡ *…jà…8d•À–RŠ
  Y­øˆf9ÒŠ]"`¥àÊ$€W0Œ%^¨�D¡›äu@E 	ÿTa®0BQˆ£”u²¿�Ä�@Üâ×¸$‘Ä/XT¼ŠE3G ¥\±‹*ø ˆ*~0„@�°¸ŽÈ°ÛóqA
vx€	Ž1YA�ˆ¯|ç+_�"?8†	`5pá„¤$ƒZ!CøA3¸‹„Yø sB
úø¬A°Cd/ ƒô ±ˆCÜƒè`´xµÃÄ°¼€”)‚gŠáƒY !ÁÍÀƒƒàƒ-¨`
þ@
*|—¼<@|ñðˆ—âW†´˜ÑŒ‹kð�OA[ðAnü,èxHà±��<á!; È¾Er‡?Ìä;¹IP~®¦\e!\9Ë[N°—wÜãÙÌhŽl’ÙÜf›ÎÎÍÌœ_@e+cYË\Þ3˜Åìç2¹·‚^s¡Eüæ8+šÎŽÆs¤;
__CPAN_FILE__ src/widget/templates/images/floatingPaneClose.gif
GIF89aæ™¼ï¢Ãô¬Ëú¥ÅõÂÓì§Ç÷ŸÀòªÉùœ¾ðr�µ:Nd<Pfp‹³‹¯å>Qg”³âž¼é;Nd}¢Ù¯Îú�°åž¿ð¢ÅùZs’‘²àžÁõ–ºî†ªá®Ìù¡Áò™»ímˆ°¦Äñ‘´ê¦Éü¤Çú;OdŽ²ç Ã÷ ½ên‰±yžÖ©Èö¢Áï“·ìœ¾ï>RhqŒ´l‡¯ÁÓë³Ðü§ÆõÁÓì@Sj–¸ë•¶æ„©à›¿ó¤Äô±Ïû—¶ä�²ã¬Êø‚¦ÝoŠ²?Rh<PgÄÕí¨Êý�»é™¼ñ´Ñý;OeŽ°à›ºçÃÕív›Ó`w•<Odo‹²qŒ³q�´r�´<Oelˆ°ÄÕî–¹íÃÔí®Íû):K‰®ä²Ðý°Ïü³Ñþ“¶ë€¦ßlˆ²©Ëþr˜ÐÆÖík…«!ù,ÿ€d‚ƒ„…†‚a‰Š‹ŒŒ	dDUc“”•–cUD�"UG]Ÿ ¡¡GU"�#U2[«¬­­2U#RdU;\¸¹ºº;UQd&UXÅX ÆÇÉU&/dCÔMA'Ô'AMÔCÏ9K>+5Y..Y5+æ>K9PdFW*ûEYSN²8(²¯€Š+F�ÑpeÆ€‡”�È’…„ˆf\Ñ �ÅBà�„""è¸ÂBaˆ+È| $‹‚Y„<�i Ã•OÈ”¸R‚²DÀ€!é‚F+\)„Lƒ+-h½  ‰Ö$
.hÐâJƒªx°ÂÖJ�¶nMáz °™lxÙË·o_~Ø•@€‚–Ãˆ'¦@@Â2)hàøB¹²eË8h¤xÌ$Æ¥Ï”b0¡BFŒéÓ¨S§†AŒë×°cÇ†;
__CPAN_FILE__ src/widget/templates/images/tab_right_r_curr.gif
GIF89a�–Õ"b�ÒúûþýþþèïùíòúòõûöùýßéöåíøÚåõâë÷ÝçöØãôÖâô¦Àæh”Ôçîø“²à€¥Ú¹Íë¢½åÀÓî–µái•Ôãë÷¨ÂæûüþŽ¯ß|¢ÙÇ×ï©ÂæÍÜñd‘Óÿÿÿÿÿÿ!ù",�–ÿÀ�pH,�È¤rÉl:ŸÐ¨tJ­Z¯Ø¬v[p¿à°xL.›Ïh³7Ín»ßð¸|¾\Óïø¼~ÏgÛû€�‚ƒ„y…ˆ‰Š‹ŒN‡��‘’“w�”—˜™šW–›žŸ ž�¡¤¥¦…£§ª«¬p©­°±²[¯³¶·¸Jµ¹¼½³»¾ÁÂ¥ÀÃÆÇ—ÅÈËÌ‰ÊÍÐÑ{ÏÒÕÖoÔ×ÚÛcÙÜßàœáãäÝåçèXÞéìåëíðßïñôÖóõøÍ÷ùüÆûý{ýHÐÖÀ‚[LÈÐÔÂ†?=ŒHÓÄŠ#]ÌÈQÑÆŽ }I’ÏÈ’(+¥\	ê$Ë—~`Ê¤är¦Í05oêÔ’s§Ïÿ.?ƒê)´(¢F“Aª´©¦N•B�jt*U¡V¯þÌªu'×®7¿‚�)v,Ì²fY¢M›r-Û’nß†Œ+·#Ýºïâ­¨woÄ¾~œp0á‚†L¬¸ãÆùC®'yr¼Ê–ÛaÎœn3çsž?“-:éÒòP¿=­ZëÖö`›}-;íÚúpw½­ïÞþ€Sý-<ñâ‘7=®óæ¡W•^ô9uXÖ¯³Ê®]÷îÁ{¯ó;ù–çmšO¿i=ûLîß'“ÿ2>}IöïCÊ¯Ÿÿþ—€$ýG !(H‚
Õ G>8�„EH!^HG†ÊÁÿa‡®€(˜ˆ}HbL'"–¢Š+.Ö¢‹/:£Œ3FV£�7R&ÀŽ<öèã�@)ä�Diä‘H&©ä’L6éä“PF)å”T:	@Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ¹&Ôiç�xæ©çž|öéçŸ€*è „jè¡ˆ&ªè¢Œ6ê(¢ é¤”Vjé¥˜fªé¦œvêé§ †*ê¨¤–jê©¨¦ªêª¥@À«°Æ*ë¬´Öjë­¸æªë®¼öêë¯À+ì°Äkì±È
ÀÌ6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–û-¤«ÿîºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ð¾\ ÀÁ'¬ðÂ7ìðÃG,ñÄWlñÅg¬ñÆwìñÇ gü”lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÍ8°ÀÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\S�$ öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×m÷Ýxç­÷Þs[à€.øà„nøáˆ'®øâŒ7îøã�G.ùä”Wnùå˜g®9äD°�"4 úè¤—núé¨§®úê¬·îúë°Ç.ûì´×n;ûí¸ç®ûî¯W@Áˆ <ÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWoýõØg¯ýöÜw½@ ¼ðA;
__CPAN_FILE__ src/widget/templates/images/tab_bot_right.gif
GIF89a�–Äb�Ò Æÿ–Àÿ­Îÿ¸ÔÿÀÚÿÈÞÿh”Ô€¥Ú³Ðùçîø£¾å‰«Ýš»ë¡¼äd‘Ó‰®å‡®æ|¢Ù�¸ø†°ì’¼ýûüþáê÷µÏ÷¨Âæ¬Íþ¹Íë”¾ÿÿÿÿ!ù,�–ÿ  Ždižhª®lë¾p,Ïtmßx®ï6çÿÀ pH,�È¤rÉl:ŸÐ¨tJ­Z¯QvËíz¿à°xLkËè´zÍn»ßÇ3|N¯Ûïx´<Ïïûÿ€u{�„…†‡ˆJƒ‰Œ�Ž�s‹�“”•–S’—š›œš™� ¡¢�Ÿ£¦§¨l¥©¬­®W«¯²³´F±µ¸¹¯·º½¾¡¼¿ÂÃ“ÁÄÇÈ…ÆÉÌÍwËÎÑÒkÐÓÖ×_ÕØÛÜ˜ÝßàÙáãäTÚåèáçéìÛëíðÒïñôÉóõøÂ÷ùü¹ûýeýH0ÕÀ‚ELÈpÓÂ†)=ŒH±ÑÄŠ
]ÌÈñÏÆŽ ñ|I2RÉ“œFÿ¢\©‡¥KH*_Êìs¦M+5oêÌ²³'Ÿœ>ƒ"*´è¢F“ú@ªÔ(Ó¦BŸBõ)uêÎªVobÍ:s+×—^¿²+%Ù²%Ï¢
©vmÇ¶n3Â�[q.Ýˆvï6Ì«7!ß¾ÿ(xp¿Â†ó!N\o1ãxŽ·‹,9åÊå.c§y3¸Îž»�íŽôÚÑ¦­¡N-�µØÕ®›ÁŽm�vÖÙ¶‰áÎ­�7ÔÝ¾{î�xÒáÆi!O.�yTçA—Cg%}:ªêÖMaÏ®�»Vï6·ƒO9^¦øò—Î£¯¤~}1÷+ÛÃw$>£úöáÏ¯‘?[ÿ í  èG�þ” ÿF.øŒƒ5!NG…º�a†ªpè—‡mbK#V¢‰'–¢Š+*Ö¢‹/6£Œ3BV£�7N–£Ž;ZÖ£�?’SÁiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå•HÀ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiç�xæ©çž|ÖIÁ*è „jè¡ˆ&ªè¢Œ6êè£�F*é¤”Vjé¥˜fª©¤<p †*ê¨¤–jê©¨¦ªêª¬¶êê«°Æ*ë¬´Öjë­¸æktPÀ¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíKµØ:›XÐ�à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæÛ.
°Aó ðÀlðÁ'¬ðÂ#��;
__CPAN_FILE__ src/widget/templates/images/timeIcon.gif
GIF89a³7`µ¾Ês�³ÿÿÿ/ZšÞÞÞNp¥Ž¦ÉÌÌÌåëóÌ×å�¨¸öööÛâîÌÌÌ!ù,€ÐI×Ž!ÄœÉùÁ t“ž„@šØ‘ƒÂ¦œ*Ìù‡!¥VNÇƒ]h’ã¶0†‚:$6  cîxØ_“¨2œÐ‘ƒ%¨vß­Mø&|ÛRÉÌhàv8G'x+(/$G
�5yš¡¢£;
__CPAN_FILE__ src/widget/templates/images/treenode_expand_plus.gif
GIF89aæH999~šÃDDDCCDïòöçëñ€›ÄîñõùúûìïôûüýþþþÄÎÝãçïÙßéÛáêÚàéýþþßåíëïôùúüøùûÃÍÜÞäì~™Ãâåêðóöäèïö÷úÉÒà¾ÉÙàåíöøúåéðÓÚåðòö}™ÃšÃàæí}™ÂÑÙäüüýÐØäØÞèêìîûûýíîðÞãìÒÙåCDDòô÷ôõøåêðèìñêíóóõøâçîÊÓàËÔáòôøßâç›Äüýýôöù÷ùûßäìêîóëîóþþÿ×Þèy–Áÿÿÿ!ùH,{€H‚ƒ„…†‡ˆ‚F‹Œ�F‡FG’-@3C�’
?#š†‘�.	8=�D),	5
/%�>½E�21A+*Ã¥ ;<(�76!09$�B4&":'�ŽŽ‰óôõö÷øô�;
__CPAN_FILE__ src/widget/templates/images/treenode_blank.gif
GIF89a÷'ÿÿÿþþþýýýüüüûûûúúúùùùøøø÷÷÷öööõõõôôôòòòñññïïïîîîìììëëëêêêèèèçççæææäääãããâââáááàààÝÝÝÜÜÜÛÛÛÚÚÚÙÙÙÖÖÖÕÕÕÓÓÓÒÒÒ½½½___!ù',OH° Áƒ*\È°¡Ã‡#JœH±¢Å‹1;
__CPAN_FILE__ src/widget/templates/images/blank.gif
GIF89a€ÿÿÿÿÿÿ!ù
,L;
__CPAN_FILE__ src/widget/templates/images/dpCurveBL.png
‰PNG


IHDRÈ‹JétEXtSoftwareAdobe ImageReadyqÉe<ºIDATxÚíÍÁ	Â@†ÑO¶ba kÆX�±	Ë°†À:¼yt‚È;|?Ã\^Ù¯-»�@ �@ �@ �@ �@ �@ �@ �@ �@ È¤ÆdWj?´ì ?‰\Zv¥âH®lc²û+äÜ²›	éâHnBÆ9�{:²éNë¨e6!‹hHEZ{AËh�iÈ»x¬¢>ºE�o!O7
©W:0¼mIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/submenu_on.gif
GIF89a	÷äääîîîëëëøøøõõõåååâââìììéééýýýúúúêêêòòòÿÿÿ!ù,	8è �À�&¸°aAƒ$è  ;
__CPAN_FILE__ src/widget/templates/images/soriaActive-c.gif
GIF89a6wæ¤Ãòz˜Ä™¼ïžÁõ³Îø¨ÆôªÈõ¦Èü Ã÷­Êö§Åó¾Øü¤ÇúÁÙþŸÀñ©ËþžÂö£Æù¥ÄóÃÛþ¢Âò¢Äø®Ëö¨ÊýÂÚþ½Öü¯Ì÷¥Èû¼Õü»Ôû›½ï�¾ðœ¾ð©Çô§ÉüŸÃ÷µÐù°Í÷ÃÛÿ¸ÒúÃÜÿÀÙý²Í÷�Àô Áñ›½ð™½ñ¹Óú¶Ñù³Ïø¹Ôû«Éõ¡Âòž¾ðš¼ï›¿óž¿ñ¿Øý¾×ü™¼ðžÁö�Àõœ¿ô›¾ó™½ò™¼ñš¾ò™»ð™»ï!ù,6wÿ€‚ƒ„…†‡ˆ‰‰(Œ�Ž��‘’““&–—˜™š›œ�� ¡¢£¤¥¦§§ª«¬­®¯°±±
´µ¶·¸¹º»»)¾¿ÀÁÂÃÄÅÅ9ÈÉÊËÌÍÎÏÏÒÓÔÕÖ×ØÙÙ:ÜÝÞßàáâããæçèéêëìííðñòóôõö÷÷úûüýþÿ”A° Áƒ*\¸ð…Ã‡#JœH±bÅ3jÜÈ±£Ç�aˆI²¤É“(S¦$Á²¥Ë—0cÊœ93†Í›8sêÜÉ³gO@ƒ
J´¨Ñ£GU(]Ê´©Ó§P£F-AµªÕ«X³jÝºUƒ×¯`ÃŠK¶lYhÓª]Ë¶­Û·oÿÈ�K·®Ý»xóæ�Á·¯ß¿€<Ø€áÃˆ+^Ì¸qã�#KžL¹²åË—hÞÌ¹³çÏ C‡V@º´éÓ¨S«^½Z‚ë×°cËžM»vm¸sëÞÍ»·ïßÀƒN<7…ãÈ“+_Î¼¹sç4¢KŸN½ºõëØ±³ØÎ½»÷ïàÃ‹ï ¼ùóèÓ«_Ïž=Ž÷ðãËŸO¿¾}û5òëßÏ¿¿ÿÿøÁ€hà�&¨ ‚ 4èàƒF(á„RØÂ…f¨á†vè¡‡„(âˆ$–hâ‰(¢hÃŠ,¶èâ‹0Æ(£ŒÔhã�8æ¨ãŽ<öèã�@i#Diä‘H&©äÿ’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™hF9Äšl¶éæ›pÆ)çœtÖiç�xæ©çž|öéçŸ€*è „î`è¡ˆ&ªè¢Œ6êè£�F*é¤”VÚh˜fªé¦œvêé§ †*ê¨¤–jê©¨¦ªêª¬¶êª«.Ä*ë¬´Öjë­¸â
Ä®¼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF­ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«®º?´ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿ñÞ ðÀlðÁ'œ°7ìðÃG,ñÄWlñéÅg¬ñÆwì1Ä+„,òÈ$—lòÉ(£ÜÃÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬³ÌôìóÏ@-ôÐDmôÑH'í3L7íôÓPG-õÔTWmõÕXg­õÖSCàõ×`‡-öØd—]öh§­öÚl·íöÛo# ÷Üt×m÷Ýxç�w|÷í÷ß€.øàƒG`øáˆ'®øâŒ7Þ8�G.ùä”Wnùå—o ùæœwîùç ‡ú¤—núé¨§®úê«‹àúë°Ç.ûì´×^û¸ç®ûî¼÷îûï¿? üðÄoüñÈ'Ÿ¼"Ì7ï<"�;
__CPAN_FILE__ src/widget/templates/images/toolbar-bg.gif
GIF89aÄçççàààæææÓÓÓöööóóóêêêúúúðððÚÚÚííí÷÷÷ÖÖÖäääñññÔÔÔîîîÑÑÑûûûÞÞÞëëëøøøõõõØØØòòòâââùùùÜÜÜééé!ù,1 $¤fVè¢¬å0&;4bC¸¢S¼ás@€P@l3È€rÂÜ8Ð‹”A}XØˆ6;
__CPAN_FILE__ src/widget/templates/images/dropdownButtonsArrow-disabled.gif
GIF89a÷ÿÿÿ¥¥¥!ù,
8`à€ƒ;
__CPAN_FILE__ src/widget/templates/images/dpHorizLineFoot.gif
GIF89a€qŒµ‘§É!ù,D
;
__CPAN_FILE__ src/widget/templates/images/verticalbar.gif
GIF89a"ÄÙÙÙƒƒƒYYY+++“““hhh999IIIœœœ¦¦¦²²²ªªªppp}}}mmm‡‡‡”””®®®tttŽŽŽ˜˜˜ˆˆˆxxx   ³³³!ù," äPÙ#`Vq)Ú2mðÆ4šeÆ�D œ@;
__CPAN_FILE__ src/widget/templates/images/treenode_child.gif
GIF89a€!ù, Œ�©Ëí¢œ`ÑkïÌ:òþi!¦tÒH¡[iVÏÇòS;
__CPAN_FILE__ src/widget/templates/images/treenode_grid_p.gif
GIF89a€rrr!ù,Œ�©Ëí£œ”�‹o»Sþy8ŠK;
__CPAN_FILE__ src/widget/templates/images/soriaMenuBg.gif
GIF89a÷�¶ð¡Ãö­Ìú§Èø¶ÓþŠ²î²Ðü‡¯í›¾ô•ºò…®ì!ù,H°àÀ$@`@@;
__CPAN_FILE__ src/widget/templates/images/no.gif
GIF89a³	ÜX\ê� í«­Ó.4öÕÖÖ<AÙJOüññÐ &ÿÿÿ!ù	,`0Éº&É)WxDGH!l‡er€ÆÆ�ã¤¶„ @€˜P5Â�¸ô~¬KqCö¤N�•s�ZÐŽ’¹+l¹AhÙ“Y
6œŠåBÀLkQ*Ö¡X0‚ƒ‚;
__CPAN_FILE__ src/widget/templates/images/slider_left_arrow.png
‰PNG


IHDR�‘h6tIMEÖ²�þ0	pHYsÂÂnÐu>gAMA±�üaæIDATxÚc¬œv��ÀÄ†ú:Dª>ñ
„uæÚ366Vv66vv6VV Ì@"™@�é×{ J&’ÜC@Ã‡·/ž?¾C”†ß¿~Ý³rÁÄ’WÏ`ñ42øÿÿßí+ÇOXûõó{œ¡¯ŸÝ={xí»W�Éôa
¢RÊ~±UÞIÜ¼‚¸4 û�‘‘IMÏZUÇüü±­ç�m#¬XÙ8¬]ÂõM�~ýüN”–Æ4¥ž†Ú §*ÎÈÈöœþËÀð�‘ñ7ÃÆ¿Œÿ�4\½~êafA(—‰«~@ð}’`AIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/submenu_disabled.gif
GIF89a	€�–�!ù,	D`§ÛöbRl%
;
__CPAN_FILE__ src/widget/templates/images/floatingPaneMinimize.gif
GIF89aæ€¦ßœ¾ð“¶ë¥ÅõÃÔíÄÕîÂÓì™¼ï–¹íp‹³r�µ®Ìù¯Îú�°å¦ÉüŽ²ç¢Åù–ºî„©àÃÕí±Ïûn‰±–¸ë¡Áò‚¦Ý Ã÷¨Êý™»íÁÓë‹¯åžÁõmˆ°‘´ê¬ÊøqŒ´†ªá³Ðü¤Äôv›ÓyžÖoŠ²œ¾ï§Æõl‡¯›¿ó“·ì}¢ÙÄÕí¤Çú™¼ñÁÓì©Èö´Ñýž¿ðqŒ³q�´lˆ°r�´o‹²‰®äŸÀò²Ðý¢Ãô§Ç÷ªÉù¬Ëú®Íû°Ïü³Ñþ):Kr˜Ðlˆ²©ËþÆÖík…«!ù,ÿ€J‚ƒ„…†‚H‰Š‹ŒŒ
JI“”•–I�4DŸ ¡¡4�0$=«¬­­$09JC¸¹ºº7JBÅÆÇÇ"J/AÒÓÔÔ/Í,!@Þßàà!,6J13?ëìíí31	J*øùúú*ó-”ðA° Aƒ%´˜‚À#J”x�J¨ £Ç�kx€BI)(Â²¥K•)t(9ÂÀ\ê,‚sƒ�”`0`A€Ñ£H‘Z0€!¨
vH�J•j.>(9!C€¯`Ã†• ã„V.©¥ÄÁ%FâÊ�K—î
%GòêÝË—ïŠ@;
__CPAN_FILE__ src/widget/templates/images/clock.png
‰PNG


IHDR––<qâgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<$`IDATxÚì]	˜]E•>õúõÞ�¤·tö��„€paSqØ\pçw™O?åÓqÆÏuÔudåSÑ7ÜP¶AÂ*²oIXHè�¥;{z_ÒUS§î­ªSuï}ï¾ÎëÐ�¾nÞ½÷Ýwû½ªÿžsêÔN1! \ïP³|ù†Ü®„2‰¾w&Scå¼Ý�åvõ{Ï¬Þ£î��/AµHîß-·åüK°¦°P6Ëí,	®MìwTÈƒ'ä¶"kêLÊ kävb.4}¨2)— –®ÌKƒuåøý
–5ó„–qsU$°œ�á*ÃU™å„¼Ñ0~¸Ê�5±q5nÈjÈ3–ËZxÊŽ
Ç¯ï3Te’+“X™dÀÊ$“X™dÀÊ$V&™dÀÊ$V&°2É$V&°2™š’Ÿê
P-[`Z-S[c
ƒújuUµ•ª+*+˜Üä>‚œŒŒâ&`h``D@ÿ0@ß�€žAÝÁ6t Ö”PkC°5Ë­©ŽAmU<½'Žž“ ËË­ˆ¤�D¯°·_Àž^»Â
Á–ë0“™ÓÌÂmzNîç *_@i$ésµ¨ñ$XçÌŽ‡¥öÚÑÍ¡s¿Üº…Ü°&«Ì�šhn“Üfä`NSr¬<`*p˜©„@ž×œS—˜Ú¶—ÃÖ}rÛ+`_¿È€5Á´@vàüf
5¹’Á4VÀ%¥ºù C€k�õrxy�€Í{�eÀš€²°…Á¢Ö,”[…§ž
�¥\šË¿OÐô5ú=þò9Ëfå c‡MrëØ-2`MAÍ´¸-§6¿ƒ ŠÝ?
ÀðAX$¿?nwrµ¡&Ë€õ
H[#ƒ#Û,i¯Pá(IÀo@•
0}^_‡È|i&_è…w
ØÙ#2`
AGxi{–ÎdÐTŸ^Kj@¥˜�++„4‘rËaÃº¸YfÀ'™5�ÁQÒYÔÊL‡LP%i©BÚ÷ñÁ9ù¡bnÏwb¸BdÀ*·=›ÁòÙ9˜^›TcToßÜ²úAøÕM«aé¢yðåÏ|@�bí¸åÎá…M[ §¯N<n|ô}—BC}mÙ´—.|]Ô
Ð,AöìvÏmŸàšðs…
Õ§,ÊÁ©‹+bA…¯åÊö»aÃÆ-pæª•Îù
P'®X
?úÖ§áÆ|A�»ö‡7–m$éÿúŠ¿ÛÛÛ$ÖAÈÌF€“eC.Ÿmèñ4}¨¥®ùè»`V{‹sþò7Ÿ
œsª9>óÔãá¾‡ž*k˜Â?ï¿b[`›`Ûd¦pŒa„ãæ05“ôO_ªT38ÓH_Q4Ôäs°v›˜°a‰		¬ÅÒ§X1�©i™8PMý‰5"ær<{dJ›Ox•ì½Êœ€�»2SXT–Ì8qAÎ€*8I1+t¸¯úØ—á¼wþ³ãˆÿê�wÁ¥ïÿ,|úKß/¨Ð‘—ï²·œ]ògã¾g±ß·�m„m…m–«¨ÚVÎCNTº†ö�ï{ð)8ÿu§¦rÄFÐ‰ÿâµ7ÀGäˆpöÌ–’?÷=ÓþFÿÛ
ÛÛ.VŒà�úøyÑN›¿´Îº ã�Æ« üÒµ?U@¥Ž|)÷=Óúaþh7l3l;lÃXDæ5IŸj.²Xê©™WÂ¯BP¡9=ñ¸¥J[�§”ò»ñÛÛÛ2sÞçüŽ�0½6>–“Ö<
AP¡i=ãÔ•ÊoÓrÆªãÇdKuæãŽéhÛÛiÑ;{¦0°0Ð·|–€¶VL¯¨0¨�´¼çÆ^×X_7®š+\I kkªM†ô½‚ÀRß�‰�¹­;,àr‹p_�L]gÞ,,5ÈÂ�y÷î{–ÎÔ
ðø(Ùš££¿‰2·çk!
²‰"q“ØçêðXSÝÀh×ª¾`ª+ÕÓýôŸÀöÇ#Ý}ê5Žkµ!×ÈåL/‹"<áI¾gÏÛ¯g@(ì=ÔDøifïgÞÿÆQíŽnOï¬¾’&p¢€§XÛPÁ¶]6Ó6¼jwF÷3Ó 	áÁÂ÷„ÁGHýYÝ×FíØÏ†=!b%°„ §…ý£œÅê1
@(ÿÆ‚l\x ®oŸ&`Y»pF6þHp¢A'*¸ü÷â6lclkcgˆ.°VEX%a;Øà@ppúUµ"„^&5–ƒR‚¥mB¤ZØ…Çæý]¸ýœþ~Œ|y¡á/ ªBÀ’6¡&UKÕV™”ÖFØÆØÖ�\Å¡4í3áX%Á(Ð´æ"ÓNØçöSDŸ„íû«û”­�eïî…¶XûY`l/¹–þp`æ‹š�¢ŠžpÒBûTår¹HÌª®U\H@±<Gsø^©ñ£ñ]Ä}ÏbBv½o€Ýçœ›ýÇ:<Ûiýdå3ÛoúØöñ¹œ?nFáÂŒqöo|ÿÎíµ¹rîF1G|r­õí­Ó.„Ážú§EŽþN[¤fQ@¥	ˆfÚ«0°(¨è†Ã³¿¾°»ß3…Ä·bFE1ë`™CfŒƒ˜$ÝÐW³î¼ì_Ö¡²oÌ€cåW%êÏ:uÌ˜Lm¹uÃó‹[…Šµ¤ñ£2P÷µÒNÎc›/nCI8>‘ã.ƒk.Í'>sFÔç8ñ±ƒ½Xç�ÞÈñ©�GO¸6Ú5¼s§8¢%É+Flû¹3Œ‹mú,ÐL¤Ó„;×ÔŸÛÁ‰ù¸Lª�¥Ç�Øª�€Éuîìçoæn[0‚%Žd²‘àøŒµ`Ûc€ge¨ÕgÄgÃÂÑh€œ€OH©Ñõ¸@‘aª£Ž(p¼·ÕˆÃîæ7ƒ|bŠóÓ;wì�o¾n]ý¼çíÀeo¶”djþê&;�‚suÅ?åÛ/…�¼7àÛû<ù¤È=j­Í{�h¥¾¦r†€Æ�ãêÿ³(.B¿LVsÔ^ÚX7CRª½D$€Ê­
kãšD*àÉu/¨†òÐT~
—¿åløÎ?¦æêpÞGVSEâøöß¾þÆÔZÌDå›<¡,ñ…+À£ŠÄDb^¡öÊY?Š:cÖ4ª 'QsàØ[­¯ãÄ¹“¯³§E3N#çŸ³
®zÛºï­òI=cÕJµ¡ ÷çç�07UÄçÛc[Ü÷ÐÓ%ß­Ç¬i"bê¬¯äD§ìLŠ õ}k!Ü(¿ÒXLØˆ©ý1íÜÑè»Úàœ/|nî0µJõ—ôõh–.vµš‚Î®ÝSØÏ*�o¯ÛûûDPÿÙ	~{ÁTÏi·8\¾¿–³*�$òÐ¢QuÇ�?ÎÃ
€:ýÂAþ´j+êdnúæ‰{x~ª
òíÏH`Åk[¬È3½F[NÜ,cPý/œ¹_A"ë¾ÓïOñ �0bbWÜÑfÌÄª¨ßÅÕuÌ<ÁñìéàÐŒ3)£#/Ý€Ëß|Ö˜>__…YåvZ&xånô9ªÝ8Q6ad?t“çá9Pû9A<¼9'ö—“÷õ{@‚Ÿà8t@L#H`•–‘d.Qå÷öõ»S"½ýò|Ý”åÛÏ
i=ci[ìîøO¤ïl,!¢XÀ7�t À­ËÙ¸“ “ÐÂ1ø£?`fG–Ü|‘Ö¡j-”C0•"ü§Ö÷»w)ßÞ¸²oÚ¨åá¡‹ÁµdàÒF¸uÞEhgµŠs´QøG…f0€«™ŒéäîfêæÊÛÄa6ª~^@Pá“‹Ï©ªròí±oÚÂlj£?Ì'®�Þ×ÀãÄ¯M&^O}2 Ôdâˆ¡yPÓ7l¬, ü©ð}Á,_KÅ<Dð~[C¾l‘t|:_�ëÃ×|K�	A6ÖÔ«É*±|{ÙÞØ³Š´CR"ìÌFkÅ¨�€–¯œ"Ÿr»6Apj-Í0 LÂFÀ+®ýÓváÎV»œ&7‡A¥"Ê£h”ûùÇWBMUÎPc4›¡«7ÔF�Ò¯šÝÞbtGˆåHmŸl»/ÝqÔŸå _õþà0‡[×Œ@Ï @”Cààp›½è¼�ë}(¨;z¹æ»S¶Bx#¡Ãöáû2Ï°o47DK^ÓÆ(¦µ’¦jPCM%-åÇíâÚ2�$]‡}ÔRÐ3`ûšOŠ€É?�™[;Á•Aä¨]µq-A�%Âá$×ûÁ°Ò�eï7×gÇ“Ešêµ‹£§èx8ò·£B ¼/ÁMd@§žFáƒëòŠoÃ,2DÕ¢RÒÉGW£	2)9£.ë°É"Hºr˜%÷)ÝÃ}µºP,ŒW13+£†Ž.á,41…$GM1ˆ:Õ'†Ò(×Rá¨ÌªJ¡–ñÍ^Ò~±÷2)ÍÔùf/é=½�}…œøáQ*’t–Žãî¼í+íÌs�— y—`Ä¹áP�×æ
’È(k‚ {ZMj*Y�IHì«ÆZ»{¸“�ÃèèO�öW¯†%ÌÜŸž—A¿;o¤fÄiÙ~>ý�ºl0ø f7§U\o&å%»Gñ»ºýžf`yu4-‹;ùÂAˆÅR^ä}Î–Þ§y.„üsÁ=p*i$XªË´^é#½b×Ç}Nõ™^šõ·½QŸpá'b¢ù@¥YõI�+œP8CSsNž¨«ÊÀ1Ù@‰}ÆA8c6’Ýg?§ã¢ \§Û'Ç'ð±4E†:ZÖ¾º)^Ê˜›ÐÈìÆåÔ¨*ö�òB@Ë@8>,N[Ñ>Rë5r×%
âSÖÃfÆg‚H4AWðÈ›k=Ü‹ðÛ‰�å!ŒuK0“Û¯¿BMeqÀÐão¾n¿ûaµ?«­ÞóöóaÉ¢yÀRÊãkÖÃ�ºÛ$äžpìøà•õu5EG‰Z°Ï‚éæ¥
3�ÓyƒOœ¸KÌÔ}Ðæ1ðhÀÖZ;Ùhø6ÜònÂén(Å )·Tq÷H_�ê®‡áŸ|/üðëŸ”€š_úÎÏÊ—˜jÚ	§¾Î;{\ÿ�O©6|aÓVøñ¯n+ÚöôûÌ’`xHEçf‚Ùe´p[“#Œ�ªð*·ä.ÂÈ»š;Â9$Â…‰¶;e#DÀÙrøÒ¶<`Væâ§ŽÿïîGàÜ³N–šªY_ö¦³Ô\`Ü¼X&ñ‚Ú]³<pÎðÜ³O�Î�{Ma\¿`ŸiVƒÂ•V.º0L¨L¸V6*:¯“T9•ÕZ9—[Ãm–ŽósnBû\‡î¹pnÊ
9ä+XÑ�~ÅXrÄ\ó>6Ì	Ç.UO]¡ _¦­âÛM!Z€Ž9²¨åŒà*B¿˜“Ê@œX- 4tÂ€ñ¦{,…™{“ÐÂ¸L†c2eÉSæb¦ˆ—0n[.©œw|E Ñ§Ïõö÷gè)Qž\·6lÜ
·Ýý�ò±Î=ë”X+‘ä¼ë>ê¡Š
R‹Æ/…›zèÔGbVcqŸªM"ðhYˆâèk|P®Ð¼øü3à'¿¾ž”¦¯§·¾û£ß*mG‰É´Vrà ýÓŽY÷?²Fåg&i¬B}`�;YðÃ¦õ®D„Q`&/D4*�£²ØsÑÒEè¯áºÇ®Æò÷õëÅœ©Tã�·Ü«þšAå7„æ1?¤xÎšÙímM°Rš@|½A>¬¯yõ±Aårµh¢oòÅ‹ŠÛ	<¯>�£·È”N8Ü¤¶|¾–§½i#$Z+Ü'¡�9D­u‰ÿF	Ÿ¾,ÎUZœJoGÊ‡²sçí©Ì ì3Í¶…Ù˜�]
1àÅæ=^Ÿ4_Pó²Lˆ!’<A†¢@Ò€tÅÐO5*ôê)©¾"‡Éºêâ‚×ME“˜ÔøŠ®Œ	®�÷bfP›>£»îc$4rÀmy«0ƒ^aœÔdÐ¬PÚ$v*L\_‘+˜Ííh]òKˆªÚ$sˆ¡…[;¶Á‹/mƒO}ð�ªQ2˜^®ùêT¸æµ§¬€¿<¼FFßuéS›Aì3m±(»…éQ¢žÃÑ¡Äˆ
O��L&.S¦�“¢k,í#`B†D8Jà`g
9©¶ë‘Tå[C£ò½¼¦$pÕÕUÃ‘çÀé'§XLÙç¸i ©¼BÚ
å×ý‹ÊÀ<Kô«Ú[›Ž{1Pá«ê3Åµs+Ð˜.æš2ãNá˜*Ž6ŒÒ¶‹‡f‘Ð$œ:\Ü�� w"Rb²ˆÇ‚)îG6ÔÕÂñËÇJ}¿`š
à*æè¶ÄÁŽŸ4áƒHDªÄØ÷±Ï4�ì4�)f S>\3J!Ì„@…
&/È".“Tã…GPát7ÓAºÁÑˆã^h_(‰Ÿ5U'­ÓL*Ç9ïIªÐ>ö™-F›8S»�F©Â9cZ÷ÝÄ8yÌ¼¦‰Òùg7Hê†"Ül@ý^ÏÀ�T€*T,Ìd$¬2:•Ã¥h£4Ã>3á”ì`ƒ‹hH!¾H_è2	M›‰I%s?Zˆ—îþ©P’Ù+¤•¦‚ILcÓ„ÒnÝý£î=†#�/ÂÝ×�É+tïí¿'M†Ål¿ü’ýÒ¬—ˆKÒTÅÂ¾YL›Œq8ƒ*iJ&í÷pc_u÷�€p nžOx‰Íææ-ÃÂ,á•öVÈÓ‹õ�ÊÞáÜ³ILµõ)íâ>C#{{@]uEâ�‰3o…–KóMâáêo¥%ë%Å£
=´IöfD›|›ì`�{'‹cžù“)BnÁdø‚8º0¤¾på�K&\+õãQv÷€9ÍU‰šª�¶ò�zß\ò·Š™ÕÉ¨´ÎR5½ûÊ.c"‚ÈBô‹Ø0å+“(½
W„š.ð±´)àŒòtŠ�ÒC!¸èŠ3HãÖ
wÄ¸«{X¾Ö%‚¨ØtC1sXÌ™ŸLÚ«PŒLö•5ƒ´¼u¡4Ã��;·,,×ÝÕƒóyº¬˜­ÑÀ-=lô““USxÄ'³Ñû]Ý#jš º2W°Æ2BLÒR“\q¿µÔ%MÆªµôTÎ®ýÃa. ­ÜgÖ$déÑbråCã(¡¼e‰ê|gn LçPâ<÷Ý6“ùJg©÷÷�@×Þ!˜ßVS°h£þô7wÀ�®U÷[rÄ¸äÂ¿QÅB’4Öd2�Å´T1PáüàÕÿö=øü'þV,_<f�…}„ƒ-4
ÂK¯×8ipi×Æës[û?°lf-§¨-Rk
ª¹õ'iñ-;Qi sßpâSDKêÄ½þîÖû¨þý³ÿÿõ•�C}]-|í?>&3:Ñ&®TÈ[ûÚu?·qÅ”m§á:%°„à&j.œ¥n´ÃÎ
³T²÷«fƒS=;P�Á
�q[>PÄ”Šä!‡GëÕËŽÀÝÎ=C0ÊÇö$=ýìFxÃ'A}m�iòÚ“�SLÓb£Ÿ8·ØùC	¨4ß«¨P~+:œ
;X_û¦sßØÚì�²P<^
xN’r„YV‚;å¼y˜PÃCÚ½Ô¯Œ+è­¸Ã‰vêº¿ßžéÜ7[w–lÿñ	[´`¶b=`A[<¾ýîGë!M|¦˜f8”+ô÷JáÝÿð•€rõ.w®KÒJ…Ú
û¦sï 8Ë)ÝÀmñb®Ké<º’…îtRF”L^çÁ«,)¼å,°ÉÝâ‘Üjíø@Ý²kæµT}"•¢ÄÎH¾–ò–7œ;ví…úÌµÐÞÖ}ýð¯W_Up�˜¸XW!k¼ý¯RçúŠš@ù�]÷“?À—¼f¶Î°áªR¶u× ;ÂÓyƒfÞX8¡Zÿ›úØÂ¼1r}.R-lºu´ü²�5Ð5T(ì9Yd¿¼žà,¤¡üs}ìØØ±Þzîká´“Ž‘škP±KÓ<‰Åâ=Å¦@V3¥ù[IZª�¶BP�öêcáõÒE¤�KÚ6¥öÉ©±üåÄ”æ6ÉÉ¶¨åÂsH–îEÞ|Åé\ùùè, Y¦W¿f‘3AikuÑ‚lŽ†9L«ÍCÛôªXæBÜÂMýCðõïÿÞ}éU#½d¬\~$üì·V\£ùsfÆÆ¸’b_I×ª‘âXB
>Àn¿ç9 ¹_QŒ^ìØÏ½°Ö<·	*++`ïþ8bþ¬X0%ì…­ý°~[ŸÒ.Ì›Ãc&J-–pŒT_ðÉñ:rŸ§ˆ±±0¯ªØ¡Â/ƒ+l&ìg‰ÈoÞ9GÏ«ƒŠŠ\b£R3ˆlÒ¾þAXuâÑê<`Ñ‚YpäÂÙÐ:ð¥HR¬k<Ë(�uä—¬ã�^Ÿûø»�ÁÊÌ–PÓV££^’}¢û‰ÈÂù@³¯îpfÉ8Ä«in‹A/)t™òÂ«¢!Æ“0=1¡ö<]UÕ/|#w^–?bcg?,™Si\
(½ßÚ2]ßyÿðºÓO†Å;v«'õ"iãü“¸ÕÒøcÅ€PJ�¯±úSÅ ¸¡OÕ&ÛÅ'ò!¨Î�ª$€mìê‡-;l_ÒïDÿ è¡ÑÞ†ySì!R*Ò=Ë¬õ‹™ÆaŽ
õKxoêŠVÐÚš§ÃU—Ÿ¿¸é.Xûü&Ù¨M°ú/OÀEo|
wÔ‘Éìbëô%MÅ¯ñ¯´¦¯PÐ8Îwô�L†¤×TZ^’¹ÄéÖÎ9‹2ZâKE
÷<¸¥"5`Ù'¿s§ðé1^7Ä¬\îäÙYÖ€Ÿ³²U�+®Æ»_û]?³¾CéZM_.¶i€Z°üPø[…ÀU*°’œóµÒÇZ8¯êj«# Jô­¤_µú©Ý�JÄö7sŠkGqà×òcÞ1ÐXÌ¯ÐÇÏ†NRA7#~˜[\£NÓZñKâ�ZÐVU•‘F§&‘³l¡êtíkiÐ%M:—R‹«˜V;XSXJH!‰úR,Ø6qç“@5<2*û ×ÑV®GN|fG€4}U0ZyÍ5].³”Ù8VÄ9Š„«4‹Y0™RÞÂ�fP.kèøuHs¸~k
»°1¶#âÀ$
²¸uùÊ1ùÇ;ó—P¥FÒKâ¶~ktìè·Åi™›$AŸ I‚»z‰dJGHÇ1k†ç£åk­©Ç)³~”££„pÀhF`Úßbv*iÃÖ^˜Ý\
Í�U‰àòÁä©˜Æ*VÖ{<XãåW¥M1ÿjOÏ0l�ÚÊé\ÁœŒgn|'f½d^˜IÐQ¨á„v2¥"'P)eîØÀ.NNœ;Z Ë7X¸ô¯y:Â»ö
Âó/÷Â©Ë›
vT’¶J£±|ðŠDŒƒ�U�uÞ/m¤ýù-=Ðµg,Ý“ŒÄÈ°ÎVœÑì)t•.¥Ä€›º´äÂA€Æ�ácñ°aKØ‘Øò�`X¦A�JæˆAf<{„Ý£®yNþÈ¶Upäìú¢¢4ë¿6mÞî\ƒÛW\òU+¢\t›±Æ«>xÍµ*c'“õðýš�üÝ˜5V¡íÅí}ðÜË=Žµ†´gcX6ÃÆÒÞ].» <-Ðia‚9‹”ë8¨qÞ™—Œè¤Œ•HKP2'†E4��1á„'†¤ùÌænh‘æpFCeÉÚ!��õŽ‹ÎvÎïØ½>tÍ·á´Wc>Ÿf5Œb<ü±A»vî…¯|æý°hþ¬²±Aã¶}½#ðLG7
s7Z3ÓâdÒ`§ðÃ„¢®—I1KÏÙß˜§«7ø�Nï™3ô2tl£àrmt¨.·í„µ/uÃéÇµ$<fóïñû[ï‡×Ÿñ*dL"
ÒR¥ª¨0Ð«‚›óÚSg-—Êc×Çk_ÚÛv_(ºf’é‘¹]£ÃíBáTT¦‹3Q’Ÿ¾GÎ1“Î­è¤³]Ù	ÈJætÕ'ˆüqˆjÉZ×±ÖlÚ_¶§S¯ÃçGŸ±ðÈŸïV�¸<‘çÆ?Wêß,DºÃrŽIëßL»aÛ®“¯éÝoÜƒK„šN“'ýìþ+À+±
~˜¾â´s¯ø<]\‡z)Yî’‘È+³=š;ÏLU!Õ3Bca)ÂðÌþ¾ah¬«„õ•cr�Ó\wÓ@Ue%\rÁé©XIŒ…]§V6ýÝm÷«GÎXs¡�6ÁÀæÞý½pßÃkà†ßÜ]»öÁÒ#æ@ee~Lš)î<F×Ý°†G„]Âá1ˆI!dÌ™+Öö“…þ6þâ§,ºL‰vÞš¼ðÔ^d‘\#DÄÚ¹óKþ‚ÂÓŠAÖôS/îƒÚª´7Õ$¥ÐÔMœéÔç�)±ú/OÂ‡¯zk¤\RBF€ð?7Ã_>þþKaÅÑ‹Œ¯7ÿê¬ÓVªMÑW¤öúêu¿„_þñ¸ò²7””‘TíÚ;OmÜ=²m#Ã{_·Dæ‡…Ÿò—8‰j¦¨Ò
Näàd1>)Áµ·g8UƒR³QÈœà+Î1"½ù˜¥M ÿÿŽ&T8jÓs•…¾KÒ¹¸÷jkªàÂsN�Gž|¾àïI3¨’Oeb[b›¾Ò’‡	 /uõCe>'/kR¦±�™‹‹²ÇFq»ùÎ‡á²7�«­
Qjè{¸ýÅhÅXßÓÏ¾3[š,ƒÒ¥Ä2»˜;Ð70xÐÅ=zúGà		*lË‰ XFå+rNZÚ
µùT£°80i@ÜûÐZUØíÌUÇ³¬$b ÞyaÈ°ØôòvØ¸y»â?­~àwpÎkN€·½å¬’¢ìI¯÷<ø´üŽ+­”†JCïÓ;paŸjÃ‰"X(ÈÃÆÒà*T>Àn½ë8óÔNÜ+)É5‰«µ1²^øºUð&¹¡œ¼r|î7¨IàcåV
ç
åCŸý´µLƒW¿î}p�âŸ]|ÞkøÓ”# ûªÇ6ì…ç·ôN¤®œXÀBÁ•müª%3Tµû ÐÔÍŸã�àJ5ƒÔA¿àì“ÍþyO‚nù’ù%›Ãk?ÿèØºCiÃ�½ï­ÐÚ4­¨¹KzÅ(j*d-L4™pÀBÁ†‘è:añ9Z¬NbðÁqÔâ¹å¦Pj~RQìt)o™­(
í`�Å×š?»5•ÿT0z¿wž”£¿Ž®‰¹’G&¨`ƒ=ôÜØÔÙ—:2],Øi]¶45ªå-w=lÞ_·¾^ÚÒ'­XRôóÅFˆi2–ãzll›‰
* �¨_®wðìÜ7¤‚p3§Wd�&Å”Š¥â:ÎioQ¾Ð#Oo€­�»á¶»…KÎ?]™Ábihi�ùRÞ[ÛÑ
�oØ§¨0YØ'¾yë¤¨ÈìÂipÌÂF¥OK=NCM.vl4¨ô‹0àŠ~Ò�ÓÎ¦qèÓj_N(÷ÀºŽîÉÐ]ÓÇŠlÐ½½Ã°|~#,NA¹)5×Ùôü‚9mA�dcÖÆí}ð¬1oÛ=8Yºkò…íÜ?Ëæ5BSH»)VW«Tp%$í½Ë²½rÔ·~K<'GÊÃ#|2uÕä
6ðÓ›ºU	ÌúY6·AEí‹,­¦+Ë´Þ{±ã‘ÖoíU	(;ÐÇœ„’‡I*Øà¸mÙ5 Ø¨Kæ4$†
JÑjc¡0—R—«¸0Ô‚¬ÏÍ;`2K&¹`à†T‘#fÕÁ¢ö �¿¨JÑncU)àÂ´wLêÅß°©ëðXa6‡‰`‡à¶¡µÌ¶†š|Éþ×X}¶±h3§è5ïá$y8Ì;·g7WÂ<	²¹­50§¥r^¸¡P’j¹RëãÞÇ"8ÁOø=ÑA?%‡©`‡á¶æ¥n5-4«©FnÕÐ>£ª*s‰±«rTûóï�Ž.éâ€¹R8s¸K¦€`Gâö”ÜŸ^Ÿ‡ÖiÕÐ:½J%Î67VBmUEYÿÞÀð(ìéQÑq,w½«{ö÷€©$y˜b‚ŒŽ¼P°ýôúJ˜V—‡ÆÚ<ÔK¿¬®¦B�
ß«Êç _ÁWL9Ú\À�QÃ¸ª“Ž ê…>é/á*ZH·ÆräC“,î”«Ì‚Ð¡‹LÊ'¹¬	2É€•I¬L2`e’I¬L2`e’+“L2`e’+“X™d’+“X™LIÉ3(_‰j"kÑI.åÂj¬Ñ¬93)³Œ"°žÉÚ!“2Ë3¸Øøwé²áó_&“_Ê„…ï¢Æº^nwdMšI™±t}î?}¬‹äöÍÌßÊä`üªC!¦Í(¹ú?n;F¾üƒÜV„[[Ö^SZ�¸�É…ª‘¬	·ÿ–€2þúÿ0¿LKºgQóIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/soriaPressed-c.gif
GIF89a6wæ†¯ì‹µó‹µôz˜ÄžÁô˜ÁþªÉù•¾û‡¯ì±Ïü�¶ï Âõ³Ñýˆ°ì�¹÷§ÇøŒµôµÒþ¶ÓþŽµî�Àô¬Ìú¡Ãö”¹ñ—Àý�·õš½ó›¿ó¨Èøˆ³ñ˜¼ò’¼ù–¿ü”½ú‰±í˜ÂÿŒ¶ô¤Å÷“¸ð¥Æ÷®Ìú†°î£Äö�¶ï«ÊùŽ¸ö’·ð—»ò–ºñ‘»ø‹²í¯Íûˆ°í´ÒýŒ³î�´î°ÎûŠ²í·Ôþ²Ðü‡²ðŠ´ò¸ÔÿŠ´ó…¯íˆ²ñ‰³ò‡±ð†°ï…¯î…®í…®ì!ù,6wÿ€‚ƒ„…†‡ˆ‰‰#Œ�Ž��‘’““–—˜™š›œ�� ¡¢£¤¥¦§§ ª«¬­®¯°±±´µ¶·¸¹º»»!¾¿ÀÁÂÃÄÅÅÈÉÊËÌÍÎÏÏ1ÒÓÔÕÖ×ØÙÙÜÝÞßàáâãã-æçèéêëìííðñòóôõö÷÷$úûüýþÿ„@° Áƒ*\¸P€Ã‡#JœH±¢Å‹3j| £Ç� CŠI²¤É“(SzüÁ²¥Ë—0cÊœI³¦Í›8sêÜ9³‡ÏŸ@ƒ
J´hQ!H“*]Ê´©Ó§P£J�JµªÕ«X³jeÚ¡«×¯`ÃŠK–l�³hÓª]Ë¶­Û·pÿãÊ�K·®Ý»xó®åÁ·¯ß¿€<xˆáÃˆ+^Ì¸±ãÇ�#KžL¹²åË˜3k®L¤³çÏ C‹Mº´éÓ¨S«^Íºµë×°cËž=;…íÛ¸sëÞÍ»wï"ÀƒN¼¸ñãÈ“+_Î¼¹óçÐ£KŸN½ºuë@²kßÎ½»÷ïàÃ‹O¾¼ùóèÁYÏ¾½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€aà�&¨à‚6èàƒF(á„Vhá…f¨á†vèá‡ †(âˆ$–hâ‰(¦¨â„´èâ‹0Æ(ãŒ4Öhã�8æè"<öèã�@)ä�C6`ä‘H&©äÿ’L6Ù$
PF)å”TViå•WŠ å–\véå—`†fd–iæ™h¦©æškÊàæ›pÆ)çœtÖY§
xæ©çž|öéçŸÞ è „jè¡ˆ&šèŒ6êè£�F*é¤“®`é¥˜fªé¦œvÚ© †*ê¨¤–jê©§º êª¬¶êê«°Æ«	´Öjë­¸æªë®»^àë¯À+ì°Ä[,È&«ì²Ì6ëì³Ï¾ í´ÔVkíµØf›­Üvëí·à†+î¸ãj`î¹è¦«îºì¶ÛîðÆ+ï¼ôÖkï½÷R ï¾üöëï¿0lðÁ'¬ðÂ/àðÃG,ñÄW\±ÿg¬ñÆwìñÇ« òÈ$—lòÉ(§œr	,·ìòË0Ç,óÌ3Ÿ`óÍ8ç¬óÎ<÷Üó@-ôÐDmôÑGs ôÒL7íôÓPGµTWmõÕXg­õÖ[³àõ×`‡-öØd—]vh§­öÚl·íöÛo£ ÷Üt×m÷Ýxç�÷|÷í÷ß€.øàƒã`øáˆ'®øâŒ7Þx�G.ùä”Wnùå—ï ùæœwîùç ‡:¤—núé¨§®úê«×àúë°Ç.ûì´×^{¸ç®ûî¼÷îûï¿K üðÄoüñÈ'Ÿ¼Ì7ïüóÐG/ýôÓû`ýõØg¯ýöÜwß½"à‡/>"�;
__CPAN_FILE__ src/widget/templates/images/tab_top_left.gif
GIF89a�,Õ;b�Òåíøíòúöùýúûþòõûßéöèïùýþþâë÷•¿ÿŸÆÿÝçö­ÎÿÀÚÿ¸ÔÿÚåõØãôÖâôÈÞÿÔáóÎâÿd‘ÓŽ¯ßh”Ôf“Óçîø�¦Ûûüþ¨Âæ¹Íë¦Àæ‹°æ•´á¡¼äãë÷”¾þŽ´ìŒ°åÓàó§Áæ£¾å×ãôÌÛðx Øz¡Ù¡½äÍáþºÓùáê÷ž½ë–¾ù½Ñì¸Òö·Óþ’²àÆÖïÿÿÿ”¾ÿÿÿÿ!ù;,�,ÿÀ�p§él,€¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°¸:ô`dµWeÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€�‚ƒ„w;&0Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥›;" «¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄ¼16ÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãÛ)%
èéêëìíîïðñòóôõö÷øùúûüýþÿêc1c�Áƒ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±£Ç�3�P@²¤É“(Sª\É²¥Ë—0cÊœI³¦Í›8sêÜÉ³§Mÿ:‚
J´¨Ñ£H“*]Ê´©Ó§P£J�JµªÕ«X³j¥
t«×¯`ÃŠK¶¬Ù³d»¢]Ë¶­Û·pãÊMªv®Ý»xóêÝ‹¶.ß¿€|×/áÃˆ+^ÌÔ0ãÇ�#Kžëx²åË˜3W­¬¹³çÏš9ƒMºô`Ñ¦S«^í5ë×°cgu-»¶íÛHiãÞÍ;¶îÞÀƒ�þ-¼¸ñÉÄ�+_~89óçÐó:�N½zÛéÖ³k‹}»÷ï›Á‹/¶;ùóè…šOÏ^üúöðµ¿�O?úüúø•ßÏÏ?øþþâö_€úVà�Ù
ˆà‚¤)Èàƒ�9á„–IHá…�Yˆá†ˆiÈÿá‡�yâˆz‰Hâ‰”¡¨âg&®èb_/ÆˆœŒ4fXã�‰µˆãŽáñè#_:þ(dcC™¢‘H¶–ä’kÉ$’N>Yd”R
Ie•>^‰åŽZnyc—^Òf˜1ŽI¦‹fž©bšjžÈf›#¾	ç‡rÎ¹a�v^ˆgžîÉçƒ~þ¹` ‚Hh¡Š(€Š.Ê_£Žâi¤ôMJ)|–^Ê^¦š¢Çi§ä}
ª{£’)j©Þ�Šª|«n©j«Õ½
«}³J)k­ÌÝŠ«~».©k¯Åý
¬Ã)l±¼‹¬€ËZÙì�Ê>+[´ÒÂFmµ¬]‹­jÚnkZ·Þ6®˜ãÊn¹ž�‹ÿnhë¢ÙîŠê¾[¡¼(ÆKodöÞk£¾ æË¯bþþÛ¡ÀLðichpÂ€-Ì0�÷1„OŒWÅÛ…qÆrmÌ1\¬¤È‰’\²ÉŒ¢œ²Ê�²Ü²Ë’Â³Ì•Ò\³Í˜âœ³Î›ò¼é@-ôÐDmôÑH'}ôD�„ÒPG-õÔTWmõÕK”��4œ@Á×`‡-öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×m÷Ýx¯}È7à Áß€.øà„nøáˆ'®øâŒ7îøã�G.ùä”Wnùå˜;¾Ã!Dàùç ‡.úè¤—núé¨§®úê¬·îúë°Ç.ûì´×nÿûí¯�`�
ôîûïÀ/üðÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWo½ó ÀÀöÜwïý÷à‡/þøä—oþùè§¯þúì·ïþûðÇ/ÿüô·ßÂ
ä¯ÿþü÷ïÿÿ HÀð€L ÈÀ:ð�Œ ˜$à‚Ì 7ÈÁzðƒ ¡GHÂšð„(L¡
WÈÂºð…0L!@ÃÚð†8Ì¡wÈÃúð‡@¢‡HÄ"ñˆHL¢—ÈÄ&ˆ¢§HÅ*ZñŠXÌ¢·ÈÅ.zñ‹`£ÇHÆ2šñŒhL£É¸ñ�pŒ£çHÇ:ÚÿñŽxÌ£÷ÈÇ>úñ�€¤ IÈBò��@ÉÈF:ò‘�Œ¤$'IÉJZò’˜Ì¤&7ÉÉNzò“ ¥(GIJO`¨L¥*WÉÊVºò•°Œ¥,gIËZÚò–¸Ì¥.wÉË^úò—Àæ.@€bó˜ÈL¦2—ÉÌf:ó™ÐŒ¦4§IÍjZóšØÌ¦6·ÉÍnz›@€8ÇIÎršóœèL§:×ÉÎvºó�ðŒ§<çIÏzÚóžøÌ§>÷YOäàŸ
¨@JÐ‚ô M¨BÊÐ†:ô¡�¨D'JÑŠZô¢•¨?3ÊÑŽzô£ 
©HGJÒ’Št£&M©JWÊÒ–ºô¥ÿ0=(JcJÓšÚô¦8Í©IgªÓžúô§@
jMy*Ô¢õ¨HMªB‰ªÔ¦:õ©P�)S£JÕªZõª�*V·ÊÕ®bU«^
«XÇT°’õ¬hM+KÍªÖ¶ºõ­e+\çJ×ºT®vÍ«^ßŠ×½úõ¯aí+`KØ¨
¶°ˆMlQ«ØÆ:ö¦Œ}¬d'»ÒÈRö²˜ý¨e3ËÙÎfÕ³ 
-H7+ÚÒš ¤=­jA›ÚÕº³­}­lÛÙÚ±µ½­nÿšÛÝúÖ®½ý­pù:Üâ^6¸ÆM®X‘«Üæn•¹Î�.U¡+Ýê6•ºÖÍ®Q±«Ýîþ”»Þ
/NÁ+ÞòJÕ¼èíÿ*yÓËÞ�¶÷½†…¯|¯;ßúu½öÍïgõË_�â·¿^j€|^x­NpJÿ«`3¸Á~0„,á	ó·ÂÎ/†3\ß
sX¾þð{C,bö’¸Äè=1ŠË«â‡·Å.î.ŒcœÝÓ¸º6¾qts¬ãæò¸ÇÉý1�‹+ä!·ÈFö-’“¬Û%3Ù¶N~²l£,e×R¹Êª½2–M«å-‹¶Ë^fm˜Eæ1s¶Ìf†mš3Œæ5O¶Ín¦mœ!ç9+¶ÎvÆmžŒç=¶Ï~æm 	èAëµÐ†n¢)¼èþ"ºÑp}4¤Ý*éI«µÒ–F+¦3MÖMsz¹Ÿq¨máëéQsµÔ¦þjªM¼êô¢ºÕÓ…µy_-ë§ÒºÖôÅµwo­k¤òº×Û¶v-ì²ÛºÄ>¶O“­lÿ6{ÇÏv.³£mÓiS›¦Ö¾6L³­m—r»Û÷‘Å=nr+ÙÜçFw“Õ½nvCÙÝ¶
;
__CPAN_FILE__ src/widget/templates/images/treenode_grid_c.gif
GIF89a€rrr!ù,Œ�©Ëí£œ”�‹oÝ¼û†L;
__CPAN_FILE__ src/widget/templates/images/tab_bot_left.gif
GIF89a	–Ä–Àÿ Æÿ¸Ôÿ­ÎÿÀÚÿÈÞÿçîød‘ÓŸ»ã€¥Úáê÷h”Ôf“Ó“½þ�¹ù¬Íþ£¾å¹Íëš»ë³Ðùûüþ¨Âæ†°ì‡®æx ØµÏ÷‰®å‰«Ýb�Ò”¾ÿÿÿÿ!ù,	–¥ 'Ždgž&‡¢êšº/ÜºóZ³pwŸ{Lç=p(#þŠÈ£Òfd&�KÜSå5©Ð,vk�v«>íWæ–Çf¡÷ÌVƒÝdx:H¿¢ïíúZŽççí{zoƒq…s€~Š‡}Œ�„‰Ž‹‘”‚•�–™˜›†—�šŸœi
0©ª¯°
¶·¼½ÄÇÇÇ	"!;
__CPAN_FILE__ src/widget/templates/images/tab_left.gif
GIF89a	,Õ;òõûúûþßéöåíøíòúöùýýþþèïù•¿ÿŸÆÿ­Îÿâë÷ÝçöØãô¸ÔÿÀÚÿÚåõÈÞÿÖâôd‘Ó�¦ÛŽ¯ßh”Ô¹Íëçîøf“Ó¨Âæ¦Àæûüþ½Ñì‹°æx Ø•´áŽ´ìáê÷¡¼äÔáó¸Òöž½ë·Óþ¡½äºÓùãë÷z¡Ù£¾åÎâÿÍáþÓàó’²àÆÖï×ãô”¾þ§ÁæŒ°åÌÛð–¾ùb�Òÿÿÿ”¾ÿÿÿÿ!ù;,	,ÿÀ�p‡ÑP&¸áÅb*¹Z;N¥–ŠX#»‘çÁíŠ&'‡xÌ
)ÎhÅç–h»™bNGàtø<þ®Ïóû:}‚z„~€{ˆ�Š†‰ˆ�‹�Œ“’•€�˜”—šƒœ…ž‡–�¢Ÿ¤¡›¦Ž¨«£¬¥®§­²¯³±´·¶¹ªµ»¸½º‘°¿ÃÁ¼Å¾ÇÀ™©ÉÄËÂÍÑÏÆÓÈÕÊ ÎÙÒÛ×ÚÌÞÜàÝäãæÐáéåèëÔíÖïØçÔ8õöõCDFHJ(/HD©#†„ƒvlÑ ¡Cd@˜Hq
32XaC€Ç�2X@²äRªL‰ã€Ë—.q˜Is&8sâÄQ §Ï˜ž8*‡�£H�âÈÁ´)Ó¥N›B�šcjT«N±J¥ú”kU¯Z»r
ûu,Ø³fÓR%ËíZ·Wáf•»Um\»sñÖ}«W,ß¿wç¼7°áÁ‡#^¬¸±ßÄ�Gv\–ðäË•!g–¼™rÛ¾�1¶ºôhÍ§9§öLWtkÓ¯W»-6íØ¸oë&]»wnÞ¿QWý:;
__CPAN_FILE__ src/widget/templates/images/bdYearBg.1.gif

__CPAN_FILE__ src/widget/templates/images/dpYearBg.gif
GIF89a¢t‘»u‘»t�¹s�¸sŽ¸rŽ·s�¹t�º!ù,pþPC+x�Í‹ÿ	;
__CPAN_FILE__ src/widget/templates/images/treenode_grid_x.gif
GIF89a€rrr!ù,Œ�©Ëí£œt‚‹3¨¼û†`;
__CPAN_FILE__ src/widget/templates/images/dpBg.gif
GIF89akæw“¾y–Ây–Á{™Åz˜Ä€ŸÍu‘¼€žÌ†¦Ö‡§×ƒ¢Ñ~œÉ|šÇv“½v’½‚¡Ð…¥Õ„£Ò{™ÆŒ®à~�ÊžÌ†§Ö�±ä�Ë�ŸÍƒ£Òy—Â|™Æ“¶ê{˜Åw”¾“¶ëŠ«Ü‚¡Ïx”Àˆ©Ú�³æ’µéx•Á‰ªÚˆ¨Ù�±ã…¥ÔŽ°â…¤Ôv’¼�Ê‡¨Ø}›Ç‹­Þ�¯á�²å†¦Õu’¼Œ­ß{˜Ä’µèƒ£Ñ|šÆ‚¢Ð�¯â‘³ç‹¬Ý�¡Ï‘´ç”·ë~œÊžËŠªÛ}œÉv“¾w”¿„¤Óx•Àz—Ã� Î}›È!ù,kg€B &9A>%4*,=372?!E($)0		5+-I¤:

<"@L°D/CFMÀ1;8KÎ'JÖ#HÙG

.6�;
__CPAN_FILE__ src/widget/templates/images/dpHorizLine.gif
GIF89a€®Éñ„¤Ó!ù,
;
__CPAN_FILE__ src/widget/templates/images/dpVertLine.gif
GIF89a€y—Á°Çç!ù,D\;
__CPAN_FILE__ src/widget/templates/images/slider-bg.gif
GIF89a‡>Mc€“¯�ž·dx•q…£ds‹euŒ[n�`pˆy�ªYlŠBQis†¥HXrz�©� ¸q„¢€’®ižh}œ†˜³�¡¹]o‰k}˜EVoDTlr†¤J[v@PfWj„l�¡‰š±Xkˆ^n†}�¬Tfƒvˆ£\p�f{™Vj†v†žCSjn�žv‰¨fuŒ‚”°ŽŸ¸ŽŸ·_rŽ„–°FVoat‘Wg�k}šZm‹ey—hx’br‰oƒ et‹x‹§Zk„Pa|GXplœ?Nd?Ne„–±ƒ•°>Lbbv“x‹©fx“†—²Ug„‰›µ~‘­_s�=Lbtˆ§cw•Wj‡‹�¶Vi…j|˜�Ÿ·�“¯r…¤dx–?MdcsŠXk‰`D$^0‘A�ýp�\Ø]¨�î‘	p—äÀ‘>o‘>b`è`ÀlHý´É¨´Éh^:6nlýüýülEl^¨PQh^<ýül‘	E‘	Ná»]`À`T�î`è`d‘@.PQx^<‘	p—äÀ‘@ï‘@»ýü€�åå�H¬^$^,fÜh0	lfÅ¬:¬:nf¥o–ffÜh0	ÏÐ±¡agÎÁTS…ù¡fi!ù\,ÿ¹0ÀÂÀŽZ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±#ÆBô Á…*<pñ¢ŠË—0cÊœI³¦Í›8sêÜÉ³§ÏŸ@ƒ
Ý) ¨”%1HXà‚ƒB’!DZX™JµªÕ«X³jÝÊµ«×¯`ÃŠK¶¬Ù³`¨�ÀD„ IpdÅ®èÝË·¯ß¿€L¸°áÃˆ+^Ì¸±ãÃ@Ð¡H
*2Nx�0ÁÄ
, C‹Mº´éÓ¨S«^Íºµë×°cËžMÛõ€PŒÌh£CŠ
#”8`CÁ–ãÈ“+_Î¼¹óçÐ£KŸN½ºõëØ³kßnD”)J|ü+(‰!ÃB‚dYÏ¾½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿù  EPR@;
__CPAN_FILE__ src/widget/templates/images/soriaButton-l.gif
GIF89a6wÕ†¯ì¸ÔÿŒ´ïµÓþŠ²î�¶ð’¸ñ¬Ëúš¾ô©Éù‰±í—¼ó¨Èù³Ðý±Ðü¥Æø®Íû·Ôþ­ÌûŸÂö‡°í˜½ó”ºòªÊú°Ïü�´ï‹³î“¹ñ›¿ôˆ±í¦Çøˆ°í´ÑýžÁõ¢Ä÷¤Å÷–»ò´Òý¸ÕÿŽµï�Àõ¶Óþ‘·ð…¯ì¡Ãö¯Îûz˜Ä…®ì!ù,6wÿ@—pH,�È¤ÒÄl:ŸÐ¨t*u®Ø¬vËíz»®ˆxL.›Ïè4Ú•j»ßð¸|NŸ»ø¼~Ïïûÿ~.%ƒ„…†‡ˆ‰Š‰. Ž��‘’“”•”.
™š›œ�žŸ Ÿ.¤¥¦§¨©ª«ª.¯°±²³´µ¶µ.-º»¼½¾¿ÀÁÀ.ÅÆÇÈÉÊËÌË.ÐÑÒÓÔÕÖ×Ö.ÛÜÝÞßàáâá.æçèéêëìíì.	ñòóôõö÷ø÷.üýþÿ
(Ð…‡ƒ*\È°¡Ã†.HœH±¢Å‹3bt1¢£Ç� CŠIr¤(Sª\É²¥Ë—.]°˜I³¦Í›8sêÌéb‚ÏÿŸ@ƒ
J´(Q!’*]Ê´©Ó§PŸº@AµªÕ«X³jÝªÕ‡¯`ÃŠK¶¬Ù².¨]Ë¶­Û·pãÂuQ¡®Ý»xóêÝËw¯‹€L¸°áÃ†]�XÌ¸±ãÇ�#KŽìÂ‚åË˜3kÞÌ¹3gB‹Mº´éÓ¨O»0Àºµë×°cËž-Û…ŠÛ¸sëÞÍ»·ïÞ.
N¼¸ñãÈ“#wq¢¹óçÐ£KŸN}º‹Ø³kßÎ½»÷ïÞ]O¾¼ùóèÓ«OïBƒû÷ðãËŸO¿>}òëßÏ¿¿ÿÿþç‚hà�&¨à‚
ºÐÁƒF(á„Vha….| á†vèÿá‡ †¢”hâ‰(¦¨âŠ,®è0Æ(ãŒ4Öhã�6º°ÂŽ<öèã�@)d�.¼`ä‘H&©ä’L6Éd‘NF)å”JBIå•XV™å–[ZÉå—Qz	æ˜Z’if’bžIfšj‚Éf›\¾	g–rÎye�vN‰gžaòé¦Ÿ_î	è’‚Š¦¡t"Še¡Š¾À¨¢�"©¡“Z) —ú™)Ÿ›æÙ©�ŸÎ*œ£¶Yªš§ž™ª™«®Ù(•­ŽëŸ¯J9k µÚškŸ»6ykœ½úì“ÃZl™Çùk—É"¹l¢Íùì¢ÑJ[­£×N{g¶ÜV«-¬ÝFû­žá6;®®Þ*¡îºì;
__CPAN_FILE__ src/widget/templates/images/soriaDisabled-r.gif
GIF89a6wÕÉÉÉñññóóóòòòïïï×××ÖÖÖåååíííêêêáááÙÙÙÝÝÝÚÚÚÊÊÊðððãããëëëîîîßßßØØØäääÞÞÞÛÛÛéééæææçççâââôôôàààÜÜÜèèèìììËËËÌÌÌÕÕÕ!ù,6wÿ@€pH,�Èd’Ãl:ŸÐ¨t*	®Ø¬vËíz»¡¯xLæ†è´zÍn»ßî3|N¯³C�¼~Ïïûÿ€x�„…†}!Š‹Œ�Ž��‘�!•–—˜™š›œ›”� ¡¢™!¦§¨©ª«¬­¬!±²³´µ¶·¸·°¹¼½¾µ! ÂÃÄÅÆÇÈÉÈ!ÍÎÏÐÑÒÓÔÓ!	ØÙÚÛÜÝÞßÞ×àãäåÜ!éêëìíîïðï!ôõö÷øùúûú!ÿ
H° Á‚!2(\È°¡Ã‡#Bq ¢Å‹3jÜÈq#ÅŽ CŠÌ¢‚É“(Sª\É²%ËbÊœI³¦Í›8o†ØÀ³§ÏÿŸ@ƒ
*Ô�‚£H“*]Ê´©Ó¦FŸJ�Ju©ƒX³jÝÊµ«×¯^LK¶¬Ù³hÓªMëÀ‚Û·pãÊ�K·.]òêÝË·¯ß¿€ÿâ
L¸°á¾<(^Ì¸±ãÇ�#Cvp¡²åË˜3kÞÌy³ƒ C‹Mº´éÓ¦?£^Íº5ibËžM»¶íÛ¸oÃÎÍ»·ïÚ(N¼¸ñãÈ“#wP ¹óçÐ£KŸN}:óêØ³k�îÀ€÷ïàÃ‹O¾<ùîæÓ«_/ÞÁˆ÷ðãËŸO¿¾ýúîïëßÏ~þþèŸ€ø_�êw`‚Øàƒò-aƒN˜`…ˆa†nÈœ!€~È_ˆ"*Xâ…'"HbŠô­Èb„/vc€.Î8B�3â£Ž/òÈ¢�)y¢�%)¢‘"É¡’2i¡“B	¡”RI¡�ýYÉ –(b¹—*zù¥˜&’i˜šy¦šø±Ù¢›Â	šÊ�2Úùž4ê¹§Ÿ7Ê'ˆ‚êç Yª'¢#*j'£cê¨œ(aé¥˜";
__CPAN_FILE__ src/widget/templates/images/tab_left_r_curr.gif
GIF89a	–Õ#èïùúûþöùýâë÷íòúòõûýþþåíøßéöÚåõÝçöØãô¤¿åÖâô¨ÂæªÃç¢½åûüþÀÓîçîøãë÷“²à–µá¹ÍëÐÞòf“Óx ØŽ¯ßÜæö€¥ÚÇ×ïh”Ôd‘Ób�Òÿÿÿÿÿÿ!ù#,	–ÊÀ�hH
‹Ä#R¤D6‹ÏäÒ8eV£Ô)Öª½z»àåvü—�ghZF·Õo¶9ž�ÛÝwx^Žïëý|‚�„u€†ƒˆ…\{ŠŽŒ‡�‰’‹dt”�–�˜œš‘ž“ •k™¤�¦¢¥—©§«¨¯®±›¬´°³¶Ÿ¸¡ºI¾¿¾!ÃÄÃ!ÈÉÈ!ÍÎÍ!ÒÓÒ!×Ø×ÝÞãäéê 
ðñ#	ö÷#þ#^øABƒNpÐ!Dˆ ;
__CPAN_FILE__ src/widget/templates/images/treenode_expand_minus.gif
GIF89aæI�œÅ999üüüóôö��Åîðóéìðõö÷ïñôþþýúúúâæìÿÿþßäëÔÛåñòôûûûýþÿÒÙäùùùDDD�œÄ€œÅøùùÝâêÞãêòóõ÷øøÜáéÿÿÿþþþËÔàùùúêíñÚßèôõ÷äèí¿ÉÙÕÛå¾ÉÙëíñôõöÓÚäÌÔáÅÏÝðòôÍÕáìîòÖÜæíôþñóõþýýÊÓàüüûçêïºÆ×ùúúåèîãçííïòÛàèÄÍÜ}šÄåéîþþÿö÷øëîñ÷÷øæêïèëïÄÎÜìïòy–Á!ùI,€€I‚ƒ„…†‡ˆ‚H‹Œ�H‡H7%,.0
?(�'F+&9!)�=$¦†H4*:­C
±…H<Á
�"E;A8Ç²6G2 	¼„HD/5	�B-#3@1>�ŽŽ‰øùúûüýù�;
__CPAN_FILE__ src/widget/templates/images/no.svg
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
	<!ENTITY ns_svg "http://www.w3.org/2000/svg">
	<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
]>
<svg  version="1.1" id="Layer_1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="15.433" height="15.433"
	 viewBox="0 0 15.433 15.433" overflow="visible" enable-background="new 0 0 15.433 15.433" xml:space="preserve">
<circle fill="none" stroke="#D02026" stroke-width="2" cx="7.716" cy="7.716" r="6.716"/>
<line fill="none" stroke="#D02026" stroke-width="2" x1="3.02" y1="12.352" x2="12.639" y2="2.732"/>
</svg>

__CPAN_FILE__ src/widget/templates/images/tab_top_right.gif
GIF89a�,Õ7b�Òåíøöùýèïùòõûýþþúûþíòúâë÷•¿ÿŸÆÿßéöÝçö­ÎÿØãô¸ÔÿÀÚÿÚåõÖâôÈÞÿÔáóÎâÿd‘Ó¨Âæh”Ô|¢Ù¹ÍëŽ¯ß�¦Ûûüþ£¾åçîø’²àãë÷k—ÕÓàóŽ´ìž½ëÊÚð¦ÀæŒ°å‹°æ½ÑìÆÖïÚæõ¸Òö•½ø“½ýÍáþ•´áºÓù¡½ä·Óþÿÿÿ”¾ÿÿÿÿ!ù7,�,ÿ@€pH,�È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vë´p.Ÿ›øV)›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûã0-%c‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ –2(7¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ¹)7ÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàØ4!
æçèéêëìíîïðñòóôõö÷øùúûüýþÿøHxP@° Áƒ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±£EˆI²¤É“(Sª\É²¥Ë—0cÊœI³¦Í›8sêÜIóÿ@ƒ
J´¨Ñ£H“*]Ê´©Ó§P£J�JµªÕ«X³N µ«×¯`ÃŠK¶¬Y²\Ïª]Ë¶­Û·pã&M+·®Ý»xóêUKw¯ß¿€¾Ûw°áÃˆ+fZx±ãÇ�#×m,¹²åË˜«RÎÌ¹³gÎ›?‹MzpèÒ¨S«v{zµë×°³¶ŽM»¶m¤³oëÞ;7ïßÀGûN¼xåáÆ“+?Œ|¹óçy›CŸN½­ôêØ³‡½®½»wÍßÃ‹ß>¾¼y«ÜÏ«Ÿ~½ûîíßË§¾ýåõïë'ž¿ÿÝýý' mhàj¨ i	.è`g
>(¡eNhác^¨!bnèÿa`~(¢^!Žhâd'¦èY‰*¶È—‹0JÆbŒ4~5c�8bucŽ<nÕã�~íä�J	Iä‘E‰ä’@)É$’N>Id”RIe•=^‰eŽZnYc—^Æf˜.ŽI¦ŠfžybšjŽÈf›¾	ç†rÎya�vNˆgžîÉç‚~þy` ‚Hh¡ÿŠè~Š.z_£ŽÎi¤ïMJéz–^z^¦š–Çi§â}
êw¢Ž
Ÿ©m–Š*vª®JŸ«d¶
ës²ÎŠŸ­[ÖŠ«qºîÊŸ¯Rö
ìoÂ ±K‹¬mÊ.K ³SB;d³ÒºFmµª]‹-jÚnË ·\‚‹c·â®X.�äž›ÿYºê^Æn»ÇÁÛâ»òBFo½ŽÝ‹¯búîË¡¿n,b¿FpÁ€Œp�k¨pÃÑAláÃÛEqÅr]Œ1\oÌšÇ€‚¬`Ç"¿X²¡'£œr¢+³Ü2£/Ãó£3Ó\³¤7ãœs¥;óÜ3¦?cÊÅÐDmôÑH'­ôÒL7íôÓPG-õÔTW
µ`Œq\wíõ×`‡-öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×�ö*Ì@Èôí÷ß€.øà„nøáˆ'®øâŒ7îøã�G.ùä”Wn9ã+€PÊ
tîùç ‡.úè¤—núé¨§®úê¬·îúë°Ç.ûì´×nÿ»ë1\pC¼÷îûïÀ/üðÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWß¼ÀÀöÜwïý÷à‡/þøä—oþùè§¯þúì·ïþûðÇ/ÿüô·Âä¯ÿþü÷ïÿÿ HÀð€L ÈÀ:ð�Œ h‚ à‚Ì 7ÈÁzðƒ ¡GHÂšð„(L¡
WÈÂºð…0L!D€Úð†8Ì¡wÈÃúð‡@¢‡HÄ"ñˆHL¢—ÈÄ&:‰€§HÅ*ZñŠXÌ¢·ÈÅ.zñ‹`£ÇHÆ2šñŒhL£×XFà�pŒ£çHÇ:ÚÿñŽxÌ£÷ÈÇ>úñ�€¤ IÈBò�ˆ$ÀÈF:ò‘�Œ¤$'IÉJZò’˜Ì¤&7ÉÉNzò“ ¥(GIÊR~H¥*WÉÊVºò•°Œ¥,gIËZÚò–¸Ì¥.wÉË^úò—À¦0y	ó˜ÈL¦2—ÉÌf:ó™ÐŒ¦4§IÍjZóšØÌ¦6·ÉÍnzó›Ù@ÆIÎršóœèL§:×ÉÎvºó�ðŒ§<çIÏzÚóžøÌ§>÷ÉO{ 
¨@JÐ‚ô M¨BÊÐ†:ô¡�¨D'JÑŠZô¢ÍèDÿ©ÑŽzô£ 
©HGJÒ’št¤=©JWÊÒ–ºô¥ÿ0�)BS*ÓšÚô¦8Í©NOJÓ�úô§@
ªPmÚÓ¡õ¨HMªRZÔ¥:õ©P�ªL›*ÕªZõªX¥(U³ÊÕ®z5«[ýªXÇJV¡†µ¬hM«Z[zÖµºõ­pÅh[ãJ×ºÚõ s½«^÷
×¼òõ¯€«_KØÂJu°†M¬b�ŠØÅ:ö±8m,d'KY–J¶²˜Í,H/«ÙÎzV«Ÿ
­hCÊÙÑšö´--jWZÕ²öµ™u-lgYÙÒö¶‰µ-nwXÝòö·wõ-p‡ÛWâ³Â=®rÇšÜå:—«Í}®t«ÝéZ×©Õ½®v�šÝíz¨Ýý®xsÞñšwªçMÿ¯WË«ÞöòÔ½ð=l|ç‹]úÚ©ì½¯~A»ßþî4¿þ
0SL`ôøÀlE°‚U
à¸Á&0„#à	S¸¿¾°~3¬aûr¸Ãóý0ˆá+â··Ä&N/ŠSlÞ³X¼.~±wc,cíÒ¸ÆÖ½1Ž¥«ã;·Ç>V.�ƒlÜ!y¸F>òo“¬äÝ2¹É·}2”g+å)¿¶ÊV^-–³|Ú-sy´^þrkÅ<â0“¹³f>slÕ¬á4³™²n~småá8Óy±v¾snõ¬à<ó™°~þso]à@z¯†>tp]aFû7ÑŽŽ+¤#ýÖISz­–¾tZ3­é²rºÓÌuˆoEßO“º«¦>5XU}bV«7Õ®¦n¬ÏëYCµÖ¶®o®¿‹ë]'µ×¾æn°·ìa›ÕØ×-6²ªìeÿ×Ù<†ös›-í›R»Ú5½6¶cªím¿´ÛÞNp¸‘<nr—{ÉçFwº�¼nv·;ÊïŽr;
__CPAN_FILE__ src/widget/templates/images/dpYearBg.png
‰PNG


IHDRÈ¢eÌŸtEXtSoftwareAdobe ImageReadyqÉe<0IDATHKc,�¸›GY£¬QÖ(k”5Êy¬kÂ.’Y;a¬~«˜kmXië_6Oh„IEND®B`‚
__CPAN_FILE__ src/widget/templates/images/soriaDisabled-c.gif
GIF89a6wÕáááåååòòò×××óóóêêêñññíííïïïÚÚÚÝÝÝÉÉÉÙÙÙÖÖÖðððîîîéééãããèèèäääçççëëëØØØÛÛÛÞÞÞßßßìììàààÜÜÜâââôôôæææÕÕÕ!ù,6wÿÀ…pH,�ÈdÒÃl:ŸÐ¨t:%X¯Ø¬vËíz¿à°ø*(›Ïè´zÍn»ßð¸Ù@¯Ûïø¼~Ïïûÿ€uƒ„…†‡ˆ‰ŠŠ�Ž��‘’“”•–—˜™Žœ�žŸ ¡¢££¦§¨©ª«¬­®¯°±²§µ¶·¸¹º»¼¼¿ÀÁÂÃÄÅÆÆÉÊËÌÍÎÏÐÑÒÓÔÕÊØÙÚÛÜÝÞßßâãäåæçèééìíîïðñòóóö÷øùúûüýý
H° Áƒ*\È0à„‡#JœH±¢E‹2jÜÈ±£Ç� AvI²¤É“(SªT	 ¥Ë—0cÊœI³¦Í›8sºÜÀ³§ÏÿŸ@ƒ
:4ƒÑ£H“*]Ê´iSP£J�JµªÕ«WhÝÊµ«×¯`ÃŠK¶¬Ù­Òª]Ë¶­Û·pá^˜K·®Ý»xóêÕ› ¯ß¿€L¸°áÃˆûeÀ¸±ãÇ�#KžL¹²åË˜[ØÌ¹³çÏ C‹= ´éÓ¨S«^Íºµë×°c›n@»¶íÛ¸sëÞÍ»·ïßÀkƒN¼¸ñãÈ“+_Î¼¹óçÐ£KŸN½ºõëØ³kßÎ½»÷ïàÃ‹O¾¼ùóèÓ«_Ï¾½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà�&¨à‚6èàƒF(á„Vhá…f¸�vè!A;
__CPAN_FILE__ src/widget/templates/images/dropdownButtonsArrow.gif
GIF89a€/?Zÿÿÿ!ù,„[;
__CPAN_FILE__ src/widget/templates/images/dpMonthBg.png
‰PNG


IHDRÈ@¹×ætEXtSoftwareAdobe ImageReadyqÉe<KIDATHÇíÔ+ ÐBvÿpn…+ŠdG:÷Òì£ÖÆ\8Õ‘*HŠ`sdOšT‰¾ .%q›”Ñ†aAÿQÃ0ŒlÿÅé¨A“žIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/tab_close.gif
GIF89aÕá^^çccÚXXýóóÔTTÃEEê……åbbäaaÞ\\â__üóóûííúììÌVVüððà}}ÎXXáýôôÞ[[ÔSSÜddñkkàhhãkkÐPPÍNNÏOOÝ{{Ü{{ÎNNÑQQß\\ÇHHÈJJëppîiiËKKêeeíhhìggÅGGÙXXýððÆHHìrrèddïjjÄFF×__çƒƒëggè‚‚ÌMMÀÿÿÿ!ù,U@œpHÞŽÈ¤ðv�¡N t[–R®h&!¨ân4ËP{XÞÛë`L$Nú ˜
��)
À0 
"i2 -1i+6#*iI˜EšBA;
__CPAN_FILE__ src/widget/templates/images/slider-bg-vert.gif
GIF89a‡Qb|„–±|Ž«wŠ©Oa|’®„–²xŠ¦’¢ºt‡¤xŒª^t–wˆ¢Vj‰l€žby˜N`{XmŒr… dx—|�­m~—n‚ g}žm‚¢ew’L]xVg€^t“k|–Yj‚z�ªŠ›µd{œr†¥zŒ§h}œf|��”¯av”yŠ¤r‡¦I[uq„¢j~�x‰£j|•l€¡x‹©vˆ¥l€œdzš[p‘l}–j~›pƒŸi~ by›|�¦ˆ™³gz˜{Œ¥Sd~i|šZj‚‰š´n~—}Ž¦zŽ¬br‰z‹¤u†¡f{šzŽ«kžw‰¥j dv‘r‚›|�¬� ¹|Ž©]p�Te~Ui‡bw•r…¢M_zwŒ©uˆ¤‹œ¶l�¡e|œh|™v‡¢c{�Žž·\m†~�¨t†£Zp�as�fx“bu�Wh€bt�hz”Wh�Rc}Uf`r�gy“€’¬h~Ÿi{•`s�cz›‚”°ƒ•°_u–‘«€“¯Pa|\r’‘­Xi‚`w—i ]s“nƒ£Vfo‚žuŠ¨{�¨ƒ•±o„¤cw–h{™Wi�iz”oƒ£s†£q…¤tˆ§�“°‡˜³n��n‚¢k€¡…—²y‹§Xi�bt�j{•s…¡v‡¡cu��“¯~�¬k�¡^s“q†¥ax˜uˆ§n—yŒ©dz™aw—cv‘pƒ¡q„Ÿbs�lœcu‘`u”�“¬h~ž~�«g|›p„¤p…¤t‰§j€¡k€ cy™q…¥g~žt‰¨i~�iz•}�ª�“­`v–~�ª€’®†˜²‡˜²~�­~‘®„•±o€™fy“‚”±‚•°~‘«wŠ¦ey—�’¬o„£€“®]r“‡™´t‡¦†˜³‡™³GXq‚“­m�Ÿn� fy˜s‡¦?Oedw–Sc~EUm@Of_u“arŒ€‘«Œ›´u…�v‰§i}šy�«ax—ƒ”±RfƒSg…}‘­�ž¸[q’u‰§[k„gy”hŸr…¥k€žnƒ¢\r“\s“�­p…¥fw“uˆ¦`p‰!ùÿ,ÿÿñf�Àåv #@
0 Â˜CðNK¤qN h™VÇŸ0A�ƒl£	1òHi©†MR ªýòD¥™5oÒ„YéÕN›>såTHÈg:€
€H…�ptxx êT¨R©ZÕšëÕª]Á~Ýê•ëÔvðô8›vm´jÙÆ}ÛV®[¸wëÒ�km3·}ÿN�T'–‘Á…W lqã
ÄêSyòÔÊŠ‡™°\A3gÏ‡kTêäEÑ¤M£.}z4ëÕª+åy-›v´Ò—DßF‘Û€°(-zÿ^Ã7ðÞ€+*ž¼ÅrÍŸGg®œºóÇøb°»vî}ÿï.~;ùñáÑ—¿¾û:}#¼tWV,þüúò;Ôñ4býüù`ÿíGà€þ¹É–�†‚:aƒ.Há„Z(a>È!…™ä!Àšlâˆ%žH¢‰"®¨b‰rˆØŒ2ÂXÀKØˆ£Ž9n Ç�=þˆ£>I¤�Kiä½SJªÒä“QöâN)YD¹È•Y
²%–Zr&˜^RC7”yfšj˜‰fm®	§›7Ì)gœoªñÄcçž�ø©ç�þI¨ €"z¨¡…ÎCÄ9VH2ÅI@*)¥–NZi¤šfŠ)§”Æj:£¬àÀ¤¤šŠj©§¾‘j«éôÿ³‚S$“Î#³Özk®f(@M*¬øÐë¯Á¬°¾kÜ(Ë¬³ÜÜP,³Ò
ƒØ`-¶Úš1·Â~›m¸àz[®¸Úò3@=Ú óM„8’
:lÀ+/½öÎ[o¼úæ‹/¿øî2‹?Ô+0Á\pµ(\oÃ3ì0ÃÐØÓE½�0¢D"kÌqoÜ±È {<òÇ�Ü#rÜLÂ°ì2Ì2¿sË6×Ls
ð²sÏ?û³[�°ÍÐEÝÑF€J(E;ã4Ô$HýtÔScÝJ./È2�[wýuØ^ƒ½%esBË-i¯Ý6Û_«
·œÌÂÞèqÆ!w#ÿBÀÞ}ÿÍ7~N¸à�^84‰òUüí8ä’?ù“_žyå”cn¹äôÌyÄ1Ã	�n:ê¤Ãb
ë¸»ì©ÇþzíºÜNzî°óžúàâÊïÁŸðÂŸ<&È�É'< ÏG?}õÒS}ö«PR‚(@Ðý÷á�¾øÞŸ_†-\¨Ï¾ûí‡¿~üÌ¯ŽüL„p
(õç¿ÿúã_ü'À?„À€¨Ÿ¨À&°|`È@:°~8 0¤�A
rpqÐ > B
î�„!Æ	K¨BšÐ…-dá
S8ÃÊn¸@î�+äp‡=ü!H}¨Ã!
1ˆED"‰¸Ä#2ÑˆIdâÈ )|Áù br0Å¨ w A¨ vÀ#
hÇ5¾Ø* ÿ‡TÐ�;
__CPAN_FILE__ src/widget/templates/images/slider-button-vert.png
‰PNG


IHDRLef„,tEXtCreation TimeFri 23 Jun 2006 09:31:26 -0500¿ÄbtIMEÖ
 1†¿xß	pHYsÁÁÃiTSgAMA±�üaEPLTEÿÿÿ{œÆ{”Æ„œÆ¥ÆÿsœÖ{œÎÎÞÿ”µçœ½ïŒ­Þ{œÖ„¥Ö„¥ÞŒµçŒ­çŒ­Ö”½ï”µïŒ¥ÖœÆ÷Îçÿ„¥Îeì†gtRNS@æØf©IDATxÚe‘ÙÂ K Iéiñÿ?Õ€ÒbÞfÃ‘0O¯uøÃÇDºE^3‚þnŠ9T îÒ$M‡rÚ³ùõ[
À½öºŸ[=±\O�M¶@í,Ú »ì=(·“Ê,s°Z½›!‹,'¦S}ÒdõÓ‰BéóNV™ZÉ]ýÊ£’‘ý9.Á˜Ì*S?Oµn42ù~žö+ad¦›­Ã “o¬¼Gãÿ®&IEND®B`‚
__CPAN_FILE__ src/widget/templates/images/soriaButton-r.gif
GIF89a6wÕz˜Ä{™Æ¡Ãö†¯ì¶Óþ…¯ì‹³î®Íû‰±í�¶ð’¸ñš¾ô¦Çø¨Èùˆ±í–»òˆ°í³Ðý”ºò±Ðü­Ìû—¼ó¯ÎûŸÂöŽµïµÓþ¤Å÷·Ôþ¢Ä÷�´ï¸Õÿ‡°í´ÒýŠ²î›¿ô¥Æø�Àõ´Ñý‘·ð¬Ëú©ÉùªÊúžÁõŒ´ï“¹ñ˜½ó°Ïü¸Ôÿ}›Ç|šÇ{šÇ|›Ç~œÇ{šÆ~›Ç…®ì!ù,6wÿ@€pH,�ÈdÒÃl:ŸÐ¨t*¥½®Ø¬vËíz»´�xL.›Ïè4šFh»ßð¸|NŸÛ2ø¼~Ïïûÿ~0 ƒ„…†‡ˆ‰Š‰0%Ž��‘’“”•”0™š›œ�žŸ Ÿ0¤¥¦§¨©ª«ª0.¯°±²³´µ¶µ0º»¼½¾¿ÀÁÀ0ÅÆÇÈÉÊËÌË0ÐÑÒÓÔÕÖ×Ö0'ÛÜÝÞßàáâá0)æçèéêëìíì0(ñòóôõö÷ø÷0
üýþÿ
(ƒƒ*\È°¡Ã†0FHœH±¢Å‹3b„¡¡£Ç� CŠIrä(Sª\É²¥Ë—.g˜I³¦Í›8sêÌ9ã‚ÏÿŸ@ƒ
J´(Ñ*’*]Ê´©Ó§PŸÆ AµªÕ«X³jÝª5†ˆ¯`ÃŠK¶¬Ù²1¨]Ë¶­Û·pãÂ�Ñ¢®Ý»xóêÝËwoŒ
€L¸°áÃ†c<XÌ¸±ãÇ�#KŽC‚åË˜3kÞÌ¹3ç,B‹Mº´éÓ¨OËPÀºµë×°cËž-[†‰Û¸sëÞÍ»·ïÞ2N¼¸ñãÈ“#—�¡¹óçÐ£KŸN}ºŒØ³kßÎ½»÷ïÞe¬O¾¼ùóèÓ«O/Ã€û÷ðãËŸO¿>ý!òëßÏ¿¿ÿÿþWhà�&¨à‚
àÀƒF(á„Vha…@ á†vèÿá‡ †b”hâ‰(¦¨âŠ,®À0Æ(ãŒ4Öhã�6PÀŽ<öèã�@)d�Ü`ä‘H&©ä’L6Éd‘NF)å”JBIå•XV™å–[ZÉå—Qz	æ˜Z’if’bžIfšj‚Éf›\¾	g–rÎye�vN‰gžaòé¦Ÿ_î	è’‚Š¦¡t"Še¡ŠÞÀ¨¢�"©¡“Z) —ú™)Ÿ›æÙ©�ŸÎ*œ£¶Yªš§ž™ª™«®Ù(•­ŽëŸ¯J9k µÚškŸ»6ykœ½úì“ÃZl™Çùk—É"¹l¢Íùì¢ÑJ[­£×N{g¶ÜV«-¬ÝFû­žá6;®®Þ*¡îºì";
__CPAN_FILE__ src/widget/templates/images/soriaAccordionSelected.gif
GIF89a³�¶ð¡Ãö­Ìú§Èø¶ÓþŠ²î²Ðü‡¯í›¾ô•ºò…®ì!ù,�1J Å»ÿ;
__CPAN_FILE__ src/widget/templates/images/slider.gif
GIF89a
‡111­­­½½½ÆÆÆÖÖÖÞÞÞïïï÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,
>H° Áƒ*`!€
>LñàDŠ	^Ä˜ÁFŽ?‚9cD�%O
ü¨’¡É„[”¹P`@;
__CPAN_FILE__ src/widget/templates/images/tab_bot_left_curr.gif
GIF89a	–Õ#èïùúûþöùýâë÷íòúòõûýþþåíøßéöÚåõÝçöØãô¤¿åÖâô¨ÂæªÃç¢½åûüþÀÓîçîøãë÷“²à–µá¹ÍëÐÞòf“Óx ØŽ¯ßÜæö€¥ÚÇ×ïh”Ôd‘Ób�Òÿÿÿÿÿÿ!ù#,	–ÊÀ�hH
‹Ä#R¤D6‹ÏäÒ8eV£Ô)Öª½z»àåvü—�ghZF·Õo¶9ž�ÛÝwx^Žïëý|‚�„u€†ƒˆ…\{ŠŽŒ‡�‰’‹dt”�–�˜œš‘ž“ •k™¤�¦¢¥—©§«¨¯®±›¬´°³¶Ÿ¸¡ºI¾¿¾!ÃÄÃ!ÈÉÈ!ÍÎÍ!ÒÓÒ!×Ø×ÝÞãäéê 
ðñ#	ö÷#þ#^øABƒNpÐ!Dˆ ;
__CPAN_FILE__ src/widget/templates/images/soriaPressed-l.gif
GIF89a6wæ†¯ì‹µó‹µô‹²í˜Âÿ˜ÁþŒ¶ô—»ò Âõ”½ú°Îû¡Ãö²Ðüˆ³ñ�¶ïˆ°ìµÒþ¶Óþ�¶ï´Òý�´î�¹÷¸Ôÿ«ÊùªÉùŒ³î–ºñ¨Èø§Çø˜¼ò³Ñý†°îŠ´ò‘»ø‡¯ìžÁô¯Íû±Ïü’¼ù®ÌúŒµô“¸ðˆ°í”¹ñš½ó£Äö¥Æ÷›¿ó�Àô�·õ‰±í•¾ûŽµî—Àý’·ð–¿üŠ²í‡²ð·ÔþŽ¸ö¤Å÷¬ÌúŠ´ó…¯íˆ²ñ‰³òz˜Ä‡±ð†°ï…¯î…®í…®ì!ù,6wÿ€B‚ƒ„…†‡ˆ‰ŠŒ�Ž��‘’“’B—˜™š›œ�ž�B5¢£¤¥¦§¨©¨B7­®¯°±²³´³B3¸¹º»¼½¾¿¾B	ÃÄÅÆÇÈÉÊÉB&ÎÏÐÑÒÓÔÕÔB!ÙÚÛÜÝÞßàßBäåæçèéêëêB;ïðñòóôõöõB1úûüýþÿb  Áƒ*\Èp¡#JœH±¢Å‹…ØÈ±£Ç� CŠ©q¤É“(?
	À²¥Ë—0cÊœ)s%Í›8sÂâ£§ÏŸ@ƒ
Jt(Ï¢H“*
zt©Ó§LAH�JµªÕ«X³b¤«×¯`ÃŠKv,×²hÓª
{v­Û·lÿáÊ•+¤�Ý»xóêÝË·/_!@L¸°áÃˆNÌ¸±ãÂ‹Kž™²eËBrhÞÌ¹³çÏ Cƒ2¤´éÓ¨S«^Íz5éÖ°cËNýz¶íÛ´qëÖ]{·oØBˆN¼¸ñãÈ“#®¼¹óçÆ™CŸN=zõë×¥cßÞ\;÷ïÑ?ˆO¾¼ùóèÓ£R¤½û÷ðãËŸO>ûúøóë�¿ÿÿü( €ý
h ~¨ ?4èàƒF(á„N(D…f¨¡„nèá‡!âˆ$–hâ‰(¦ˆ¢*¶èâ‹'²ãŒ4ÆXã�7ÊˆãŽ.êÈã�6)d‰Baä‘H&©äÿ’L6Éd‘NF)å”JBIå•XV™å–[ZÉå—Qz	æ˜Z’if’bžIfšj‚Éf›\¾	g–rÎye�vN‰gžaàçŸ€*è „J¨†&ªè¢ƒ
!Â£�F*é¤”Vji¥B< é¦œvêé§ †
ª*”jê©¨¦ªêª¬®*„°Æ*ë¬´Öjë­¶
�Ã®¼öêë¯À+l°B`ì±È&«ì²Ì6Ë¬D+í´ÔVkíµØ^+Üvëí·à†+î¸â
AÃ¹è¦«îºì¶ën»BH ï¼ôÖkï½øæ‹¯ôëï¿,ðÀ,„
'¬ðÂ7ìðÃ‘ÂÄWlñÿÅg¬qÆB¬àñÇ ‡,òÈ$—L²¤¬òÊ,·ìòË0¿,Ä4×lóÍ8ç¬óÎ:ÑÁÏ@-ôÐDmtÑB° ôÒL7íôÓPG
µ/TmõÕXg­õÖ\o-`‡-öØd—möÙf1ÂÚl·íöÛpÇ-wÜB `÷Ýxç­÷Þ|÷Í·.øà„nøáˆ.DŒ7îøã�G.ùä’ÁÃå˜g®ùæœwîyçB¸ úè¤—núé¨§Žº´îúë°Ç.ûì´Ï.Ä¸ç®ûî¼÷îûï¾�ÁðÄoüñÈ'¯|òB\àüóÐG/ýôÔWO½=d¯ýöÜwïý÷à/Äª	ä—oþùè§¯þúêAÂûðÇ/ÿüô×oýB( ÿþü÷ïÿÿ …P‚ð€L ÈÀ
�Œ 'HÁ
Zð‚‚6ÈÁzðƒ ¡C(„	˜ð„(L¡
WÈÂ²Pˆ¡gHÃÚð†8¼¡"ÀÃúð‡@¢‡(D!èàˆHL¢—ÈÄ&:±‰B°€§HÅ*ZñŠXÌ"ÁÅ.z�;
__CPAN_FILE__ src/widget/templates/images/slider-button.png
‰PNG


IHDREŽÆþ,tEXtCreation TimeSat 24 Jun 2006 18:44:01 -0500öÀÄdtIMEÖ,.ïfá	pHYsÁÁÃiTSgAMA±�üaEPLTEÿÿÿ{”ÆsœÖ{œÆ{œÎ{œÖ„¥Þ„¥ÖŒ­ç„œÆ„¥ÎŒµçŒ­Þ”µï”½ïœ½ïÎÞÿ”µçœÆ÷Œ­Ö¥ÆÿÎçÿŒ¥ÖÝÍåtRNS@æØfvIDATxÚ]Ðáƒ àëŠ:�
°Ì÷TD�~ýÅ%%Í�"â,:—rux¾#Ÿál‘ä_Ÿ@uñˆã¤ÿ§)Î¡ƒ‹-hÿÕ,üG+»»fàÞƒu´–·ufÊÍ<GK­Á,#j%ð«£»,zZ¥¦=.–B›‹ìÌ%IEND®B`‚
__CPAN_FILE__ src/widget/templates/images/soriaDisabled-l.gif
GIF89a6wÕ×××áááòòòÖÖÖñññóóóêêêíííåååÙÙÙÝÝÝÚÚÚïïïîîîðððëëëæææßßßâââàààôôôÜÜÜèèèãããÞÞÞéééäääØØØçççìììÛÛÛÉÉÉÕÕÕ!ù,6wÿÀ�pH,�È¤’Âl:ŸÐ¨t*ý®Ø¬vËíz»Ö¯xLÞ~è´zÍn»ßî3|N¯³?„¼~Ïïûÿ€x�„…†}Š‹Œ�Ž��‘�•–—˜™š›œ›”� ¡¢™
¦§¨©ª«¬­¬±²³´µ¶·¸·°¹¼½¾µÂÃÄÅÆÇÈÉÈÍÎÏÐÑÒÓÔÓØÙÚÛÜÝÞßÞ×àãäåÜéêëìíîïðïôõö÷øùúûúÿ
H° Á‚ (\È°¡Ã‡#Bü€ ¢Å‹3jÜÈq#ÅŽ CŠÌøAƒÉ“(Sª\É²%ËbÊœI³¦Í›8o~�À³§ÏÿŸ@ƒ
*ôC€£H“*]Ê´©Ó¦FŸJ�Jué‡	X³jÝÊµ«×¯^?DK¶¬Ù³hÓªMûƒÛ·pãÊ�K·.Ý
òêÝË·¯ß¿€ÿâ
L¸°á¾*(^Ì¸±ãÇ�#Cþà¡²åË˜3kÞÌyó‡ C‹Mº´éÓ¦?£^Íº5é	bËžM»¶íÛ¸oÃÎÍ»·ïÚ6N¼¸ñãÈ“#ÿ ¹óçÐ£KŸN}:óêØ³k�þa€÷ïàÃ‹O¾<ùîæÓ«_/þˆ÷ðãËŸO¿¾ýúîïëßÏ~þþèŸ€ø_�êw`‚Øàƒò-aƒN˜`…ˆa†nÈ›!€~È_ˆ"*Xâ…'"HbŠô­Èb„/vc€.ÎB�3â£Ž/òÈ¢�)y¢�%)¢‘"É¡’2i¡“B	¡”RI¡�ýYÉ –(b¹—*zù¥˜&’i˜šy¦šø±Ù¢›Â	šÊ�2Úùž4ê¹§Ÿ7Ê'ˆ‚êç Yª'¢#*j'£cê¨œJTjé¥H;
__CPAN_FILE__ src/widget/templates/images/dateIcon.gif
GIF89aÕ"Aqôôôðóöçìñòô÷âèîïòõáçíÞÞÞûûû÷ùúúûüóöøùúûìðôèìñõ÷ùô÷ù&J€ÁÉ×“®üüýÀÄËÐÙãòõ÷ÍÕà9aŸêêêJd‹p„£@[„:e� ¸ÈÈÈ9c+Iw2N{èíñ0S1TÛâéÚáéíñôèèè!ApOsªÚÚÚ2WÒÛäÓÓÓððð.Yšÿÿÿ!ù,¥À™pH,
	£’ˆ,Ÿ1ÙsmÑ®ØlvÅª`)Z6 Á`
˜ë‹Éf´:Å–Yµøk½µP	h*4**
~{_acegik]v(4(4((
•{y4$¦{”–˜š( ¦#Šn�ft’|~€‚„*%u.ÊËÌÊ!Q"/ÕÖ×Ö'&Q1ßàáâM	2çèéêHA;
__CPAN_FILE__ src/widget/templates/images/decrementMonth.png
‰PNG


IHDR5Y^tEXtSoftwareAdobe ImageReadyqÉe<dIDATÓcÐ´òf@Â6Óç/Oþÿÿ¿1LŒMÁ1 >ƒKAÿá¦žiÕ0E0I ~Sbß¹ÿÐYA;’$çU¶Î™’TâŸè
@b¶íõ)0»tíæ!løéó—ëª']_1'°&IEND®B`‚
__CPAN_FILE__ src/widget/templates/images/floatingPaneMaximize.gif
GIF89aæÂÓì®ÍûªÉù¥Åõ§Ç÷œ¾ð¬ËúŸÀò¢Ãô™¼ïp‹³r�µ¢Åù�°å¬ÊøqŒ´yžÖ–ºî§Æõ‘´ê™¼ñÁÓë¦Éü}¢Ù Ã÷œ¾ïž¿ð‚¦Ý¨Êý¯ÎúžÁõ±Ïû³Ðümˆ°–¸ëŽ²ç¤Äô†ªá›¿óÃÕí‹¯ån‰±oŠ²®Ìùl‡¯“·ì¤Çú¡ÁòÄÕíÁÓìv›Ó™»í´Ñý©Èö„©àr�´qŒ³q�´o‹²lˆ°ÄÕîÃÔí‰®ä–¹í²Ðý°Ïü³Ñþ“¶ë€¦ßlˆ²©Ëþr˜ÐÆÖík…«):Kÿÿÿ!ù,ÿ€I‚ƒ„…†‚F‰Š‹ŒŒI<H“”•–H<�<4BŸ ¡¡4<�.< @«¬­­ <.7I<A¸¹ºº<9I<JÇÈÉÅ<I0+ÉÖJÔ+0Ï&'×Éá'&8I=5JKñòñJî5=
I=ðæÉSòOB�úZô �A@�K”4$Ñ£…¾	=^8ðP ’�/zLÐ‘dD

tœ§$¥†#T$AÑ#C‚ã�ÝÌÐ…ÌfüJ´hÑJ¤H²€ˆ!P£J•*À†¥4ðÁµ«W¯
\‘BDÒª]»ÖFdeT¸D—R;’ÙË·¯_¿,’L¸°aÃ,;
__CPAN_FILE__ src/widget/templates/images/scBackground.gif
GIF89a¶æt�ºw”¿z—Ãu‘»s�¹ƒ¢Ñ~œÉy–Á|šÇx•À†¦Ö„¤Ó� Îv’½sŽ¸€ŸÍ}›Ès�¸{™Å’µé—»ðy–Âu‘¼v“½� ÏžË…¥Õ…¥Ôx•Á|šÆ›À÷u’¼‰ªÛƒ£Òw“¾™½órŽ·�Ë–ºï‚¡Ðz˜Ä{˜Ä‡§×‚¡Ï€žÌ‚¢Ð”·ëš¿õœÁ÷ˆ©ÙžÌ˜¼ò‰©Ú}›Ç|™Æ�Ê�¯áŠ«Üx”À—»ñ•¹î–¹îŽ°ât�¹�±ãrŽ¸t‘»‡§Øš¾ôv“¾~œÊ~�Ê‹¬Þ‹­Þš¿ö�³æ“¶ê›¿ö’´è�±ä†§×€ŸÌv’¼†¦Õy—ÂŠ¬Ý…¤Ô{˜Å”·ìœÁøˆ¨ØŽ°ãw”¾}œÉ•¸í”¸ì“¶ë‘´ç˜½òŒ®àš¾õ�²åt�¹‘³ç„£Ó™¾ô›ÀöŒ­ß„£Ò�²å�®à˜¼ñ!ù,¶ÿ€YY00†jjMMJJ//ddDDii#—#bb33oo;;¢&¥&==<<^^__XX..``LL¸NNaaggKKmmeeOO@@[[>>88nncckkIIHHUU99 ß 4411ZZCC*ê*PP
ïðSSô÷VVüýhhlØ„¢€Áƒ-ZœXxb…Ã"b`@±âƒ‹£DaÁB†Œ 3”YâÆ�#GŒ1À²e—.bÊ¬Q�Í›rv°aC‚ÏŸW®¤š…Q’*MJ…J…§H�Ê¡*‡X³êÐ «×®\¸ˆ+¢H‘h/4XËVŠ”p(?X˜ka€Ý»v…À·¯_¾fÌüøA °áÂ+vÀ¸q� $"“;
__CPAN_FILE__ src/widget/templates/images/transparent.gif
GIF89a((÷ÀÀÀè×gÔˆ0ÿÿÿÔˆ*ç‘2¨!�æàé$ç0‘2H!º`çL‘2H!º`ç$‘ëéh�î‘8ÿÿÿ‘2‘«‘ëé¸éäéÜçdÝtuê¼�î�ûxÿÿÿ�ûqÝu!¨Ýu,!º`¨éÜ@ê$éä@ê(z
ì¨éÜ¨ÿÿÿè,Ý›‚çtHè(‚èŒÝ‚é@‡€–Hæ‚°é@‡Lèè@è�‘È!ˆé\‘Q¨‘mé´è¸‘È!ºXé„‘QHèÔ‘È!ºXé ‘QH‘méäæ„Dº«Í0!�Ôˆýð0ç�ûl !º`é@‘ÈGi ê‘Qá8‘mGn8Gi(�ûq�Õ†�ç¼é`�çÈê�î�ûxÿÿèäê�î‘pÿÿÿ‘m‘	¼È!º`éÄ‘	’!º`êÝíÝí b¦Èáb¦ÔéPGi(êD�î‘pÿÿÿ‘mÂÂÞáÂÂãGn8Gi(ÝhªGi(Gi(êPê ÿÿÿê¼Ã\”Á pÿÿÿÂÂãD•ÕGi(c c EµGGn8I¼�ê†Ôê†Ôê†Ôê†Ô¨ê Ýltê¨I¼�I¼�æà£æ‚°!ù,((CH° Áƒ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±£Ç� CŠI²¤É“(Sª\É²¥Ë—0cÊœI³¦Í›8	;
__CPAN_FILE__ src/widget/templates/images/incrementMonth.gif
GIF89aÄ¥Åô¤Ãó¡Àí—µà”·ëp�µrˆ¦�©Ð€™¼}�Ê²Æâ¤Âò^xš‰«Ü¥Äô—ºð‚¢Ð>Rj,=O5H]™½ó—»ñ¦¶Ï˜¼ò):K!ù,% d�¤ÒHXŠIÅ¨˜PÄ”Nu]EŠ8»Ë#Yì*ÈÄ!€;
__CPAN_FILE__ src/widget/templates/images/dpCurveTR.png
‰PNG


IHDRÈ‹JétEXtSoftwareAdobe ImageReadyqÉe<ÉIDATxÚíÍ¹m‚A…Q&r=nÑ‹é€^ØÚ`‰\€%
`·Mó÷À	8Ÿtƒ�4\_oµÇ7Êk}Õ?vÕIAHÕ6¯‘¡Ÿ4XýG!UßyŸÑHU3#ÑÈ&
–áÈ%õ—¿ÑH­²¸Ä#½"Èüü"Hwv*�ã‘Î´rˆGÚ“"È�@ �@ �@ �@ �@ o‹Œw�@ �@ �@ �@ �gAî`d‘òHÙIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/dpCurveBR.png
‰PNG


IHDRÈ‹JétEXtSoftwareAdobe ImageReadyqÉe<µIDATxÚíÐ¹
Â@@Q¶;¨„˜+£Ni„Ãe Ñ	‚ÄÀ&CHvóFúÉó¤I«ºy�2O‚@ �@ �@ �@ �@ �@ �@ �@ �@ ä²,‚ìÎ�ÿDN�mdé‡‡‚TÃ@ÚÈ%Í«Cndši¢I.¤�êh½™�ï}�gt‹¿þßµ�ã×Ïò
¤Œ575ì¶«IEND®B`‚
__CPAN_FILE__ src/widget/templates/images/treenode_grid_y.gif
GIF89a€rrr!ù,Œ�©Ëí£œt‚‹3X›v[}’‘�ù Žj;
__CPAN_FILE__ src/widget/templates/images/soriaPressed-r.gif
GIF89a6wæz˜Ä†¯ì‹µô‹µó�¶ï˜ÂÿŠ²í‹²í–¿ü�Àô¥Æ÷�·õ†°î¤Å÷±Ïü”½ú³Ñý‰±íˆ°íˆ°ìŠ´ò‡¯ì�¹÷·Ôþ²Ðü§ÇøžÁôˆ³ñŒ¶ô—Àý—»ò¬Ìú¨Èø”¹ñ®ÌúŽ¸ö˜¼ò’·ð’¼ù“¸ð‘»ø›¿óªÉù Âõ¯Íû°Îû£Äö‡²ðµÒþŽµî¡Ãö–ºñ¸ÔÿŒµô«ÊùŒ³î�¶ï¶Óþ•¾û´Òý˜Áþš½ó�´î{™Æ{šÇ|šÇ}›Ç{™Ç{šÆ|›Ç~œÇ~›ÇŠ´ó…¯í‰³òˆ²ñ‡±ð†°ï…¯î…®í…®ì!ù,6wÿ€‚ƒ„…†‡ˆ‰‰Œ�Ž��‘’“’A<—˜™š›œ�ž�A¢£¤¥¦§¨©¨A­®¯°±²³´³A:¸¹º»¼½¾¿¾AÃÄÅÆÇÈÉÊÉA&ÎÏÐÑÒÓÔÕÔ@(ÙÚÛÜÝÞßàß@äåæçèéêëê@#ïðñòóôõöõ@úûüýþÿÂ¡ Áƒ*\Èp!�#JœH±¢Å‹�ØÈ±£Ç� CŠ©q¤É“(?À²¥Ë—0cÊœ)s%Í›8sÂ‚¤§ÏŸ@ƒ
Jt(Ï¢H“*
zt©Ó§L)H�JµªÕ«X³b¢¤«×¯`ÃŠKv,×²hÓª
{v­Û·lÿáÊ•dƒÝ»xóêÝË·/_ KL¸°áÃˆNÌ¸±ãÂ‹Kž™²eË@^hÞÌ¹³çÏ CƒÂ¤´éÓ¨S«^Ízõ�Ö°cËVýz¶íÛ´qëÖ]{·ïØCšN¼¸ñãÈ“#®¼¹óçÆ™CŸN=zõë×¥cßÞ\;÷ïÑˆO¾¼ùóèÓ£ÿá¤½û÷ðãËŸO>ûúøóë�¿ÿÿü( €ý
h ~¨ I4èàƒF(á„NøC…f¨¡„nèá‡>!âˆ$–hâ‰(¦ˆâ*¶èâ‹'²ãŒ4ÆXã�7ÊˆãŽ.êÈã�6)d‰?@aä‘H&©äÿ’L6Éd‘NF)å”JBIå•XV™å–[ZÉå—Qz	æ˜Z’if’bžIfšj‚Éf›\¾	g–rÎye�vN‰gžaàçŸ€*è „Jè†&ªè¢ƒþPÁ£�F*é¤”Vji¥?L é¦œvêé§ †
ê”jê©¨¦ªêª¬®úC°Æ*ë¬´Öjë­¶þ`À®¼öêë¯À+l°D`ì±È&«ì²Ì6Ë,7D+í´ÔVkíµØ^K„Üvëí·à†+î¸âÃ¹è¦«îºì¶ën»Dà ï¼ôÖkï½øæ‹/ôëï¿,ðÀD	'¬ðÂ7ìðÃqÂÄWlñÿÅg¬qÆ@„àñÇ ‡,òÈ$—Lr3¤¬òÊ,·ìòË0¿„4×lóÍ8ç¬óÎ:AÂÏ@-ôÐDmtÑAô ôÒL7íôÓPG
u)TmõÕXg­õÖ\oD`‡-öØd—möÙf¡ÁÚl·íöÛpÇ-wÜA¬`÷Ýxç­÷Þ|÷Íw2.øà„nøáˆ^„Œ7îøã�G.ùä’ÑÀå˜g®ùæœwîyçE( úè¤—núé¨§Žº´îúë°Ç.ûì´Ï.¸ç®ûî¼÷îûï¾¡ÂðÄoüñÈ'¯|òBØàüóÐG/ýôÔWO½d¯ýöÜwïý÷à/„«ä—oþùè§¯þúêÁÂûðÇ/ÿüô×oýB´ ÿþü÷ïÿÿ …à€ð€L ÈÀ
Œ 'HÁ
Zð‚6ÈÁzðƒ ¡C(„˜ð„(L¡
WÈÂ²P0ˆ¡gHÃÚð†8¼¡rÀÃúð‡@¢‡(Ä#\àˆHL¢—ÈÄ&:±‰F �§HÅ*ZñŠXÌ"� ˆ.zñ‹ˆ;
__CPAN_FILE__ src/widget/templates/images/tab_bot_right_curr.gif
GIF89a�–Õ"b�ÒúûþýþþèïùíòúòõûöùýßéöåíøÚåõâë÷ÝçöØãôÖâô¦Àæh”Ôçîø“²à€¥Ú¹Íë¢½åÀÓî–µái•Ôãë÷¨ÂæûüþŽ¯ß|¢ÙÇ×ï©ÂæÍÜñd‘Óÿÿÿÿÿÿ!ù",�–ÿÀ�pH,�È¤rÉl:ŸÐ¨tJ­Z¯Ø¬v[p¿à°xL.›Ïh³7Ín»ßð¸|¾\Óïø¼~ÏgÛû€�‚ƒ„y…ˆ‰Š‹ŒN‡��‘’“w�”—˜™šW–›žŸ ž�¡¤¥¦…£§ª«¬p©­°±²[¯³¶·¸Jµ¹¼½³»¾ÁÂ¥ÀÃÆÇ—ÅÈËÌ‰ÊÍÐÑ{ÏÒÕÖoÔ×ÚÛcÙÜßàœáãäÝåçèXÞéìåëíðßïñôÖóõøÍ÷ùüÆûý{ýHÐÖÀ‚[LÈÐÔÂ†?=ŒHÓÄŠ#]ÌÈQÑÆŽ }I’ÏÈ’(+¥\	ê$Ë—~`Ê¤är¦Í05oêÔ’s§Ïÿ.?ƒê)´(¢F“Aª´©¦N•B�jt*U¡V¯þÌªu'×®7¿‚�)v,Ì²fY¢M›r-Û’nß†Œ+·#Ýºïâ­¨woÄ¾~œp0á‚†L¬¸ãÆùC®'yr¼Ê–ÛaÎœn3çsž?“-:éÒòP¿=­ZëÖö`›}-;íÚúpw½­ïÞþ€Sý-<ñâ‘7=®óæ¡W•^ô9uXÖ¯³Ê®]÷îÁ{¯ó;ù–çmšO¿i=ûLîß'“ÿ2>}IöïCÊ¯Ÿÿþ—€$ýG !(H‚
Õ G>8�„EH!^HG†ÊÁÿa‡®€(˜ˆ}HbL'"–¢Š+.Ö¢‹/:£Œ3FV£�7R&ÀŽ<öèã�@)ä�Diä‘H&©ä’L6éä“PF)å”T:	@Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ¹&Ôiç�xæ©çž|öéçŸ€*è „jè¡ˆ&ªè¢Œ6ê(¢ é¤”Vjé¥˜fªé¦œvêé§ †*ê¨¤–jê©¨¦ªêª¥@À«°Æ*ë¬´Öjë­¸æªë®¼öêë¯À+ì°Äkì±È
ÀÌ6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–û-¤«ÿîºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ð¾\ ÀÁ'¬ðÂ7ìðÃG,ñÄWlñÅg¬ñÆwìñÇ gü”lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÍ8°ÀÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\S�$ öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×m÷Ýxç­÷Þs[à€.øà„nøáˆ'®øâŒ7îøã�G.ùä”Wnùå˜g®9äD°�"4 úè¤—núé¨§®úê¬·îúë°Ç.ûì´×n;ûí¸ç®ûî¯W@Áˆ <ÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWoýõØg¯ýöÜw½@ ¼ðA;
__CPAN_FILE__ src/widget/templates/images/bar.gif
GIF89a#8÷‘µê’¶ëžÁõ‹¯åŒ°æ”¸í�Àô¤ÇúŸÂö�´é˜»ð—ºïŽ²çˆ¬âœ¿óŠ®äŽ²è�³è‰­ã–¹î Ã÷“·ì�±ç•¸í¡Äø™¼ñ‡«á„¨ßš½ñ¥Èû›¾òš¾ò“¶ë©Ëþ•¹î”·ì£ÆùŒ°å�³é˜¼ð†ªàˆ­ã¢Åø~£Ú’µë§Êý‚¦Ý¡Ä÷‡¬â–ºî†ªá…ªà„©ß™½ñ�±æ‡«â�³éƒ§Þ“·ë|¡ØzŸÖ…©à–ºï—»ï›¿ó�´ê›¾óv›ÓœÀô£Æú£Åù…©ß§Éü“¶ì’µê�¦Ý€¥Üƒ¨Þš½ò¤ÛyžÖ™¼ðx�Õ�²è¢Åù¦Èü�°æ�¦Ü¦Èû‰®ãŠ¯ä‚§Þ�¥Ü¨Ëý†«áŽ±çœ¿ô¨Êý}¢Ù‘´ê•¹í¨Ëþ—»ð ÃöªÌÿ‘µéžÁôp•Îr˜Ðs˜Ð{ ×{ Ø€¤Ûˆ­âw�ÔŒ±æŸÃö‘µë¥Çû˜¼ñušÒ˜»ï•¸î§Éý�Àõ”·í¢ÄøwœÓŠ­ä¤Æú�µê¦Éü~¢Ùˆ¬ã£ÚŠ¯åœÀó‹°å‚§Ý‰­äx�ÔzŸ×wœÔƒ¨ßp–Ît™Òr—ÐŸÃ÷€¥Û›½òušÑ¡Ã÷Š®å‹¯äq–Ï�Áõ”¸ì~¢ÚyŸÖyŸÕq—Ï’¶ì Ä÷ŸÂõ„©àžÂõ‰®ä‘´é†«â£Û¥Èú{¡Ø}¡ÙŠ­ã¡Ãøš¾ñ„¨Þ–¹íˆ«â‚¦ÞŒ¯år—ÏŸÁõ�¿ô�Áô�§ÝvœÓv›Ôu›Ó“¸í¥Û Âöt™Ñ¢Æùs™Ñ¦Éû}¡Ø}£Ù©Ìþ¥Çú Â÷tšÑs™Ð| Ø|¡ÙŽ³è�´éŠ®ãu›ÒyžÕ‚¨Þo”Íƒ§Ý‹®ä�³è†«à–¹ï|¡×o•Í~£Ù€¤Ü§Êü¤Ú| ×tšÒ!ù,#8ÿµM[³¦V›H»¤4Ú±‚É–
=dh¸qÃ
9–Àé´Œ‡”!‘$iZ	’&ImÀ
‘Âƒ!fxi'EŠ0.J»òDÌ(rxcŠ
›6Âð‘ãiU1_¹šÌÐ'‹–«Y$À¸†ñŠ71n>É�–L™%KJÿ°ÜAL
$d*QÂŠ•ž5Ðp¤	O°PýÁ£kˆ#FÑZ®pîƒs¾0€���Rhè‘ãï�Ž ˆnô†YÃ-4¼¤x@àK„‚H€Âœ‹`Ìxä‚ÒŠnxdû¶ƒÕ¶'\rÑ a€�§”€Ð1b„Ži"0ÀÜÀËj\ÿ"¶b…!ä.Í¸ÑÜ 
�™@ŸÌ…
,L±1@ßŒ”¤Â7L,ñÐ0,2€{TpA( á>ˆ0BA@@À!þõÐ„\,±„õ€J
˜A¡0�'d ã	
ø ~	hø@2�ÒÄ,Š(’ÃGÈÐÀ%0�@#L°À	¼òÁd�G€@�EN44±Á˜ÁÐ^
^ð$á€|�ÁX�#ZhvÑ=Ì (ª¸d>@)„D`"@|pÇ"TP‡3Û=Pˆ2 €‚74È‚hV ÂTâ€j €`xÀ�ÿ€á~ýíE‘,…|ªbª€§
€À°ª¶Z¬#°`< Mqµ2×&(1B,ypì/gP@Á£¨áÀQ,p�[Z@‹³Y™rH"4#H¯>ÜñÐAÁ` Ê$¥D
fˆÐ‹�¶
ðÀÂÕ`ï‰úC
B€¨ 1/  ”{Aé0@"ðpc$¡fXŒ±$Q	*t¼‰N(PgSX@ÀÐX�	uH\| p	$ 5	T`@�`8êÃ¹àÀ€6ØðÖÐk'Ü+*D­JH�3â¾:'vjÇÀÞ¯5ÿH©1#ð‚À�q“`µˆ|p‚¹ZêÁ8˜_ØüêÀÚTbGHì±Ç q�|qì}°0†	°›0Iè¸Å®è-„UØQ„È`Ý3–I(D	ŒQG|"˜±ô&“`PDƒ´ÐEe´ÐBÜÁtl€sFi¤a¶ ­íÚ*€E7]tB]´0Ì$¼@.@à@î¦%ÈF:#xY%na‹KáUhÁý&ø;áùáà¬îÃ‚t0	."UÅ€t	aVhŒîaáT¸ÈD6x0 tRFXÂ¦p…hhaÿ^Ã�…Ì\5< ¸€(,°�ŒàïWÁáaPƒà`úÖ×>(mŽmò£Ÿýð§?þù€$ ˜ç<èIÔ³ö´Ç=ï�O|äƒTÎ»ÙÕîvÈÝî�Ð»ßoxÅÃñ
�¼ L®r—Ë°8ç9Ð‰Žt0êT«Ö½noè[þ–�À
®p8\â×¸Ç] rûÙÌÖEµ±Ímp“›ÿê+¼%@;D3Ò”Æ4§AMjü«ÚÕ²v‡­¡Ëk@™ÊBÙ²—nf5»YÎ°³EÎJhsÄ$‚‰�cSÇ<6Cs‘ŒK&k×»â5/BÙ_úâ—¿&ÿ0‚a·y@¢5­j]+[ÛêÖ·Â5.‘¡‹Kë’À­r•²ÑKs±°æ�Õ%kYÍz–¦8å)P‘“T¦B•ªXå*XÉ
hüy–øä'@¥ƒ*•¨E5êQ‘šT¥.%ƒ1AäOgJÓšÚô¦8Í©NwÊ“.¤!éHIZR“Ö$%*Y	KZâ’—ÀÔ‘"'º)‹\#e€F6Â‘Žxä£Y¨@JÐ‚"ö M¨BÊÐ†:ô!.”ç<\HÏzÚóžøÌ§>ÔOLÿ³„
§8ÇIÎršóœèL§:×ÉN¥ºó�ðŒG4P �i’šÕ´æ5±™Mmn“›Ýwôæ7Á)ÌaÃÆ82’¡Œe0£Îx4gIËZÚò–¸Ì¥.wÉË^úò7f0FAŠR˜â¨H…*VÁŠV¸Ò™¯„e,e)ÉIR²Å¼$&3©ÉMÀ´“žü$(C…@b„(Ä%%’E,‚�pÄ# É;
__CPAN_FILE__ src/widget/templates/images/whiteDownArrow.gif
GIF89a€ÿÿÿÿÿÿ!ù,„[;
__CPAN_FILE__ src/widget/templates/images/slider_down_arrow.png
‰PNG


IHDR�‘h6tIMEÖ8Û5Ÿ	pHYsÂÂnÐu>gAMA±�üa
IDATxÚc¬œv��ÀÄ†ú:Dª¾~ó.„õ�M� j¦ßþÃ4üýGXÃ˜“€àï¿¿503üGhøó¤áùã;¯ž?@S'&© )«d°1#Ûð¤���sÏÆ¹ÿþA˜ÊÌ’�ß‘ýÏÄLp€ˆ‡_ÔÐÊÙx (‘e;	ªá÷Ÿ?dhåÍÍ
1 È…Ký{n02±˜9CMí�\¸Ð†ÿð`ýýány5c!±�@†‚†)²ø°b¨†Ÿ?!;ÝØdÉ¯_�ÿÿgú¦áŠ>YLA°¯¡~ýúM0âþƒ|
óƒ‰–A
Òpþâ"U^}‡'îµ"BIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/soriaButton-c.gif
GIF89a6wÕz˜Ä¸ÕÿŒ´ï—¼ó†¯ì�¶ð“¹ñ›¿ô¦Çø¨Èùˆ±í–»òˆ°í³Ðý”ºòžÁõ©ÉùŸÂö­Ìû·Ôþ¬Ëú´Ñý´Òý¢Ä÷‡°íªÊú…¯ì‹³î°Ïü¥Æø’¸ñ®ÍûŽµï¶Óþ˜½ó�Àõ¤Å÷±Ðü¸Ôÿ¯Îûš¾ô‰±íµÓþ‘·ðŠ²î¡Ãö�´ï…®ì!ù,6wÿ@€pH,�Èd2Àl:ŸÐ¨t:5Y¯Ø¬vËív'à°xL.›Ïç�zÍn»ßðx\E¯Ûïø¼~¿·øÿ€�‚ƒ„……ˆ‰Š‹Œ�Ž��
’“”•–—˜™™%œ�žŸ ¡¢££¦§¨©ª«¬­­'°±²³´µ¶··º»¼½¾¿ÀÁÁÄÅÆÇÈÉÊËËÎÏÐÑÒÓÔÕÕØÙÚÛÜÝÞßßâãäåæçèéé	ìíîïðñòóóö÷øùúûüýý
H° ÁƒI(\È°¡Ã‡#F¼@±¢Å‹3jÜ¸±…Ç� CŠI²dÉ(Sª\É²¥Ë—/ÈœI³¦Í›8sæÁ³§ÏÿŸ@ƒ
:ô€Ñ£H“*]Ê´iSP£J�JµªÕ«WEhÝÊµ«×¯`Ã†@¶¬Ù³hÓª]»v�Û·pãÊ�K·n]xóêÝË·¯ß¿
L¸°áÃˆ'öÀ¸±ãÇ�#Kž<y…åË˜3kÞÌ¹sç C‹Mº´éÓ§A¨^Íºµë×°cÇvA»¶íÛ¸sëÞ½[€ïßÀƒN¼xñ
È“+_Î¼¹óçÏYHŸN½ºõëØ³gOÁ½»÷ïàÃ‹?^�ùóèÓ«_Ï¾}{ðãËŸO¿¾ýû÷1èßÏ¿¿ÿÿ hà�&¨à‚jààƒF(á„VXáf¨á†vèmá‡ †(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã�8æ¨ãŽ<öèã�@)ä�Diä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶É¡pÆ)'A;
__CPAN_FILE__ src/widget/templates/images/treenode_grid_v.gif
GIF89a€rrr!ù,Œ€Ë¦
S„o®jÎ’kÿ�¸e¥uNi´Râèµ;
__CPAN_FILE__ src/widget/templates/images/slider_right_arrow.png
‰PNG


IHDR�‘h6tIMEÖ1‰ïÞø	pHYsÂÂnÐu>gAMA±�üaýIDATxÚc¬œv�ƒƒ“�á?ü‡ÓÿQ(†_¿~±)MueF&°Hô?„€‘p+óù‹WX †ýcåÿ÷ÿüù@ò÷øýûÏÏŸ¿~MþõÛDK
¨’‰�D€®áùã;Þ¾ AÃ«çL,9ºgåï_?ˆÒ@/œ9¼iÙ´Š[—Žþÿÿ�°øúùý�­ó6-n{ýì.Qp\Ü¼‚fÁòjÆ¿~ý+>
ÌÌ,†V^†VÞŒL,Àx `ƒ˜¤BB~¿($â;IRVÓ¸œJ®§™~½gsØ™�ž```Š120°‚'º`$Þ·
„ÏÜ�ÕIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/slider-bg-progress-vert.gif
GIF89a‡¢b|ÿ–±øŽ«îŠ©ža|þ’®ÿ–²ðŠ¦ÿ¢ºè‡¤ðŒª¼t–îˆ¢¬j‰Ø€žÄy˜œ`{°mŒä… Èx—ø�­Ú~—Ü‚ Î}žÚ‚¢Êw’˜]x¬g€¼t“Ö|–²j‚ô�ªÿ›µÈ{œä†¥ôŒ§Ð}œÌ|�ÿ”¯Âv”òŠ¤ä‡¦’[uâ„¢Ô~�ð‰£Ô|•Ø€¡ð‹©ìˆ¥Ø€œÈzš¶p‘Ø}–Ô~›àƒŸÒ~ Äy›ø�¦ÿ™³Îz˜öŒ¥¦d~Ò|š´j‚ÿš´Ü~—úŽ¦ôŽ¬Är‰ô‹¤ê†¡Ì{šôŽ«Öžî‰¥Ô Èv‘ä‚›ø�¬ÿ ¹øŽ©ºp�¨e~ªi‡Äw•ä…¢š_zîŒ©êˆ¤ÿœ¶Ø�¡Ê|œÐ|™ì‡¢Æ{�ÿž·¸m†ü�¨è†£´p�Âs�Ìx“Äu�®h€Ät�Ðz”®h�¤c}ªfÀr�Îy“ÿ’¬Ð~ŸÒ{•Às�Æz›ÿ”°ÿ•°¾u–þ‘«ÿ“¯ a|¸r’þ‘­°i‚Àw—Ò ºs“Üƒ£¬fÞ‚žêŠ¨ö�¨ÿ•±Þ„¤Æw–Ð{™®i�Òz”Þƒ£æ†£â…¤èˆ§ÿ“°ÿ˜³Ü��Ü‚¢Ö€¡ÿ—²ò‹§°i�Ät�Ô{•æ…¡ì‡¡Æu�ÿ“¯ü�¬Ö�¡¼s“â†¥Âx˜êˆ§Ü—òŒ©Èz™Âw—Æv‘àƒ¡â„ŸÄs�ØœÆu‘Àu”ÿ“¬Ð~žü�«Î|›à„¤à…¤è‰§Ô€¡Ö€ Æy™â…¥Î~žè‰¨Ò~�Òz•ú�ªÿ“­Àv–ü�ªÿ’®ÿ˜²ÿ˜²ü�­ü‘®ÿ•±Þ€™Ìy“ÿ”±ÿ•°ü‘«îŠ¦Êy—ÿ’¬Þ„£ÿ“®ºr“ÿ™´è‡¦ÿ˜³ÿ™³ŽXqÿ“­Ú�ŸÜ� Ìy˜æ‡¦~OeÈw–¦c~ŠUm€Of¾u“ÂrŒÿ‘«ÿ›´ê…�ì‰§Ò}šò�«Âx—ÿ”±¤fƒ¦g…ú‘­ÿž¸¶q’ê‰§¶k„Îy”ÐŸä…¥Ö€žÜƒ¢¸r“¸s“þ�­à…¥Ìw“êˆ¦Àp‰!ùÿ,ÿÿñf�Àåv #@
0 Â˜CðNK¤qN h™VÇŸ0A�ƒl£	1òHi©†MR ªýòD¥™5oÒ„YéÕN›>såTHÈg:€
€H…�ptxx êT¨R©ZÕšëÕª]Á~Ýê•ëÔvðô8›vm´jÙÆ}ÛV®[¸wëÒ�km3·}ÿN�T'–‘Á…W lqã
ÄêSyòÔÊŠ‡™°\A3gÏ‡kTêäEÑ¤M£.}z4ëÕª+åy-›v´Ò—DßF‘Û€°(-zÿ^Ã7ðÞ€+*ž¼ÅrÍŸGg®œºóÇøb°»vî}ÿï.~;ùñáÑ—¿¾û:}#¼tWV,þüúò;Ôñ4býüù`ÿíGà€þ¹É–�†‚:aƒ.Há„Z(a>È!…™ä!Àšlâˆ%žH¢‰"®¨b‰rˆØŒ2ÂXÀKØˆ£Ž9n Ç�=þˆ£>I¤�Kiä½SJªÒä“QöâN)YD¹È•Y
²%–Zr&˜^RC7”yfšj˜‰fm®	§›7Ì)gœoªñÄcçž�ø©ç�þI¨ €"z¨¡…ÎCÄ9VH2ÅI@*)¥–NZi¤šfŠ)§”Æj:£¬àÀ¤¤šŠj©§¾‘j«éôÿ³‚S$“Î#³Özk®f(@M*¬øÐë¯Á¬°¾kÜ(Ë¬³ÜÜP,³Ò
ƒØ`-¶Úš1·Â~›m¸àz[®¸Úò3@=Ú óM„8’
:lÀ+/½öÎ[o¼úæ‹/¿øî2‹?Ô+0Á\pµ(\oÃ3ì0ÃÐØÓE½�0¢D"kÌqoÜ±È {<òÇ�Ü#rÜLÂ°ì2Ì2¿sË6×Ls
ð²sÏ?û³[�°ÍÐEÝÑF€J(E;ã4Ô$HýtÔScÝJ./È2�[wýuØ^ƒ½%esBË-i¯Ý6Û_«
·œÌÂÞèqÆ!w#ÿBÀÞ}ÿÍ7~N¸à�^84‰òUüí8ä’?ù“_žyå”cn¹äôÌyÄ1Ã	�n:ê¤Ãb
ë¸»ì©ÇþzíºÜNzî°óžúàâÊïÁŸðÂŸ<&È�É'< ÏG?}õÒS}ö«PR‚(@Ðý÷á�¾øÞŸ_†-\¨Ï¾ûí‡¿~üÌ¯ŽüL„p
(õç¿ÿúã_ü'À?„À€¨Ÿ¨À&°|`È@:°~8 0¤�A
rpqÐ > B
î�„!Æ	K¨BšÐ…-dá
S8ÃÊn¸@î�+äp‡=ü!H}¨Ã!
1ˆED"‰¸Ä#2ÑˆIdâÈ )|Áù br0Å¨ w A¨ vÀ#
hÇ5¾Ø* ÿ‡TÐ�;
__CPAN_FILE__ src/widget/templates/images/submenu_off.gif
GIF89a	÷!ù,	ÿ9èàŸÀ�&¸°aAƒ$è  ;
__CPAN_FILE__ src/widget/templates/images/incrementMonth.png
‰PNG


IHDR	Ú›g`tEXtSoftwareAdobe ImageReadyqÉe<oIDAT(ÏcÐ´ò6[³içBløÔ¹KÍ@y ¡Ä?�ø?þ9iöb{˜"nGWš\0íÿÿÿòÈŠx€ø	’¢'ÇO_Ð‚ÊÁ�p,LQr~M1ÌtEÌ@|„ß¾{¯„$Ž¢„m*š{C�Malü\;Ý§\ÓIEND®B`‚
__CPAN_FILE__ src/widget/templates/images/dpMonthBg.gif
GIF89a³™¾ô•¹î›¿öš¾ô—»ñ–ºï›Àö—ºð–¹î—»ðš¿õ˜¼ò™½ó›À÷!ù,°ÉfŒ*«1` ³ŒA$Éq‚A;
__CPAN_FILE__ src/widget/templates/images/tab_right_r.gif
GIF89a�–Äb�Ò Æÿ–Àÿ­Îÿ¸ÔÿÀÚÿÈÞÿh”Ô€¥Ú³Ðùçîø£¾å‰«Ýš»ë¡¼äd‘Ó‰®å‡®æ|¢Ù�¸ø†°ì’¼ýûüþáê÷µÏ÷¨Âæ¬Íþ¹Íë”¾ÿÿÿÿ!ù,�–ÿ  Ždižhª®lë¾p,Ïtmßx®ï6çÿÀ pH,�È¤rÉl:ŸÐ¨tJ­Z¯QvËíz¿à°xLkËè´zÍn»ßÇ3|N¯Ûïx´<Ïïûÿ€u{�„…†‡ˆJƒ‰Œ�Ž�s‹�“”•–S’—š›œš™� ¡¢�Ÿ£¦§¨l¥©¬­®W«¯²³´F±µ¸¹¯·º½¾¡¼¿ÂÃ“ÁÄÇÈ…ÆÉÌÍwËÎÑÒkÐÓÖ×_ÕØÛÜ˜ÝßàÙáãäTÚåèáçéìÛëíðÒïñôÉóõøÂ÷ùü¹ûýeýH0ÕÀ‚ELÈpÓÂ†)=ŒH±ÑÄŠ
]ÌÈñÏÆŽ ñ|I2RÉ“œFÿ¢\©‡¥KH*_Êìs¦M+5oêÌ²³'Ÿœ>ƒ"*´è¢F“ú@ªÔ(Ó¦BŸBõ)uêÎªVobÍ:s+×—^¿²+%Ù²%Ï¢
©vmÇ¶n3Â�[q.Ýˆvï6Ì«7!ß¾ÿ(xp¿Â†ó!N\o1ãxŽ·‹,9åÊå.c§y3¸Îž»�íŽôÚÑ¦­¡N-�µØÕ®›ÁŽm�vÖÙ¶‰áÎ­�7ÔÝ¾{î�xÒáÆi!O.�yTçA—Cg%}:ªêÖMaÏ®�»Vï6·ƒO9^¦øò—Î£¯¤~}1÷+ÛÃw$>£úöáÏ¯‘?[ÿ í  èG�þ” ÿF.øŒƒ5!NG…º�a†ªpè—‡mbK#V¢‰'–¢Š+*Ö¢‹/6£Œ3BV£�7N–£Ž;ZÖ£�?’SÁiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå•HÀ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiç�xæ©çž|ÖIÁ*è „jè¡ˆ&ªè¢Œ6êè£�F*é¤”Vjé¥˜fª©¤<p †*ê¨¤–jê©¨¦ªêª¬¶êê«°Æ*ë¬´Öjë­¸æktPÀ¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíKµØ:›XÐ�à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæÛ.
°Aó ðÀlðÁ'¬ðÂ#��;
__CPAN_DIR__ src/widget/templates/images/Tree
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_loading.jpg
ÿØÿàJFIFddÿìDuckydÿî&AdobedÀ

E‡vlÿÛ„ÿÂÿÄ¿	!"#1AQR$2r3&!1AQBðaÁá#¡C$!1AQaq‘¡ð�±ÑÁáñÿÚë‹²Ó$2üÑ ƒ«ƒÈlÅt	M%9MÉ‰AèÿÚÏö\(L¾Söì]/fÜ6kŒâ�:W€ì^~Ç­|òú?ÿÚH°Ä-»W.qï%ñÆbña.ª¶§ÿÚ(¥L’u‘D¶ùiõ>—"ÙZ÷èH=ŒñÿÚ?mmfªg±”$i-Zò^®r:©)¶V
:³‚rÞç
îÚúêä
ü†¾î_ ö¸‘³ÿÚ?}=7ÖºŒÕ_1]ü¡Llw*J@¾èb»‡Uç¯¯|vÿÚ?]ƒ%â5jlN]&6¸]Áb(©â‚hŽ‚!¼LP<@IÔ�<®'B“÷
:IT¤›ôQÜÂd›¹)ÅÝ·p©¨›½î�6=2d®8ÞÜ²9~—qÔˆ¶P#çk¿ASC¦tÜ�y7˜Jž?´Å-ðR¦ü^šuOcd”h=^¨šItôH†ë¤uPM¨×”â*V¾�Ù9òâæÇ�y7K�FIlÙ}÷äÝZëÇôQ"Tl‘[îó��ä_Of´à;,~á^L©9kåfÌŸŽÿ§ÿÚ?!0“æaÇ–
¢1$P`,À�j†Ð€å7ÔX$©8P8(		+åRÐTa4bhz<”•â‹RæE}Ê÷ÅÓÿÚ?!>æ8V	ÕöTFD
Lî	Î¶Ãø[ôSÅCÌCkÍÆÑŠ™˜@$ï—$ª}†‚XVYI(¯ãnë9¯'Xù1ÓÿÚ?!ÜØz
*H	À Ù¾óÞ¯×x©hÐ{úï5§Á™˜Yd,ƒ¡uªó—x;¼7züËøÏjð«~>“ÓÿÚe;rÿÚ?Êæ¾Bª'‹MË)“Æ¸UFî�nËÜi%'Ä¬xvh©… ³ÎŸçÚAÒï#ü�èÄÚáüñ^¢†¸œ¿§ÿÚ?G–Õ§g•À$3'V*2$!�"
aFv‹îîô8¡!)`Uˆœ‚Ë@•‡É”bàE�‡®á¿Ú%Çócpµ®ÓS0v�êeéÿÚ?q�vDÀX‘$À‹Žƒð V€a,I™¦±‡—m�Ø{Q`Y¢IhlbFI$î€€S‚–	>áÕÆ±cQss\½¾w-ª?šþ'ÐÿÙ
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_z.gif
GIF89a€999!ù,Œ�©Ëí£œt‚zi¶¸kÏ}M;
__CPAN_FILE__ src/widget/templates/images/Tree/document.gif
GIF89aÄøüþõùýüýþ÷ûþûýþúüþùüþüþÿ×Þâûüþïô÷õúýÛàãÚßãêîñØÞâôùýìòöçìðöúþöúýÙÞâöûþåëðíòöþÿÿýþÿóùý_€ŸF^uÿÿÿ!ù,mà'Ždivhª¦e·½p¼um„È1MvHwqÀ ' u0H`XP&–¢¨SéH„Á�ôÓQ4€Xl0l;ŒŽLœ
…x‚@šs¯ék2€g}€€††g‡ŠŠ‰‹‹�Ž‡�‘g+—[&š"!;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_l.gif
GIF89a€rrr!ù,Œ€Ë¦
S„o®jÎ’k¯âH‚æ‰¦êÊz;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_t.gif
GIF89a€rrr!ù,!Œ€Ë¦
S„o®jÎ’k¯âH6[vZé´F-:q¾;
__CPAN_FILE__ src/widget/templates/images/Tree/plus.gif
GIF89aæ999† ÇDDDîñõ�œÅCCDìïôçëñïòöûüýùúû…ŸÆþþþÒÙåØÞè÷ùû…ŸÇíîðãçï‡¡È„žÆ¾ÉÙûûýðòöËÔáÛáêßäìäèïüüýßâçôõøüýýåéðëïôýþþÐØäàæíCDDåêðrrrêîóÉÒàÄÎÝòôøôöùâçîÙßéëîóÞãìòô÷×ÞèÓÚåêìîøùûÚàéàåíÑÙäðóöóõøÃÍÜùúüßåíö÷úêíóèìñÊÓàöøúÞäì‡ Çâåêþþÿzzzy–Áÿÿÿ!ù,x€I‚ƒ„…†‡ˆ‰…HŒ�Ž‹ƒ"/‘I	5,!D‘œ9-‹F
4@0¬„H
¼C2'G¸<>1E%#‹B+=.8)‹:? 76
A;Ù¸(&$3*‹Žñ�ŠôõI�;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_expand_plus.gif
GIF89aæH999~šÃDDDCCDïòöçëñ€›ÄîñõùúûìïôûüýþþþÄÎÝãçïÙßéÛáêÚàéýþþßåíëïôùúüøùûÃÍÜÞäì~™Ãâåêðóöäèïö÷úÉÒà¾ÉÙàåíöøúåéðÓÚåðòö}™ÃšÃàæí}™ÂÑÙäüüýÐØäØÞèêìîûûýíîðÞãìÒÙåCDDòô÷ôõøåêðèìñêíóóõøâçîÊÓàËÔáòôøßâç›Äüýýôöù÷ùûßäìêîóëîóþþÿ×Þèy–Áÿÿÿ!ùH,{€H‚ƒ„…†‡ˆ‚F‹Œ�F‡FG’-@3C�’
?#š†‘�.	8=�D),	5
/%�>½E�21A+*Ã¥ ;<(�76!09$�B4&":'�ŽŽ‰óôõö÷øô�;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_blank.gif
GIF89a÷'ÿÿÿþþþýýýüüüûûûúúúùùùøøø÷÷÷öööõõõôôôòòòñññïïïîîîìììëëëêêêèèèçççæææäääãããâââáááàààÝÝÝÜÜÜÛÛÛÚÚÚÙÙÙÖÖÖÕÕÕÓÓÓÒÒÒ½½½___!ù',OH° Áƒ*\È°¡Ã‡#JœH±¢Å‹1;
__CPAN_FILE__ src/widget/templates/images/Tree/blank.gif
GIF89a€ÿÿÿ!ù,„�©Ëí£œ´Ú‹³>;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_loading.gif
GIF89a÷œ¿ó“·ì{ ×žÁõ¥Èû%g¸ŠªÚ�´é¡Ä÷–¹îv›Ó‰©Ù„¤Õçî÷´Ðù±Í÷îóú�®Ü£ÆùÄÔì�³è�°àøúý�°äŸÁóñõû•²ÝŒ¬ÜŠ­âµÑúûüþ|¡×…§Û¸Ìé’µè§Éüƒ¥×Š­á‚¥ØùûýˆªÛ®Îûõøüš½ï’³æ�¯âèïø�¯Þˆ©Ùþþÿ›¶ß˜´ÞÉØî±Íõ¨Êû€ Ï‚ Î†¨Ù�¿ð×âòˆ«á…§ØŒ­ÞŠ«ÜŠ«Ý�Ê‘¯Ü®Ë÷¤Æùˆ©ÛÈ×î�¾î¨Çô‹¬Ý´Éçˆ©ÚÜåô•·éŸÂô�£Ö~¡Ö�²ä‡©Ýêðø°Îø¬Ãå»Îêkkk¯Åæ›¾îœ·à„¦Ø¯Ìõ¯Íú–¸é} Õ£Åø}œÊ÷ùüÇÖí�¬Û™»íÅÕíááá°ÌõwœÓÁÒëžÀòëñùÒÞñ–·çô÷û¤Åöˆ¬áßçõÂÂÂœ¾ñãëö”±Ý�¼é˜»îŽ¯à‰«Ü·Ëè�±çˆ¬â™¼ñ�¦Ýÿÿÿ!ù,ÿ	(PEƒ&ô`FÃ�<I„X± �àMÀŒ(0‚ˆ
u*jc Œ�)¨$°
…L`¬éÒ¡C�#$èteÁv²Pq@ô 7’"XáÄÀ	,†<˜
§ 
²fe1aàh¸ Áà Ò¦Å£¥ 
?tüÈõ³Ð†¹s—Pt¤@‚¿	Dàd�a"
èa(Š�!·8gà™Š¼#… \¸q%ƒÓ9.Pˆ0pO	>°as�Â!6ì!B0À£�ïßÀûÄ1� ’+_þD×„!L|@½uL`9Æ”4
Â+ø²EM‘€ (!Câ	‰U\ 'è¡�œbæë¯;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_child.gif
GIF89a€!ù, Œ�©Ëí¢œ`ÑkïÌ:òþi!¦tÒH¡[iVÏÇòS;
__CPAN_FILE__ src/widget/templates/images/Tree/closed.gif
GIF89a÷¼ÐÙã³ÊåºÎæ°ÈäÎ×ã§Âá®ÇãÀÒçÁÒè¸ÍæºÎåØâîËÙêªÄâ¦Áà®Çä¹Íå·Ìæ±Çã¯Çä©Äâ¼ÏæÕàí×áîÂÓèÈ×éÄÕéÅÕéçíónˆ¨æìò«½ÏÁÓèÙãîÃÔèÜåï­Åâ­ÄâµËåÉÙìrˆ¢àèï†¡À´Êäg‡ªÌÚêÒÞì{–·Š¦ÆâéñÊØêw‘°u“³“­Ì¨»Ðr‘±±ÉäœµÒÛäî–®Ç–±ÑÓÛåˆ¢½Ì×âÉØê˜°ÉÜäï¿ÒéŸºØ~’ª­ÆãÆÔäpŽ¯£¿ÝÁÑã¼Ðçäêòj��ÎÛë‰¦Äy�«„žº«ÁÚ† »ßæðv’¯ÆÑßÖàí²Éå«Ãáãêðd…¨Œ¦Å}š¹ßçïl‚œz˜¹”«ÅâéðÊÕã¾Ðç¿ÑçÆÖéÞæïhˆ«s‰¢j‰ªž¿³Éã¸Ìå{˜·¬¾Ð¾Ðè®ÄÞáèð…¡ÁÀÒèÍÛëÓÞìµËäÊÙê¯Æã€™·«Åã°ÁÔ±ÁÔ·Ëäœ±Èaƒ§²ÃÕ¾Ñè¡¼Ú…Ÿ½eŸ��»yŽ©‚˜´vŠ¢ÐÝì‘¬Ìo†¢èíó²Èã«ÄáªÃá°ÆãÇ×émƒžd}œèîô—³Òv”µÔßí‰£¿x•µ¬Åã¶Ëäl‹«ÄÔè¯ÆßæëòÎÜìÒÝì±Èä¨ÃáÏÜëäêñ®Æâ¶Ëåt‘¯àèðåëñ¿Ñè«Äâm‚›oŒ¬¯ÀÓ»Íâ¶Ìær�±¨ÃâÝæï¥ÀßÍÚëÓßí®¿Ñqˆ¤©Ãâ!ù¼,ÿy	H° Áƒyeò1%ŠM4n ùC ¢•W×<	²#L >°r½ù dI�`~TjÄÁ¨U¦´ˆ‘“ÂË™=x]âÃ$†**µ„è±àÂ¸\Œá5ËFQ˜ìˆRTÊÉ-x€d8Â+•¡:-ÈÈ ÉÌO@ ³!¯*]D`@p ™
@P€@ƒ†Ñ(€ÐÆ§lÝ0Dœ%¬’é‰Y$D� AT&d)áÅ"Î#H­òX�Ç€ˆÅk‹”Q°eÙ´§…]¤
8øÄKMß´„ÛJ2ˆ�\éAÄ«ÓK‹`¨x1£C!JŒšLúâj ]‡P¤)’(¡û÷ð;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_p.gif
GIF89a€rrr!ù,Œ�©Ëí£œ”�‹o»Sþy8ŠK;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_c.gif
GIF89a€rrr!ù,Œ�©Ëí£œ”�‹oÝ¼û†L;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_x.gif
GIF89a€rrr!ù,Œ�©Ëí£œt‚‹3¨¼û†`;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_expand_minus.gif
GIF89aæI�œÅ999üüüóôö��Åîðóéìðõö÷ïñôþþýúúúâæìÿÿþßäëÔÛåñòôûûûýþÿÒÙäùùùDDD�œÄ€œÅøùùÝâêÞãêòóõ÷øøÜáéÿÿÿþþþËÔàùùúêíñÚßèôõ÷äèí¿ÉÙÕÛå¾ÉÙëíñôõöÓÚäÌÔáÅÏÝðòôÍÕáìîòÖÜæíôþñóõþýýÊÓàüüûçêïºÆ×ùúúåèîãçííïòÛàèÄÍÜ}šÄåéîþþÿö÷øëîñ÷÷øæêïèëïÄÎÜìïòy–Á!ùI,€€I‚ƒ„…†‡ˆ‚H‹Œ�H‡H7%,.0
?(�'F+&9!)�=$¦†H4*:­C
±…H<Á
�"E;A8Ç²6G2 	¼„HD/5	�B-#3@1>�ŽŽ‰øùúûüýù�;
__CPAN_FILE__ src/widget/templates/images/Tree/Tree.css

.dojoTree {
	font: caption;
	font-size: 11px;
	font-weight: normal;
	overflow: auto;
}


.dojoTreeNodeLabelTitle {
	padding-left: 2px;
	color: WindowText;
}

.dojoTreeNodeLabel {
	cursor:hand;
	cursor:pointer;
}

.dojoTreeNodeLabelTitle:hover {
	text-decoration: underline;
}

.dojoTreeNodeLabelSelected {
	background-color: Highlight;
	color: HighlightText;
}

.dojoTree div {
	white-space: nowrap;
}

.dojoTree img, .dojoTreeNodeLabel img {
	vertical-align: middle;
}


__CPAN_FILE__ src/widget/templates/images/Tree/transparent.gif
GIF89a((÷ÀÀÀè×gÔˆ0ÿÿÿÔˆ*ç‘2¨!�æàé$ç0‘2H!º`çL‘2H!º`ç$‘ëéh�î‘8ÿÿÿ‘2‘«‘ëé¸éäéÜçdÝtuê¼�î�ûxÿÿÿ�ûqÝu!¨Ýu,!º`¨éÜ@ê$éä@ê(z
ì¨éÜ¨ÿÿÿè,Ý›‚çtHè(‚èŒÝ‚é@‡€–Hæ‚°é@‡Lèè@è�‘È!ˆé\‘Q¨‘mé´è¸‘È!ºXé„‘QHèÔ‘È!ºXé ‘QH‘méäæ„Dº«Í0!�Ôˆýð0ç�ûl !º`é@‘ÈGi ê‘Qá8‘mGn8Gi(�ûq�Õ†�ç¼é`�çÈê�î�ûxÿÿèäê�î‘pÿÿÿ‘m‘	¼È!º`éÄ‘	’!º`êÝíÝí b¦Èáb¦ÔéPGi(êD�î‘pÿÿÿ‘mÂÂÞáÂÂãGn8Gi(ÝhªGi(Gi(êPê ÿÿÿê¼Ã\”Á pÿÿÿÂÂãD•ÕGi(c c EµGGn8I¼�ê†Ôê†Ôê†Ôê†Ô¨ê Ýltê¨I¼�I¼�æà£æ‚°!ù,((CH° Áƒ*\È°¡Ã‡#JœH±¢Å‹3jÜÈ±£Ç� CŠI²¤É“(Sª\É²¥Ë—0cÊœI³¦Í›8	;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_y.gif
GIF89a€rrr!ù,Œ�©Ëí£œt‚‹3X›v[}’‘�ù Žj;
__CPAN_FILE__ src/widget/templates/images/Tree/treenode_grid_v.gif
GIF89a€rrr!ù,Œ€Ë¦
S„o®jÎ’kÿ�¸e¥uNi´Râèµ;
__CPAN_FILE__ src/widget/templates/images/Tree/minus.gif
GIF89aæ999ˆ¢Èüüüïñôéìð�œÅóôöîðóÿÿþõö÷þþýúúúâæìˆ¡ÈìïòìîòñóõðòôûûûüüûÌÔá‡¡ÈÄÍÜèëïÛàèýþÿÕÛåÜáéþýýåèîËÔàÖÜæ÷øøÚßèßäëzzzºÆ×çêï¿ÉÙ¾ÉÙêíñÔÛå÷÷øÒÙäÄÎÜùùúæêïÓÚäãçíòóõÞãêÍÕáDDDrrrÊÓàÅÏÝÝâêåéîôõöíïòíôþþþþñòô„ŸÈëîñäèíþþÿôõ÷øùùùúúùùùö÷øëíñy–Áÿÿÿ!ù,~€J‚ƒ„…†‡ˆ‰…IŒ�Ž‹$&73"9H
‹',2(:›„I)8A ‹6/0®*²§+À45#§!;1GE=¼ƒI%	-
JÒ‚I.>	F
‹@CDB<?‹Ž÷�ŠúûJ�;
__CPAN_DIR__ src/widget/templates/images/TreeV3
__CPAN_FILE__ src/widget/templates/images/TreeV3/x.gif
GIF89a¡rrrÿÿÿÿÿÿ!ù,„�©Ëí£œT†;¯ÞZõ
†âHV;
__CPAN_FILE__ src/widget/templates/images/TreeV3/document.gif
GIF89a¥F^uÿÿÿ_€Ÿóùýýþÿþÿÿøüþõùýûýþ÷ûþüýþúüþùüþ×ÞâûüþüþÿöûþÙÞâíòöåëðÚßãêîñÛàãïô÷õúýØÞâöúþöúýçìðôùýìòöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,s@€pH,�Ha`Él2‹‚tJ% G•z%Ê`L ºÃÀDãA¸Î&‚VJ�2YQ0

„„

hLzc}
”		‘˜› £‘ ££©©‘ª­­¬®®‘N´}I·¸DA;
__CPAN_FILE__ src/widget/templates/images/TreeV3/t.gif
GIF89a¡rrrÿÿÿÿÿÿ!ù,!„�Ë¦
S„o®jÎ’k¯âH6[vZé´F-:q¾;
__CPAN_FILE__ src/widget/templates/images/TreeV3/i_bhalf.gif
GIF89a€rrrÿÿÿ!ù,Œ�©Ëí£œ´RPñÍ|û©�N;
__CPAN_FILE__ src/widget/templates/images/TreeV3/expand_minus.gif
GIF89aÆEy–ÁDDD999�œÅüüüúúúâæìÿÿþþþýîðó��Åóôöïñôõö÷éìðüüûþýýÊÓàùúúåèîçêïºÆ×ÍÕáðòôÅÏÝìîòñóõíôþÖÜæ÷÷øëîñö÷øæêïìïòÄÎÜèëïÛàèíïòãçíÄÍÜþþÿåéî}šÄÝâêøùù€œÅÞãêÜáé÷øøòóõ�œÄñòôÔÛåßäëûûûùùùÒÙäýþÿ¾ÉÙÕÛå¿ÉÙëíñÌÔáÓÚäôõöäèíËÔàþþþÿÿÿùùúôõ÷Úßèêíñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,…€‚ƒ„…†‡ˆ‰Š‹ˆŽ��‡=6*>
3“;#?</I
A“(C5,B
1©†@0'°´…9%ÄËË‚H$&2 D“"F	E¿„!48	:.“G-7)+“‘‘Œÿ
;
__CPAN_FILE__ src/widget/templates/images/TreeV3/plus.gif
GIF89aÆy–Á999�œÅüüü��ÅþþýóôöîðóïñôDDDúúúâæìÿÿþõö÷ßäëÒÙäéìðûûûýþÿÔÛåùùù�œÄ€œÅøùùÝâêÞãê÷øøñòôÿÿÿþþþÚßèÜáéùùúêíñËÔàôõ÷¿ÉÙÕÛå¾ÉÙëíñôõöÓÚä}šÄÌÔáÅÏÝðòôÍÕáìîòÖÜæíôþñóõþýýÊÓàºÆ×çêïüüûùúúíïòÛàèèëïãçíåéîþþÿÄÍÜëîñ÷÷øåèîö÷øÄÎÜìïòæêïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,€€‚ƒ„…†‡ˆ‰Š‹‰Ž��‡5$,.0='“&D+%B!(“?"©†4)<±A
´…:Ä	
“;9C8Êµ6E2	 ¿„F/
7“@-#3>1*“‘‘Œûüý„�;
__CPAN_FILE__ src/widget/templates/images/TreeV3/i.gif
GIF89a€rrrÿÿÿ!ù,Œ€Ë¦
S„o®jÎ’kÿ�¸e¥uNi´Râèµ;
__CPAN_FILE__ src/widget/templates/images/TreeV3/closed.gif
GIF89aãÿÿÿÿÿŸÏÏ`ÿÏŸŸŸÿÿÏÿÿÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,OðÉI«½˜–½G–rF xX!¬¬Àq)Ï¤‰>Eì<Oœ“\Ï ìnÂáÎøCêˆL[ð	-AÏ(ÓèÔ‹„f°EnÝƒ´z½þ¸ßðL;
__CPAN_FILE__ src/widget/templates/images/TreeV3/l.gif
GIF89a¡rrrÿÿÿÿÿÿ!ù,„�Ë¦
S„o®jÎ’k¯âH‚æ‰¦êÊz;
__CPAN_FILE__ src/widget/templates/images/TreeV3/expand_leaf.gif
GIF89a¡rrrÿÿÿÿÿÿ!ù,„�©Ëí£œT†;¯ÞZõ
†âHV;
__CPAN_FILE__ src/widget/templates/images/TreeV3/i_long.gif
GIF89aˆ‘ÿÿÿrrrÿÿÿÿÿÿ!ù,ˆÿ„o�ËÙï`S’ÑŠ.Ž›w½�˜X‘’	¡�:uk¹^(ðrguþî¾Ì›�~® �øAÒ€Ê!óYl–¤'jÊºÂ¶ Iî2êu‚Ç]ò·Œ>«Åiöz†›ÝtyÛþ®Æõs|�˜wµGØ'øg¨8˜UèxÈ˜¹HÙ¸i9‰YÉyóè¹	š)êwŠˆ*©ªÉjš
»Û:û*{K‹k›Ë»ëKÚ	ü‰£%<Jjìª\Ë¬ëÜý‹\*mMŒ=¬“¬}Ì]í½,ÞLþl�>
žÍ¾ÝÓíþ
.?n_Ž®ŸÎ¿Nßà;!÷Î#˜Ï`A„û&dØÏaCˆÿ(^ówQbD‹ÿê2rÄØ1$È‘+‰WÒãÉz)E¶$ùñ¥Ì˜4W¬i$g1—8wÂ´9èA¡‰>4:éF¥&u¢ìù”©J§,¡V•ÊëOª7µÎôjµ+× c‡–-zöhÚ¤k—¶mêóëÛ©qÃ’­6ïÜ¬{·âí+÷¯à¨€íš|µ°^Äbß%ìø0äÉ‰#£µ¬3[Ín9Ã¥ÜôãÊ¢%“>õèÔ¬W»6ÝöëË¥i«–�ÛvlÝ³3×ö}›wnà»‰÷ÞüypãÃ•w~¼sréË¡7§þ{ôÏÕµ_çžüvºÓÅ'ßÝ¼ðõÌÙ[wï¾úöôß×�¾ýýøùëÿïà¢�ãñå™�ç!Xž‚ò9˜„þI …2˜ž…bX ‡úÕ ‡‚˜¡ˆš!ŠªX!‹’Ø!Œ¢Œ#ÒX¢�'ê˜"�+úØ"�/â#‘3¶£‘7"Ù£’I2ù£“MB¤”QR9$–
¹¥•Ujéb—`rf™džée–‹Õ˜¦˜kæØ¦™q¢9æœvÖ‰ç›Eæ©XŸ	ÊÉçŸtêy$¡Kú$¢S*z%£_:ª¦Ÿl:)¤nJ
'¥™Z
(§ƒbº§§wŠªi¨ zê¡©&ºê¢­6úê£±F*è¨³^Zk©¨æJj¯·vúë§¼kë°ÆVJ¬®ªÿ»i²¾2k*´»"+í²Ô^Ûlµ¬jë*·°z++¸´b-¹Ófk®µè®[.»ç¶ï»òª/½ón›.¾îÚË¯¾õú{o·ù
¼/Àýü/Â;0Ã+|°Ã	K¼p¸
[ü0Åc<1Ç�›±ÇƒÜ1Éãz±É#£²Ê¿1ÌË,2Í.ÇŒóÌ9×¼óÍ:ÿÌ3Ð>MôÐF³\2Ò'+®Ò+3�²Ó6KÝ3ÕB[]4ÖGCÝ²Ö^s�4ØKµØO“ÝµÙS«]5ÛW»�5Ü[£6Ýc[¶Ýgã�¶ÞkûÝ6ào7ásó]7âw+û·â{3¸ã�C>¸ä‘ÿS^¸å•c~8ç_þ¹æ™{.wè¤ƒ^zê¨¯.zçÏæÝºé¯÷»êµ³~úíºçÎûì‰÷îlðMÛüð¸û¾8ò�+?9ó—;¿9ô£Kïºð°=õ²[O;öÝkO<øÇsÿ»ø»›ï}ùä'¿þòí7ÿþóñG?ÿôõWoüù÷oŸúì÷�¾î/|¨¿*0{ôŸûø½
‚ê£àÿhÁbpƒÌ ü<(?ÒO„ö#!þ8XA^°ƒ*Ô _˜B®0†4œ¡
]XCÞðƒ-ä¡uDæPˆ;a�øC"‰CdbGxD(&Ñ‰K”b­øÄÿFQ‹SÄb¹xE0fñ„]ãÉF4Ž‘[TãÙXF7*qŽT¤£íhF<Ê±Ž|¼cóøÇ=úq�€$¤ ‰ÈC*Židä	hBG¾’m”¤-HLR“‰ää")GOŠ”�$å#
XISN•¡Tå%]™IXnR–�¤å'YYJ\ž2�©Ôå*yÙJ_¾R˜±$æ,�YKdÞ˜¹dæ.8LgþšÅ”f4©yLkV›ÉÔf6¹¹LpŽR™ãôf7ÅiËr¢“œél';ßiÎpN°—ñTç<ƒYOwæžëÜ§?û	Ð{63 ,h$õIÐƒòS Ïdè4zMˆnSÿ¢ß¤è9-*OƒÒ3¡Å¨=5ŠOŽ†Ô£%éBA:P“þS¥"M)JúÒ‡Æ4¢3�hM+zÓ‹æ4£
]éN?ÚÓ–Â4¨,-êOKzÔ“5©>]ªS;ÊT¡Êô©#�ªQ©êR¬ªZ�*W¿ZÕ®ÒT¬6%+NÍªS´ò¬YeëVÃêV¯Âu®m¥ë[ëŠ×»êU®yåë^ÇWÀÚÕ¯„l_
û×²V±ƒEla{XÈ&ö¬‹¥lc%ûXËFV³“Mke={YÎf´›%mg×ZÓŽµ¥eíi�úY×®¶©•­co‹YÜŠV·ªå­msÜÝ··Ãý­p�K\ä7¹Ìÿ]®siÛZè¾©j•îl©[ëúV»Åå®r½Û\ð>»µ¯yÉ]ôNW©ÙUïuÙ[^÷nW¾Ý¥ïwí^üŽ¾éåïz›Ú^ÿ¾Àñð|
\_ßWÁùeð~	Ü_ÿWª–ð€)œ`WÃÖp†9Ü`wÄ&ñy|b‡ØÄúM1‹QÜâÃxÆ*.ñU\cß¸À9–q�iüâ9ÈDÞq„‹lÕ$W×ÇH^2��<a(_XÊ¦ò‡­<b,¯XË6V2Ž›üe.ëØË<s™ÅÌd4?™ÌGVó�Ýlæ6³9Êsžr�«|ç+ç9Ë{ÞrŸ»ìä7ÿyÌ�Ž3�
çD:Í‹^3¢-h;
__CPAN_FILE__ src/widget/templates/images/TreeV3/open.gif
GIF89aÂÿÿÿÿÿŸŸŸÿÿÿÿÏŸÏÏ`ÿÿÿ!ù,PxºÜþ�‰9ã$gaqøAQža—y¾ÁªŒ4eÄìá½EP¬™ÎõéùpÁÜ�ç+ÏVñX¨®¢­ž¶ú{*u5Úà{›Ïg‹zÍŽ$;
__CPAN_FILE__ src/widget/templates/images/TreeV3/expand_plus.gif
GIF89aÆCy–ÁDDD999�œÅüüüúúúÿÿþâæìþþý��ÅóôöïñôîðóÊÓàþýýñóõºÆ×ùúúüüûçêïðòôÅÏÝÌÔáÍÕáíôþÖÜæìîòåèî÷÷øëîñö÷øæêïìïòÄÎÜèëïÛàèíïòãçíÄÍÜþþÿåéî}šÄ€œÅ�œÄùùùøùù÷øøÞãêÝâêÒÙäßäëõö÷éìðÔÛåýþÿûûûñòôÕÛå¿ÉÙôõ÷¾ÉÙÓÚäôõöëíñÚßèþþþÿÿÿÜáéËÔàêíñùùúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,…€‚ƒ„…†‡ˆ‰Š‹ˆŽ��‡;3)@,“=":0F?“'E615
/©†>D&±´…2$Ä
ËË‚A#%B
“!G	C¿„ 94-	7+“<.8(*“‘‘Œÿ
;
__CPAN_FILE__ src/widget/templates/images/TreeV3/i_half.gif
GIF89a€rrrÿÿÿ!ù,Œ€Ë¦
S„o®jÎ’kÿ�âH–æ‰¦;
__CPAN_FILE__ src/widget/templates/images/TreeV3/expand_loading.gif
GIF89aç€œ¿ó“·ì{ ×žÁõ¥Èû%g¸ŠªÚ�´é¡Ä÷–¹îv›Ó‰©Ù„¤Õçî÷´Ðù±Í÷îóú�®Ü£ÆùÄÔì�³è�°àøúý�°äŸÁóñõû•²ÝŒ¬ÜŠ­âµÑúûüþ|¡×…§Û¸Ìé’µè§Éüƒ¥×Š­á‚¥ØùûýˆªÛ®Îûõøüš½ï’³æ�¯âèïø�¯Þˆ©Ùþþÿ›¶ß˜´ÞÉØî±Íõ¨Êû€ Ï‚ Î†¨Ù�¿ð×âòˆ«á…§ØŒ­ÞŠ«ÜŠ«Ý�Ê‘¯Ü®Ë÷¤Æùˆ©ÛÈ×î�¾î¨Çô‹¬Ý´Éçˆ©ÚÜåô•·éŸÂô�£Ö~¡Ö�²ä‡©Ýêðø°Îø¬Ãå»Îêkkk¯Åæ›¾îœ·à„¦Ø¯Ìõ¯Íú–¸é} Õ£Åø}œÊ÷ùüÇÖí�¬Û™»íÅÕíááá°ÌõwœÓÁÒëžÀòëñùÒÞñ–·çô÷û¤Åöˆ¬áßçõÂÂÂœ¾ñãëö”±Ý�¼é˜»îŽ¯à‰«Ü·Ëè�±çˆ¬â™¼ñ�¦Ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,þ	(PEƒ&ô`FÃ�<I„X± �àMÀŒ(0‚ˆ
u*jc Œ�)¨$°
…L`¬éÒ¡C�#$èteÁv²Pq@ô 7’"XáÄÀ	,†<˜
§ 
²fe1aàh¸ Áà Ò¦Å£¥ 
?tüÈõ³Ð†¹s—Pt¤@‚¿	Dàd�a"
èa(Š�!·8gà™Š¼#… \¸q%ƒÓ9.Pˆ0pO	>°as�Â!6ì!B0À£�ïßÀûÄ1� ’+_þD×„!L|@½uL`9Æ”4
Â+ø²EM‘€ (!Câ	‰U\ 'è¡�œbæë¯;
__CPAN_FILE__ src/widget/templates/images/TreeV3/minus.gif
GIF89aÆy–Á�œÅ999üüüóôö��Åïñôéìðõö÷îðóþþýúúúâæìÿÿþßäëÔÛåñòôûûûýþÿÒÙäùùùDDD�œÄ€œÅøùùÝâêÞãêòóõ÷øøÜáéÿÿÿþþþËÔàùùúêíñÚßèôõ÷äèí¿ÉÙÕÛå¾ÉÙëíñôõöÓÚäÅÏÝðòôÍÕáìîòÖÜæíôþñóõþýýÊÓàüüûçêïºÆ×ùúúåèî÷÷øÄÍÜãçííïòþþÿÌÔá}šÄåéîæêïö÷øëîñìïòÛàèèëïÄÎÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,€€‚ƒ„…†‡ˆ‰Š‹‰Ž��‡7&,.0A)“(H?'9"*“; %	©†4+<°:´…FÄ“#G=C8Êµ6E2!
¿„B/5

“D-$3
>1@“‘‘Œûüý„�;
__CPAN_DIR__ src/widget/templates/Editor2
__CPAN_FILE__ src/widget/templates/Editor2/EditorToolbar_FontSize.html
<div class="SC_Panel" style="width: 150px; height: 150px;">
<table width="100%" cellspacing="0" cellpadding="0" style="table-layout: fixed;">
<tbody>
<tr>
<td nowrap="">
	<div class="SC_Item" dropDownItemName="1">
	<font size="1">xx-small</font>
	</div>
	<div class="SC_Item" dropDownItemName="2">
	<font size="2">x-small</font>
	</div>
	<div class="SC_Item" dropDownItemName="3">
	<font size="3">small</font>
	</div>
	<div class="SC_Item" dropDownItemName="4">
	<font size="4">medium</font>
	</div>
	<div class="SC_Item" dropDownItemName="5">
	<font size="5">large</font>
	</div>
	<div class="SC_Item" dropDownItemName="6">
	<font size="6">x-large</font>
	</div>
	<div class="SC_Item" dropDownItemName="7">
	<font size="7">xx-large</font>
	</div>
</td>
</tr>
</tbody>
</table>
</div>
__CPAN_FILE__ src/widget/templates/Editor2/showtableborder_gecko.css
/* For tables with the "border" attribute set to "0" */
table[border="0"], 
table[border="0"] > tr > td, table[border="0"] > tr > th, 
table[border="0"] > tbody > tr > td, table[border="0"] > tbody > tr > th, 
table[border="0"] > thead > tr > td, table[border="0"] > thead > tr > th, 
table[border="0"] > tfoot > tr > td, table[border="0"] > tfoot > tr > th
{
	border: #d3d3d3 1px dotted ;
}

/* For tables with no "border" attribute set */
table:not([border]), 
table:not([border]) > tr > td, table:not([border]) > tr > th,
table:not([border]) > tbody > tr > td, table:not([border]) > tbody > tr > th,
table:not([border]) > thead > tr > td, table:not([border]) > thead > tr > th,
table:not([border]) > tfoot > tr > td, table:not([border]) > tfoot > tr > th
{
	border: #d3d3d3 1px dotted ;
}
__CPAN_FILE__ src/widget/templates/Editor2/EditorDialog.html
<div id="${this.widgetId}" dojoAttachEvent="onMouseDown" class="dojoFloatingPane">
	<div dojoAttachPoint="titleBar" class="dojoFloatingPaneTitleBar"  style="display:none">
	  	<img dojoAttachPoint="titleBarIcon"  class="dojoFloatingPaneTitleBarIcon">
		<div dojoAttachPoint="closeAction" dojoAttachEvent="onClick:hide"
   	  		class="dojoFloatingPaneCloseIcon"></div>
		<div dojoAttachPoint="restoreAction" dojoAttachEvent="onClick:restoreWindow"
   	  		class="dojoFloatingPaneRestoreIcon"></div>
		<div dojoAttachPoint="maximizeAction" dojoAttachEvent="onClick:maximizeWindow"
   	  		class="dojoFloatingPaneMaximizeIcon"></div>
		<div dojoAttachPoint="minimizeAction" dojoAttachEvent="onClick:minimizeWindow"
   	  		class="dojoFloatingPaneMinimizeIcon"></div>
	  	<div dojoAttachPoint="titleBarText" class="dojoFloatingPaneTitleText">${this.title}</div>
	</div>

	<div id="${this.widgetId}_container" dojoAttachPoint="containerNode" class="dojoFloatingPaneClient"></div>

	<div dojoAttachPoint="resizeBar" class="dojoFloatingPaneResizebar" style="display:none"></div>
</div>
__CPAN_FILE__ src/widget/templates/Editor2/EditorToolbar_FontName.html
<div class="SC_Panel" style="width: 150px; height: 150px;">
	<div class="SC_Item" dropDownItemName="Arial">
		<font face="Arial" style="font-size: 12px;">Arial</font>
	</div>
	<div class="SC_Item" dropDownItemName="Comic Sans MS">
		<font face="Comic Sans MS" style="font-size: 12px;">Comic Sans MS</font>
	</div>
	<div class="SC_Item" dropDownItemName="Courier New">
		<font face="Courier New" style="font-size: 12px;">Courier New</font>
	</div>
	<div class="SC_Item" dropDownItemName="Tahoma">
		<font face="Tahoma" style="font-size: 12px;">Tahoma</font>
	</div>
	<div class="SC_Item" dropDownItemName="Times New Roman">
		<font face="Times New Roman" style="font-size: 12px;">Times New Roman</font>
	</div>
	<div class="SC_Item" dropDownItemName="Verdana">
		<font face="Verdana" style="font-size: 12px;">Verdana</font>
	</div>
</div>
__CPAN_FILE__ src/widget/templates/Editor2/showtableborder_ie.css
table.dojoShowIETableBorders, table.dojoShowIETableBorders td, table.dojoShowIETableBorders th
{
	border: #d3d3d3 1px solid;
}
__CPAN_FILE__ src/widget/templates/Editor2/EditorToolbar_FormatBlock.html
<div class="SC_Panel" style="width: 190px; height: 150px;">
	<div class="SC_Item" dropDownItemName="p">
		<div class="BaseFont">
			<p>Normal</p>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="div">
		<div class="BaseFont">
			<div>Normal (DIV)</div>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="pre">
		<div class="BaseFont">
			<pre>Formatted</pre>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="address">
		<div class="BaseFont">
			<address>Address</address>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="h1">
		<div class="BaseFont">
			<h1>Heading 1</h1>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="h2">
		<div class="BaseFont">
			<h2>Heading 2</h2>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="h3">
		<div class="BaseFont">
			<h3>Heading 3</h3>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="h4">
		<div class="BaseFont">
			<h4>Heading 4</h4>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="h5">
		<div class="BaseFont">
			<h5>Heading 5</h5>
		</div>
	</div>
	<div class="SC_Item" dropDownItemName="h6">
		<div class="BaseFont">
			<h6>Heading 6</h6>
		</div>
	</div>
</div>
__CPAN_DIR__ src/widget/templates/Editor2/Dialog
__CPAN_FILE__ src/widget/templates/Editor2/Dialog/inserttable.html
<div>
<table cellSpacing="1" cellPadding="1" width="100%" border="0">
	<tr>
		<td valign="top">
			<table cellSpacing="0" cellPadding="0" border="0">
				<tr>

					<td><span>Rows</span>:</td>
					<td>&nbsp;<input dojoAttachPoint="table_rows" type="text" maxLength="3" size="2" value="3"></td>
				</tr>
				<tr>
					<td><span>Columns</span>:</td>
					<td>&nbsp;<input dojoAttachPoint="table_cols" type="text" maxLength="2" size="2" value="2"></td>
				</tr>

				<tr>
					<td>&nbsp;</td>
					<td>&nbsp;</td>
				</tr>
				<tr>
					<td><span>Border size</span>:</td>
					<td>&nbsp;<INPUT dojoAttachPoint="table_border" type="text" maxLength="2" size="2" value="1"></td>
				</tr>

				<tr>
					<td><span>Alignment</span>:</td>
					<td>&nbsp;<select dojoAttachPoint="table_align">
							<option value="" selected>&lt;Not set&gt;</option>
							<option value="left">Left</option>
							<option value="center">Center</option>
							<option value="right">Right</option>
						</select></td>
				</tr>
			</table>
		</td>
		<td>&nbsp;&nbsp;&nbsp;</td>
		<td align="right" valign="top">
			<table cellSpacing="0" cellPadding="0" border="0">
				<tr>
					<td><span>Width</span>:</td>
					<td>&nbsp;<input dojoAttachPoint="table_width" type="text" maxLength="4" size="3"></td>
					<td>&nbsp;<select dojoAttachPoint="table_widthtype">
							<option value="percent" selected>percent</option>
							<option value="pixels">pixels</option>
						</select></td>

				</tr>
				<tr>
					<td><span>Height</span>:</td>
					<td>&nbsp;<INPUT dojoAttachPoint="table_height" type="text" maxLength="4" size="3"></td>
					<td>&nbsp;<span>pixels</span></td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td>&nbsp;</td>
					<td>&nbsp;</td>
				</tr>
				<tr>
					<td nowrap><span>Cell spacing</span>:</td>
					<td>&nbsp;<input dojoAttachPoint="table_cellspacing" type="text" maxLength="2" size="2" value="1"></td>
					<td>&nbsp;</td>

				</tr>
				<tr>
					<td nowrap><span>Cell padding</span>:</td>
					<td>&nbsp;<input dojoAttachPoint="table_cellpadding" type="text" maxLength="2" size="2" value="1"></td>
					<td>&nbsp;</td>
				</tr>
			</table>
		</td>
	</tr>
</table>
<table cellSpacing="0" cellPadding="0" width="100%" border="0">
	<tr>
		<td nowrap><span>Caption</span>:</td>
		<td>&nbsp;</td>
		<td width="100%" nowrap>&nbsp;
			<input dojoAttachPoint="table_caption" type="text" style="WIDTH: 90%"></td>
	</tr>
	<tr>
		<td nowrap><span>Summary</span>:</td>
		<td>&nbsp;</td>
		<td width="100%" nowrap>&nbsp;
			<input dojoAttachPoint="table_summery" type="text" style="WIDTH: 90%"></td>
	</tr>
</table>
<table><tr>
<td><button dojoType='Button' dojoAttachEvent='onClick:ok'>Ok</button></td>
<td><button dojoType='Button' dojoAttachEvent='onClick:cancel'>Cancel</button></td>
</tr></table>
</div>
__CPAN_FILE__ src/widget/templates/Editor2/Dialog/replace.html
<table style="white-space: nowrap;">
<tr><td>Find: </td><td> <input type="text" dojoAttachPoint="replace_text" /></td></tr>
<tr><td>Replace with: </td><td> <input type="text" dojoAttachPoint="replace_text" /></td></tr>
<tr><td colspan='2'><table><tr><td><input type="checkbox" dojoType="CheckBox" dojoAttachPoint="replace_option_casesens" id="dojo_replace_option_casesens" />
		<label for="dojo_replace_option_casesens">Case Sensitive</label></td>
			<td><input type="checkbox" dojoType="CheckBox" dojoAttachPoint="replace_option_backwards" id="dojo_replace_option_backwards" />
		<label for="dojo_replace_option_backwards">Search Backwards</label></td></tr></table></td></tr>
<tr><td colspan=2">
	<table><tr>
	<td><button dojoType='Button' dojoAttachEvent='onClick:replace'>Replace</button></td>
	<td><button dojoType='Button' dojoAttachEvent='onClick:replaceAll'>Replace All</button></td>
	<td><button dojoType='Button' dojoAttachEvent='onClick:cancel'>Close</button></td>
	</tr></table>
	</td></tr>
</table>

__CPAN_FILE__ src/widget/templates/Editor2/Dialog/find.html
<table style="white-space: nowrap;">
<tr><td colspan='2'>Find: <input type="text" dojoAttachPoint="find_text" /></td></tr>
<tr><td><input type="checkbox" dojoType="CheckBox" dojoAttachPoint="find_option_casesens" />
		<label for="find_option_casesens">Case Sensitive</label></td>
			<td><input type="checkbox" dojoType="CheckBox" dojoAttachPoint="find_option_backwards" />
		<label for="find_option_backwards">Search Backwards</label></td></tr>
<tr><td style="display: none;"><input type="checkbox" dojoType="CheckBox" dojoAttachPoint="find_option_wholeword" />
		<label for="find_option_wholeword">Whole Word</label></td>
<tr><td colspan="1">
	<table><tr>
	<td><button dojoType='Button' dojoAttachEvent='onClick:find'>Find</button></td>
	<td><button dojoType='Button' dojoAttachEvent='onClick:cancel'>Close</button></td>
	</tr></table>
	</td></tr>
</table>
__CPAN_FILE__ src/widget/templates/Editor2/Dialog/createlink.html
<table>
<tr><td>URL</td><td> <input type="text" dojoAttachPoint="link_href" name="dojo_createLink_href"/></td></tr>
<tr><td>Target </td><td><select dojoAttachPoint="link_target">
	<option value="">Self</option>
	<option value="_blank">New Window</option>
	<option value="_top">Top Window</option>
	</select></td></tr>
<tr><td>Class </td><td><input type="text" dojoAttachPoint="link_class" /></td></tr>
<tr><td colspan="2">
	<table><tr>
	<td><button dojoType='Button' dojoAttachEvent='onClick:ok'>OK</button></td>
	<td><button dojoType='Button' dojoAttachEvent='onClick:cancel'>Cancel</button></td>
	</tr></table>
	</td></tr>
</table>
__CPAN_FILE__ src/widget/templates/Editor2/Dialog/insertimage.html
<table cellspacing="1" cellpadding="1" border="0" width="100%" height="100%">
	<tr>
		<td>
			<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tr>
					<td width="100%">
						<span>URL</span>
					</td>
					<td style="display: none" nowrap="nowrap" rowspan="2">
						<!--input id="btnBrowse" onclick="BrowseServer();" type="button" value="Browse Server"/-->
					</td>
				</tr>
				<tr>
					<td valign="top">
						<input dojoAttachPoint="image_src" style="width: 100%" type="text" />
					</td>
				</tr>
			</table>
		</td>
	</tr>
	<tr>
		<td>
			<span>Alternative Text</span><br />
			<input dojoAttachPoint="image_alt" style="width: 100%" type="text" /><br />
		</td>
	</tr>
	<tr>
		<td valign="top">
			<table><tr><td>
						<table cellspacing="0" cellpadding="0" border="0">
							<tr>
								<td nowrap="nowrap">
									<span>Width</span>&nbsp;</td>
								<td>
									<input type="text" size="3" dojoAttachPoint="image_width" /></td>

								<td rowspan="2">
									<!--div id="btnLockSizes" class="BtnLocked" onmouseover="this.className = (bLockRatio ? 'BtnLocked' : 'BtnUnlocked' ) + ' BtnOver';"
										onmouseout="this.className = (bLockRatio ? 'BtnLocked' : 'BtnUnlocked' );" title="Lock Sizes"
										onclick="SwitchLock(this);">
									</div-->
								</td>
								<td rowspan="2">
									<!--div id="btnResetSize" class="BtnReset" onmouseover="this.className='BtnReset BtnOver';"
										onmouseout="this.className='BtnReset';" title="Reset Size" onclick="ResetSizes();">
									</div-->
								</td>
							</tr>

							<tr>
								<td nowrap="nowrap">
									<span>Height</span>&nbsp;</td>
								<td>
									<input type="text" size="3" dojoAttachPoint="image_height" /></td>
							</tr>
						</table>
					</td><td>

						<table cellspacing="0" cellpadding="0" border="0">
							<tr>

								<td nowrap="nowrap">
									<span >HSpace</span>&nbsp;</td>
								<td>
									<input type="text" size="2" dojoAttachPoint="image_hspace"/></td>
							</tr>
							<tr>
								<td nowrap="nowrap">
									<span >VSpace</span>&nbsp;</td>

								<td>
									<input type="text" size="2" dojoAttachPoint="image_vspace" /></td>
							</tr>
						</table>
					</td></tr>
					<tr><td colspan="2">
						<table cellspacing="0" cellpadding="0" border="0">
							<tr>
								<td nowrap="nowrap">
									<span>Border</span>&nbsp;</td>
								<td>
									<input type="text" size="2" value="" dojoAttachPoint="image_border" /></td>
								<td>&nbsp;&nbsp;&nbsp;</td>
								<td nowrap="nowrap">
									<span >Align</span>&nbsp;</td>
								<td>
									<select dojoAttachPoint="image_align">

										<option value="" selected="selected"></option>
										<option value="left">Left</option>
										<option value="absBottom">Abs Bottom</option>
										<option value="absMiddle">Abs Middle</option>
										<option value="baseline">Baseline</option>
										<option value="bottom">Bottom</option>

										<option value="middle">Middle</option>
										<option value="right">Right</option>
										<option value="textTop">Text Top</option>
										<option value="top">Top</option>
									</select>
								</td>
							</tr>
						</table>
					</td>
				</tr></table>
		</td>
	</tr>
	<tr><td>
		<table><tr>
		<td><button dojoType='Button' dojoAttachEvent='onClick:ok'>OK</button></td>
		<td><button dojoType='Button' dojoAttachEvent='onClick:cancel'>Cancel</button></td>
		</tr></table>
	</td></tr>
</table>
__CPAN_DIR__ src/widget/templates/buttons
__CPAN_FILE__ src/widget/templates/buttons/paste.gif
GIF89aÄüüüÊÃƒæææòòòÜÜÜÌÅ…¯¨h·°pÃ¼}«¤d»´t¿¸y³¬l¨¡b÷÷÷ìììáááïí%ÇÀ€TLIAn¾ÿÿÿ!ù,nà%Ždiž(*ER*Rð±0eRE!Ïln“”€PB$
¿eÂl:'ÉbZ©Z«ÑeÁ­X¾àJ–¢(Wè´¸D9¸+Žk|Ì¨WøühèWW€c	„‡ˆ{J
ŒW�c5•–Š&WW.œ!;
__CPAN_FILE__ src/widget/templates/buttons/justifyfull.gif
GIF89aÕ'2–16š5:ž9D¨CI­H-‘,?£>B¦AY¼XF©EWºVcÇbbÅaG«F8›7.’-5™4jÍiT·SmÐl1•09�8fÉeA¤@U¹TRµQ>¡=_Â^0”//“.< ;M°LP³O]Á\4˜3N²MK¯JZ¾Y,�+!ù',CÀ“pH,�È¤r‰œD,ŒB2"‚€Éíž›DJ\<§`òº“ŠÌ§qÐT ”‡iß~û‰VXZl|‡ˆnA;
__CPAN_FILE__ src/widget/templates/buttons/bg-fade.png
‰PNG


IHDR
d0®6ÀgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<CIDATxÚb<sænÀÄ€°022MÝ”>tý=�5|Ð>RíÍþ£ºGuß
zÔcƒÎi£†:Ã	HGÃ&�(x}IEND®B`‚
__CPAN_FILE__ src/widget/templates/buttons/inserthorizontalrule.gif
GIF89a³I­HN²MY¼X:ž9jÍi]Á\6š5?£>T·SmÐl2–1fÉeD¨CbÅaççç!ù,"ðÉI«½8ëÍ»ÿ –KSH0Ç`(”#Ï4Þx®ï¼;
__CPAN_FILE__ src/widget/templates/buttons/createlink.gif
GIF89a÷´øùúðñô‹‹‹óôöccc666555—È˜[[[ßßß˜˜˜ÔÚìœÎžJJJ€€€]]]òóö÷øùGGGîîîAAAèèè®ºÝ—Ìœö÷ùq™ÇÞÞÞæçç—Å˜Þäñþþþm§o444¹Éëƒ¹…ÅÅÅÏÕèºÌîÌÙîkmk„…‡¸ÀÚŽÂŒ¼ÊÐÙÞë¨µÚllnŠ¼‡eee¯ºÚzzzdt¡…¶…“¶òÙàðblcššš€°�ˆ¶‰fv¡fik---£ÄçŒŒŒÀÁÀbbb™Ä›nqo¤·Ï�¸Õ™¿ÊHHHt¢…m¡ox«z‡°íäçí|§ív£ww¦zdƒºëëë•ªÜ§ÂÝ�‘–RSS…º‡NNN›ÁÉW�\•¼·Ößà§Ó®EEEZZZÈÔØööùïðókokííí„´†¼ÅÖáçó¨Ö°îñóÓÔÖ¹Ãß°×»‡‡‡ÌÌË777`bdùúûjŽ¬³³³f”—ÌÜØììì‰‰‰�¸’~˜Í—Ð™o¡ÃyŸ˜‰À‹y¯vq©t   «¬¬šºëiim‰­ð���ÅÖñ…ˆ‰°¼ß°½ÞìîòÖÖÖ“““·ÎññññËÑãfw¦{¨·×ØÙm•´œÕŸ‹Œ�ÎÜìÝáë¦´Ü–ÔMMMnqn\\\DDD¬¹ÞÂÊâåêö¬Î³}}}ÆÆÆPYP†”¾�±Ý”””�¼Ž­€x¨‰ÜÜÝ‚‚‚ëíòååå„„„ýýþÿÿÿ!ù´,ÿi	H° ÁY"Xaƒ´f€ÕEL‹3^(Z`VA	Nî¸Qƒ�¢©öCp#^ø08@‚Ô£*v¤Dò(€¦–fzXeH«(tP8ÀÄ(°b¢å+=~$
@Tš!xì@r£É¤%Jj�áÚG&@g¸2ô¤Ï(=Öp½€�Š2žRø¨´!Qh$ 5`Ó+‚(Lé àTHJÈ"àˆ€PTTá±ðÌ§,?’LhPJ�ˆ8)ˆ%çJ3¼RhP�3,"àªQ @(` ‚JÄ$Ž)!4„pÈ�€NyrxJDl(!ˆcàË¥ÅãËŸ/0 ;
__CPAN_FILE__ src/widget/templates/buttons/removeformat.gif
GIF89a‘ÿ±±ÐmmÿÌÌÿÿÿ!ù,6œ�©Ëí¢|AX\ ƒÌçEáè}ß"’]"m
+bª
ñ!õµ�ûèB—‹)ä;>–Ì¦£;
__CPAN_FILE__ src/widget/templates/buttons/undo.gif
GIF89aæBPìQìÍÚöOÙöùý[«ìãêúðôüPìýþÿ"UìœµîiŽý&Wî$VíQ›è²ÅïPyëPzåÅÔôEŠäŠ¨é|šâõ÷ýßèùÏÚø¼Îñ2hãz›ìô÷ý ¶êŠÜô:tÜ;içOí!TìÆÔó°ÅðÌÚölŽúöøþ¹ËòµÆíRƒàöøý„¤éèîûûüþs˜å:gïÚãøD‚á0`ïâêúTŸéiÀñT|× SìzÁíOì‚Îñ'[èOìïóüÐÝöLîÿÿÿ!ùB,z€B‚ƒ„…†‡ˆ‰Šƒ	‚�‹‚'41#0Š@
!
">†A‚9+=8-,…A¡3 .B²:6;%ƒ*…<?„)É„7„�ÕAááƒ2“‚/$(èB5&Åîîö÷ö�;
__CPAN_FILE__ src/widget/templates/buttons/outdent.gif
GIF89a‘1zè'Œ&!ù,%”�©Ëíÿ‚œ4¬Š/¦	@xÇfáé‘ h¨à§�“&Ó.ŒçM;
__CPAN_FILE__ src/widget/templates/buttons/backcolor.gif
GIF89aæb¼¼½ãããÐÐÐÏÐÐóóôóôó¬«¬ƒ¤êÿ{ããäïóéº}µ—¤ûWÌÉæ‡ÚDüöÎ–½~°]õï÷óÿÖEûýàÿÕ¾ÿ=qÛÐÏÐ¸Ÿ†�ÙÇ¶íÍÅÊÿOÅ¸ÿúåøýµèôôóTÿãÿ×•ÿ”˜ÿé´¾¶çÐ—ÁÍûvÆÍ´Íáýÿÿl°¶È¨.Ô€ÿƒ««¬õùú÷úùÿÚþö²{¯¬¬¬Å“»žâ•�Íu�³]ÉúïöÎ‰ÖôîöïÐã´Îf×õ½•Àíï÷·Ûö««­…®"?Á½j´\÷™ÿà§õ¨¨òÖ·ÿ¨ÿòæúÿÆŠ­ÉÖQ|öíë«¬­ÿŸÿóôôÉ™ÊùÚù÷ùp¨+”éª­“ÿZÍè–¦ÿ@@@ÿÿÿÿÿÿ!ùb,¦€b‚ƒ„…†‡ˆ‰Š…a>B7D,@a‡aX?LNM;E–…Z9VK&]'_R3†(S.+! P<ƒ`¿À¿ƒFC^*¾aÉÊ`ƒ-
¾W"Ì‚6YAI¾àà	Ùb\Q¾ë`1)¾ùú`O#%5$zÐðUÅŽ€Ñ�†%
F‰	É–/¨H\Ä±£ÇA�;
__CPAN_FILE__ src/widget/templates/buttons/wikiword.gif
GIF89aÕ2<\ÇZ…ßêïú›«âìïúc|ÒMnÐª¸ç´ÆïMsÕU~Ûèëø?_ÉÀÊí~”Û^xÑÉÓñúûþ¯¼èeÓJhË³Ãì¬¼èˆ�Þ_{ÓGeËC`ÉVqÏXuÑIhÍýýþ|’ÛMpÒWrÏA_ÈÍ×òCaÉ@bËFeÊ>^ÈRoÎ{‘Ú—«ãáæöÕÝôKkÍGhÍ¶ÄìsŠ×9YÆÿÿÿ!ù2,Ÿ@™pH,�È¤RAÅb‡âá‰Š)•Ñ 8U(Å‰Š+ÂXªIÑñ�dŠÈÇ!}¼4„!AózD‰$!
C
!$F""G0‘0G).&	¦.)G%	0
0	%G+'
0
'+G ÀÊH-2Ò-IÔÚÜFOáâã12A;
__CPAN_FILE__ src/widget/templates/buttons/superscript.gif
GIF89a‘QìKvø2–1ÿÿÿ!ù,œ�©Ëí^ŠQž`ØLãY^˜‘âx‚_Æ¶î·;
__CPAN_FILE__ src/widget/templates/buttons/subscript.gif
GIF89a‘QìKvø2–1ÿÿÿ!ù,œ�©Ëí£œNc£Í’ëýau”iNÁ	¤ä{;
__CPAN_FILE__ src/widget/templates/buttons/space.gif
GIF89a€!ù,D;
__CPAN_FILE__ src/widget/templates/buttons/indent.gif
GIF89a‘1zè'Œ&!ù,$”�©Ëíÿ‚œ4¬Š/¦
ÀxÂfáé‘�¨‚_BNZ<·ï�7;
__CPAN_FILE__ src/widget/templates/buttons/bold.gif
GIF89aÕ<ržëv’ÝÄÖõ±ÂíQqÑêîú´ÄíÃÐñ¡µéRqÑMlÎ|•ÜÒßöÞçö‹ Þx“Ý–¶î”¯èBbË”ªätŽÙk’âÿÿÿ¨ºè‰žÞÅÑñÈØõQyØ‰¦åVrÏ?_É²ÊóQqÐ\xÑ@`È§í�£ßƒ�ád†Úl…ÕIjÍ ²æ|¥ìÍ×ðEiÏ?_È\zÓ�²îtŸëMmÎUtÑµÄíHgË£¶é~Ÿäb€ÖsŒØ ½ði˜ê9YÆÿÿÿ!ù<,w@žpH,�È¤RHÚ9Ÿ»N
¹X­Fã49î> ƒx–Â­hÞÜ®èÀ¬�»×[h	]dÞQ…ÀO´81^„…*
‚p:Ž7("‹sB
%–E‹,¥6.‹:®¯0&	GPO•K»¼CA;
__CPAN_FILE__ src/widget/templates/buttons/underline.gif
GIF89aÕ+EiÏ¿ÓôZ„ßÀÓôi˜êHmÑ<]È?_ÈDhÏ™¸ðFjÐµËóq�ë±Âí`×HgÌ|¥ìW€Ü§ÂñŠ®îw“ÞAcÌq�ÜGgÌGhÎ¡µèInÒh…ØSqÐMoÐQxØ>`Êf”èMpÒMsÕCfÍLpÓGlÑ=]È?aË]{ÔKkÎ9YÆ!ù+,uÀ•pH,�È¤r¥j6‹Î§P¨Š‡�V5t.ÅÇÂ	•pŠ	×¨J Š©Ä:Ù;“9Q±Cz]E$‚S…D‰+"C#G' %

+
H&©JM¦K·]QºsA;
__CPAN_FILE__ src/widget/templates/buttons/redo.gif
GIF89aæBPìQìÍÚöOÙöùý[«ìãêúðôüPìýþÿ"UìœµîiŽý&Wî$VíQ›è²ÅïPyëPzåÅÔôEŠäŠ¨é|šâõ÷ýßèùÏÚø¼Îñ2hãz›ìô÷ý ¶êŠÜô:tÜ;içOí!TìÆÔó°ÅðÌÚölŽúöøþ¹ËòµÆíRƒàöøý„¤éèîûûüþs˜å:gïÚãøD‚á0`ïâêúTŸéiÀñT|× SìzÁíOì‚Îñ'[èOìïóüÐÝöLîÿÿÿ!ùB,|€B‚ƒ„…†‡ˆ‰Š„Ž‚	‰0#14'‹>"
!
@ˆ,-8=+9‚A…B. 3�°„*ƒ%;6:½ƒ)„?<…	„7Ô…2ƒAååß„($/‹„&5î„�ó÷øù†�;
__CPAN_FILE__ src/widget/templates/buttons/cut.gif
GIF89a¢êÀÀƒ…‚êˆˆ„…ƒÈÿÿÿ!ù,5XºÜþ0ª1¤«–��uD(LØC,!U6¡
jÌ€áYØt§œ8èæ;
;À äåk:	;
__CPAN_FILE__ src/widget/templates/buttons/justifyright.gif
GIF89aÄ.’-2•1>¢=5™4:�9C§BH¬GN±MS¶RX»WüüüfÉeiÍh„Íƒ]À\aÅ`,�+çççÿÿÿ!ù,; $Ždižhª®gÃ,�“ ‡QÄ£ýÀ`�EátˆR%Qµ[n§¬BHÍlä¹JZ­(í�K.—B;
__CPAN_FILE__ src/widget/templates/buttons/inserttable.gif
GIF89aÄ¤¡œ¥¢�¦£žÃÁÀº··ËÉÈÆÄÃª¤¨½º¹ÎÓÍ¨¥ ª¨£ª§£æææóóóêêêøøøÀ¾½ÉÇÆÍÒÌ?£>TLIÿÿÿ!ù,fà%Ždižhª^ŒÌ­°À$VTïÿ¾ŠîÂ)Â�ei)0�Ì$QB­Z«Ò
d1p½Ü¬cì�ÍäJbi»ßîìcþ@Ðíôlcß ðý|R„…†…C‹Œ�ŽC+‘’“"!;
__CPAN_FILE__ src/widget/templates/buttons/italic.gif
GIF89aÕ3›«â<\ÇÀÊísŠ×9YÆ´Æïêïúª¸çìïúU~Û¯¼è@bËáæöCaÉýýþ{‘ÚeÓXuÑÍ×òž®ä|’Û^xÑMsÕc|ÒÕÝôA_ÈGhÍèëø?_ÉVqÏ>^ÈMpÒ~”Û³Ãì¶ÄìRoÎZ…ßC`É¬¼èWrÏ—«ãJhËˆ�ÞGeËúûþMnÐIhÍ_{ÓKkÍÉÓñFeÊÿÿÿ!ù3,RÀ™pH,�È¤òx F¬¥ 	¥¤ÂÁÎV1
‹(‰*¬àdjl°€‹*ãD^¯¬¥y�9
j.	p$X0^^RA;
__CPAN_FILE__ src/widget/templates/buttons/insertorderedlist.gif
GIF89a‘KvøQì'Œ&ÿÿÿ!ù,&œ�©Ë½Âƒj�³¨’zj}Oè‡–qäÇ+d¾�…bJÜr¾;
__CPAN_FILE__ src/widget/templates/buttons/sep.gif
GIF89a€‚‚‚ÿÿÿ!ù,L`†¹š÷d±ÒëðÌ|{¹;
__CPAN_FILE__ src/widget/templates/buttons/right_to_left.gif
GIF89a³
G«FD¨C@¤?=¡<I­H5™4.’-1•08œ7Qì!ù
,;PÉI«½8ëÍ»$ §#@RÉ(A‹¦– ô”Ü× ºtã„Bø‚U

dX9(œ#Å  Š®Ø,6;
__CPAN_FILE__ src/widget/templates/buttons/copy.gif
GIF89aÄýýýüüüðððëëëÁÁÁõõõÜÜÜÏÏÏ³³³ííí÷÷÷ÚÚÚ®®®ÄÄÄßßß§§§ÑÑÑÿÿÿAn¾!ù,Oà$Ždižè(­ìšNR$ÏÒÏr�Æm £·H«eâ­p¹" 0ÒŠ–�å+§"ñSµ¦«EWÉt@ã’$Êb¤I’+ñ@¼½Ãûkÿ
;
__CPAN_FILE__ src/widget/templates/buttons/list_bullet_outdent.gif
GIF89a¢G¦ðRè`†ï'Œ&ÿÿÿ!ù,(HºÜþ0J&‚˜,€ †ÿƒS]Xi>ã©qèzJzÎtl©[÷‚6Yÿ“;
__CPAN_FILE__ src/widget/templates/buttons/aggregate.gif
GIF89a¾÷ÿýä�£ÙËGhÌÑllQëÊ--«ºèÝÝÝ³Äíÿl@@@¸Îóöw’ÜêÿÖY„ß¯Ð®çççFªEt²]¶µµcíò•ÊE†ãjÍiN¥í	øÐË·ùÿÌÌúíìAn¾—­ämÊòöë÷�žØøùùÐHHºÅØZœì­ðÞþû…¥éÃÕô9YÆîíí¸Ÿ’ÈQüüü…ÍÉÂ‚ƒƒ‚”˜ÿêïúo«1|¨ë,�+V¹U˜Ê˜Lwõ‡·ˆÌ‘Ð«¹ÛõøýÓÓÔcedñññ·Ûö¹²rë¸»ÃÂÂèˆˆi˜ê111êêêÈÔØu¨zðôüoŽ³6fê?£>f†ÙçÁÁ«¤eK‚À†Õó|||ÚyyÌÙõ¥¢�[ª~¨ÒQqÑðñôöööå––ÍÓæÔÜìøÝÛb~ÔZ[Z$Wìóýs‹Øâáá˜¶ÙÌÌË¬¬¬¿ÊëðÑÑÆËÕñEüúLîƒÆ'‰Å‰:tÜÒÍn›š   Ê•¼ržë¶|²ûœÿÍÒÌ™™™ÔÞôQyÝìîõ©·©9�8

2–1^zÒ~»G µêMrÔ—¥ýk´5™4â¢¢‹‹‹tœËŠ³ÜLmÏ�²î>^È˜ÁÌœâ—¸ï›Ð�‘¤à¤Ãæ¨¥ ßåökŽüóôõM±Lev£XvÒ\À[âêúVrÏ7›6lnmSLI ¯ ÿ±±`†ïÈ1zè|’ßÿÊ#ŽÑŽwvoÉÇÆ½½¼A¥@ïí%åååOÙý÷÷Ø°-ª¤¨óóóÿ=Í´Í?Á½”éª€ÿƒWÌÉ­“ÿZÍèAaÊã´Î…®"¾žâ¨ÿ½•ÀúûþÁº{.ÔÍÅÊ]É¨¨ò³¬lïóé‹¯ËRoÎÐÐÐz›ì©ÁïûvÆããä©¨¥s˜åÖQ|¶çÐÏÚø÷÷ø ½ðûüþ×•ÿóôóÿl°U~Ú´±[*�)ÖŽŽÿÝÊäÊþº�‰®î.“.äçíáÍÍQ´PÔÙØ`”Ö’“”{¨·X‘™ÓÌ¦1m‡¿d†”¾G~'•¼·çëøbÆaW�\…‡ˆ'Œ&ÿÿÿÿÿÿ!ùÿ,¾ÿÿ	”!° Áƒ*\È°¡Ã‡#JœH±¢Å…þ2jÜ˜ñ¢@Ž ýyI²¤É“(Sª\É2¡-cÊDIp¦DS8sæüaòÅN\‚r!Ò¦Ñ£Crô¨T#Ò§P£J�JÕ «—0«jmYs«@S!Áò<è¡¬Ù²}: ¤D‰pÁŒx!QFW¯T›v<H`âÆ‚Kñ
±oCÃ3ÿÈúCØ#+W³6ž\·¢¿ÂîäÉsLWˆ¢/­Mz…¨CM½XÍúE Õczéa!·uî@È‘CÅšŽzt©œÐH6	‰ƒ³fÎžA¼œysçÏQÿ~Ô.�â†XÂcÿ¹–I¼øká÷DE•E££!£ü”½{Šö%z?ü]e©ÿŠÉ²Ø¥0¤Â6W\ÊG
ààƒ­€Ç„Rø�‘¤Bi¥¡ÆRqx�ˆI	J‚W¨�2ÑŒfÀAð­ ŸAwAä.<ðpÂ4³Š€HWÐ
*Yä}hÅ©ÖÚj°°Û?³qT[B/–X’Ã,P‚<M|A×Cv)DBmxq�œ™Ð�9îØã�A&…£Ž<ú¤�õ#è „ös‘yä™zX¨Wb…
jP)OTjé¥––âè?d`X¤†2ô� úè
�Hð„ ‹¨ÿsÃ¬7„©®ŠC;¸
+!�sk®»öúj¬µ
$®ªîÚj,Ç¢ŽG�~
ê Uh¤
AÊ-§]‹-BâJZJ1(àbè˜6d�á„›L4øâ;@„x¬âï¿«\˜áHid‚¦®ÔˆD)ÉA’¹ÂB›Ì/6		€€L4j©Õø7wX ‡ßü2C")@ÃMB+,°4#pˆn$\�)#ôìó°èdÐlg½p%B#X£I—¼í°&K,Ñ„=/£ÉÐlZQÖ$„Ä×`ƒ­2Ë.D²É(�ÝrÕ•jE®è¥‘+›zbB”bª÷š®ÿ×žEfôñ�
ù“Dˆ'®xâ½°øãŒä8ä�7NyåIÐ*Bùá÷waû-d·Enÿs.º¤ž:º1¸{Ð&v{ç}@t/§ä~Ê¾i.D®²o¼	ÌÊÄ#Å<3ÍP‚€:«¤Ì£-ý?,@ZB}ÈKv×{�ôaÆA�2EDdN5'„Â,7±ÌÝ _�"èÿU#(Àº@À� 
]0ÅÐ4r–³„_È‡ä°ƒ¨MâN«ƒ'8�#¤âƒFˆÈâ…¬ýcMÌñWØ\ a~õ»ŸAÚ÷¾øÁ0öKHé,7øð‡S€ÿÐ Ð­"¥ØÈ+4²D�ô­$pƒ¿èC’þôêw¿£âHJw:Öy±]ñü�‚ˆC^0®v
ÜéÎAÁb¯ø‚�à-àŽ0üg‘ä)£ƒ5¶p�-Pƒ�ÿX#§0;q”ÑðÁAü•³ƒDqŠ4Šˆ6ÉÉMD Æ$`	ÿù£ ¤AL�\0¢
$B
@pàB�²ñ‡Yhc.¬atÚ$"‘ŽxDÍ€@H*
òA»Œð Q`SÚ@„…„-a(E)�Nvò“¡åATÁ’š ,S˜‚qGLqSàzH)^AÏzÚ³žO	
‚�ÿT:äX²¢UBTµªv´ªR£@V²â,_-b"Ñ
èB»ó	Ä‹R¹ÛC4šr:¤ÉiÍâº‚ˆ‘šø
A€9\À;ŠLÈÚ¨»Ýí.Žÿ°h)ZÇ~
/Æ[ÅI²‚RJ„ÀúR²T¥&•!+¨D!RˆJ |¸Àpü#”ˆ$Œ
�€`xU ûìç‹2	€DAÁÞà˜¥à[Èë$‘H¨h•,¢I‚0"°,À¥@<ð‚.$¡J9Ú?¸P‚>€a	;ÀG%ÒaGìc	žàÂA>(Á™¨]HØD‚‡ ÁHH¡@äJ×nÿ¾5®s­ë8=z­‚«YÅrèSÿáŠÈCé|‡rñ`ƒæ¾óQñlH)~VŸU×gùìÜDÖ 
#¡\B.·8ƒ@n"â5H ÿa)ö2D»
�¯CB7ú6DÝ·@*RÚ”T bD@A˜€€¬1=ÈLÝ˜»ó® O`o¥eßù4�‚Ì„ŠÈˆâÃ ±ˆ?Œ¤6•©&~È
Ò…ƒ@!WA^Š&¤À’4H>‚aQ¬¡ Üõ.xÙú€ƒ¶Ä8à:[
h`0«Ð„lP	Hü°,È2Ø”å,+–JAØeÑ$Ë…\¡2 …š�ÐGðCÿÍc¨Â
âÁ.ówvH-ØÄ&F8	¯ˆ­APàd(ÿÃÈHnå’ãZè‚à÷Ñäìí?&G^Ä$n¨‡¦ëaƒG@ãZ¨Ãs2=ýjR­leR½êTçS[ÿ•¨Ä ‚‡i‘Zë�p„Eç)S�Ö;ìN¸Ê•­aÊÑ�Ž´¬K1„f3öIøï?| ƒ„	�Êh!Sš¾±�†°„)\áØÑfE6<T‹´âÝðŽ·¼ß��;ÄÞPµÁùb ’TÈÀ`ã‚,@#@H0DPˆÐ@4\­òÌ„(ÀÏ8“ÿÁ‹h 0;‚@òˆÿ0ë*“ÀrvÀ’$`y¾ì�H£�õ7X@æ¬v`Áá1 ¶2<âÁ(D¡Î©Å4pBj6	@:Òñ�w3ã/H×A¾[_�nþÈB
j`ˆ¶»À5¸=FÍ©rã
xÏ»ÞóžÝÏMÄŸ(„(PZ^ i(´~%Ñ‰2žâ2È³"zø‰Ö½?‚øGæ"_Îù}£vçG
‚_ƒô–ÙÎæÆYT/mL9îN@°m„Ì´¦6å@¸’ùÍ“»§Â³ºY�G—Dä%7¹R¾·ù)vˆ„p�´Û —ñw|€€iJ…ø„ÿ!†|^ð×¤4ÖÏ~8À½ÈE ��óQ�0%V9‹Yœ�Mý7V`
³@sg¡Kfq’5=p	ðÀ0X
H ÿQ|
±LyÆÓÔµ VÐ²å5×€æïóÝÄ~í·‚òG‘_)7Y�ƒŠ q`Šðv5@wQ
2—° sG(sùä	°
Qi‘#RhiQ…`^UÈ òPukaƒQ
ÎP†h˜†Ñ–Ûp)%p‡qÈmñ vè`
á…ÙÂ0>5ÂG<
`|+Ñ*`k%–Tøvˆ‘ˆutÔÿg
pÿ&‡qXšpÛ�«Ð„MˆNè„P¸>mµw° ÆP�ŠÌ�p�ÈGû´
�øg`
ÓÄgp0åp_64�•ð8g/«À³¥@Øü@ � mÿàAxæˆQB]£H`HPepŠ©È«ØM¤hŠ¨¨Š¬Ø6ÄÆCþP00�ôqp�B8z“¢8�8ý˜8Khû„<†q7Àò|G¡�¢3\$Î ÀsfÁsÔè Þð·WS÷²{‘�	Á‡ÂÓˆ×—„hˆeM	ò‡°Gp=á
*ÿ°±gÞ…’`â`Á@�kEd¡j�”J©ÅPÊ@À€bn5Y36³”P1ù¦pg`Œà•bÐ‹²ff¡’õÜÐ@pî _“:_£2ÀgËd�1‚m‚Œ@uÞŽt@Mù”QYH©”IÉ”N	•R©CïˆvrCwÓÃ�ÿp²™œY
·°)�çk â 	oÈ•gxa,Œwxäy
Ñx®éÓ2-œ÷y	š
‰™tÄ›fwl¥ Âé�³†	Á
Â‘ù’/p´µ	<ý‹‚—à(Ùa±S33I	ÁPÑåbÿG	5ó	 „ó'Rp¡	’ `ð¤išé×VÞ´IÃP‘rG0 ŠP J;s
º Z–
Qs7G×@ké#Ð@�¯P��:�`ÓØ	Á�˜ÓÔZÅ’ñ�H0ãÐŸÿ ‡¶Ÿ
£:•±6™¡™�Ù™Ÿ©^Ævj±DZ¤Fz¤uÓk9zl
ñˆð’ 'A^!…Uz9á…¥%lßÂ¥°)¥¶¤’fa*k¯yÁ9œgpkJ�¶ q‡r2!
€XÕi})ÙGÚ§x 	,éaJ’ à`¨¥yVå
;yÞ 	°õé¤P*¥a
À!£
À¨_—¢º î  f¹X#µ–q2 —H0?àcP—20g”
!Ôµ ¢Ñ�6)H:¬EJjá‰º)*€
	ÁZ¸éy÷ë:¾)ORs
jœTÜú‘ðÞúÜÚb$±©œC­'!Ÿ 	�
q'	+ 	^EîÊ¬ù‰:±¯BÓ¬þ:Õj4@3 ú¯Û©ªª»°S1°P¯›Ç°[±{±›±ŸÀ©¤q	Éã±û;
__CPAN_FILE__ src/widget/templates/buttons/insertunorderedlist.gif
GIF89a¢G¦ðRè`†ï'Œ&ÿÿÿ!ù,'HºÜþ0J„l5ºe]diŠ&‘mÄç…U*Ïj®œ66í_	;
__CPAN_FILE__ src/widget/templates/buttons/list_num_indent.gif
GIF89a‘KvøQì'Œ&ÿÿÿ!ù,&œ�©Ë½Âƒj�³NÒ:a7ŠÆ†U^ÉZàã~À�r‰³ºR;
__CPAN_FILE__ src/widget/templates/buttons/list_bullet_indent.gif
GIF89a¢G¦ðRè`†ï'Œ&ÿÿÿ!ù,'HºÜþ0J„l5ºÿƒBYWižÌˆfvŽŠÎ´X­÷ÆwíC	;
__CPAN_FILE__ src/widget/templates/buttons/save.gif
GIF89aÄ”¯èd†ÚïïïØ°-Ž¢àv’Ýö™Æ˜Ì—¹ÏõÿÊ#9YÆýãŽ{’áržëÿÿÿ!ù,p $ŽdyeJ*'ª–
Ãº‹cßwÌÈcÝüÀ†Ž×s4ˆ$b¨X�|‰h‚ép�If£ú4F™‰­Uìdˆ0÷š˜Rq÷Xp+
r¶áÁçã×dF
…c56„†ˆ6Š”–—”/›œ�!;
__CPAN_FILE__ src/widget/templates/buttons/forecolor.gif
GIF89aæ]   öõõöõöƒ¤êÿ{õùúÇÇÇ­“ÿ²{¯õööõöõj´\…®"öíëÿÝÎ‰Ö†�ÙÖÂÉ™Êúïöÿûòæú©©©u�³•�ÍÅ¸ÿÇ¶íÿÆèèèíï÷–¦ÿÿÚþö···ãEûýp¨+Î–½·Ûö£ÙË—ÁÍ€ÿƒ.Ôf×õ´±[ØØØÓÌ¦÷úùôîöÍÅÊTÿ~°]Í´Íº}µWÌÉÍØqÛ¶È¨]É”˜ÿÖ·ÿ½•À¨¨ò¾Š­Éÿ¸ŸþáÙÿ=õõö?Á½ZÍèõï÷ÿáåã´ÎïÐùÚà§õþº�”éª¨ÿçÿžâ—¤ûÿOàÿÕùÿ€áýÿDüöóÿÖïóé000ÿÿÿÿÿÿ!ù],›€]‚ƒ„…†‡ˆ‰Š…\J%5=40\‡\HM<>–‚[¥¦¦;@ƒ[
E	[S1¯¦§‚&+G(†[-[I„W#X6È[C„ LKFÈ![N„OBÈ[VYU)DT'È[QP2A":/ð[7R8TüX e¡-ñ\°`@bFŽ–ZD±¢¢@;
__CPAN_FILE__ src/widget/templates/buttons/hilitecolor.gif
GIF89aæb¼¼½ãããÐÐÐÏÐÐóóôóôó¬«¬ƒ¤êÿ{ããäïóéº}µ—¤ûWÌÉæ‡ÚDüöÎ–½~°]õï÷óÿÖEûýàÿÕ¾ÿ=qÛÐÏÐ¸Ÿ†�ÙÇ¶íÍÅÊÿOÅ¸ÿúåøýµèôôóTÿãÿ×•ÿ”˜ÿé´¾¶çÐ—ÁÍûvÆÍ´Íáýÿÿl°¶È¨.Ô€ÿƒ««¬õùú÷úùÿÚþö²{¯¬¬¬Å“»žâ•�Íu�³]ÉúïöÎ‰ÖôîöïÐã´Îf×õ½•Àíï÷·Ûö««­…®"?Á½j´\÷™ÿà§õ¨¨òÖ·ÿ¨ÿòæúÿÆŠ­ÉÖQ|öíë«¬­ÿŸÿóôôÉ™ÊùÚù÷ùp¨+”éª­“ÿZÍè–¦ÿ@@@ÿÿÿÿÿÿ!ùb,¦€b‚ƒ„…†‡ˆ‰Š…a>B7D,@a‡aX?LNM;E–…Z9VK&]'_R3†(S.+! P<ƒ`¿À¿ƒFC^*¾aÉÊ`ƒ-
¾W"Ì‚6YAI¾àà	Ùb\Q¾ë`1)¾ùú`O#%5$zÐðUÅŽ€Ñ�†%
F‰	É–/¨H\Ä±£ÇA�;
__CPAN_FILE__ src/widget/templates/buttons/cancel.gif
GIF89aÕ7ïïïéééåååâââóóóÓÓÓÌBBÅÍ@@ÒzzÌ>>¶Á¶ážžÐccÈ//Í;;¡°¡Ë66æ´´ÅåßßãÍÍÓTT×¡¡ÅÇ""éÑÑÖbbÔxxÉ,,¶Â¶æÅÅ©·©ÖŽŽÏPPÅÛ¾¾ÆÏ]]ßÍÍà¡¡¢±¢ðêêé½½Ç##ùùùööößßßìììýýýûûûÝÝÝÛÛÛ ¯ ÿÿÿÿÿÿ!ù7,”À›pH,kÈd²`ÖlÐ¨íÉ<Æ®ØèZ%Ödà°Ìî:[ètkI!‹5—ë±‘Ë-+W
N 0F*}{^‰%
(‰‡C50•0–0’NŸ"Ÿ�75,«&«¨5'¶
!´//	ÁÅ$/´3ÊËÌ3´4ÐÑÒ4´JÖIMÙEA;
__CPAN_FILE__ src/widget/templates/buttons/left_to_right.gif
GIF89a³
G«FD¨C@¤?=¡<I­H5™4.’-1•08œ7Qì!ù
,7PÉI«½8ëÍ»&à•T@©â8¬¤ª"Ì2ƒ’[I_!
 /6)(Œ¼ËA±ôO�tJíD;
__CPAN_FILE__ src/widget/templates/buttons/strikethrough.gif
GIF89aÕ!?_È±Âí´ÄíÈØõHgËµÄí@`ÈBbË�²îQyØ~Ÿä ½ðIjÍ‚›à£¶éQqÑÅÖõ”¯ètŸëqŒÚ­¾ëQqÐÆ×õb€Ö²ÊóEiÏ¡µév’Ýi˜êÄÖõŽÑŽ9�89YÆÿÿÿ!ù!,fÀ�pH,�È¤rØ9ŸNÇ±Ù©v –Á€pa*‚0¥Q˜p� hI!ÖË�|N¯ËCž¼~ÏÏ9	‚lC‰B‹�]”
‘E �žšDPOŽ«KA;
__CPAN_FILE__ src/widget/templates/buttons/justifyleft.gif
GIF89aÄ6š5O³ND©C?£>I­HJ®IU¸TVºU9�84˜3üüü/”/-’,eÉd*�)5™4[¾Y>¢=1–0:ž9oÒnP´PÊäÊaÄ_;Ÿ:jÎiC¨B,�+'Œ&çççÿÿÿ!ù,? 'Ždižhª®§EeÍ¡EH²l£ÒýÀ`�¥:T
‚Áä±þˆP a88Øl–äìv¢'­˜ƒò>Áè4*;
__CPAN_FILE__ src/widget/templates/buttons/delete.gif
GIF89a€Å!ù,(Œ�©Ëí@“)R™½ÙÙÐ=Ûƒ…âG~æ‚‚—Ò¯¼Êp
Í É÷N;
__CPAN_FILE__ src/widget/templates/buttons/list_num_outdent.gif
GIF89a‘KvøQì'Œ&ÿÿÿ!ù,&œ�©Ë½Âƒîˆ‹…“´Gp 1
Ùy‘âÈ¥÷¼`¡™*·:T;
__CPAN_FILE__ src/widget/templates/buttons/insertimage.gif
GIF89aæ\¤¡œ¥¢�xwp¦£žþÿþª¤¨^­€É†É!…Î¨¥ 5r³‚Ézªì[žÎÓÍ|¾2ŠÁkl�ŸXš~½F~¬ÖT–gšÜV˜4p¯zyrZ�Ðƒ½]d°q±9_“Õ’ÆYŠ°ßC}¿‚ËŠ´Ë~«ân¡C]®t¦èS¡q¸n â¶ÏíY‘¡W‡º!` ‡Ë$_¬G~'›¹Ùª§£}­î�®Ñy·CH�ÃqžÔ•ÌL#b¥V�‘P’„¾K†¿dr¶-‹ÄRI€¿}¤Î—ËM™·×‚É„Ê‰Àe�¶Û‘×ª¨£N†Ç¸Ðð `¡t«91mˆ³Ù‹Ó‚Â2†Êt°^bª'£ÃîTLIwvoÍÒÌÿÿÿÿÿÿ!ù\,°€\‚‚[…†‡…ƒƒˆŒ[Š\�‡�„†‹’‚4
Ÿ™KZ‚Y‘ˆY¦\¨=/N.6E3C[¬¨;B89!,MW[¼<-"L+(
5[«§U?H%I$QØ¼[)V7>A &2PÉ§[1'*S@:ˆ<9wO‰”#Œ`p„
[¥:¤LP,3jÌX€•–� CŠd5©¤É“�;
__CPAN_FILE__ src/widget/templates/buttons/justifycenter.gif
GIF89a³:�94˜3/“.@¤?N±M¬Ü¬GªF[¾ZüüüaÅ`T¸SgÊf,�+çççÿÿÿ!ù,1ÐÉI«½8ë}ËJ‡BLÊLHã¾0ÌÍå©®YüÎ\�Þ@ŠnØài€ÁÑel:5;
__CPAN_DIR__ src/widget/vml
__CPAN_FILE__ src/widget/vml/Chart.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.vml.Chart");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.Chart");
dojo.require("dojo.math");
dojo.require("dojo.html.layout");
dojo.require("dojo.gfx.color");

dojo.widget.defineWidget(
	"dojo.widget.vml.Chart",
	[dojo.widget.HtmlWidget, dojo.widget.Chart],
	function(){
		//	summary
		//	initializes the VML version of Chart.
		this.templatePath=null;
		this.templateCssPath=null;
		this._isInitialize=false;
		this.hasData=false;
		this.vectorNode=null;
		this.plotArea=null;
		this.dataGroup=null;
		this.axisGroup=null;
		this.properties={
			height:0,	//	defaults, will resize to the domNode.
			width:0,
			defaultWidth:600,
			defaultHeight:400,
			plotType:null,
			padding:{
				top:10,
				bottom:2,
				left:60,
				right:30
			},
			axes:{
				x:{
					plotAt:0,
					label:"",
					unitLabel:"",
					unitType:Number,
					nUnitsToShow:10,
					range:{
						min:0,
						max:200
					}
				},
				y:{
					plotAt:0,
					label:"",
					unitLabel:"",
					unitType:Number,
					nUnitsToShow:10,
					range:{
						min:0,
						max:200
					}
				}
			}
		};
	},
{
	parseProperties:function(/* HTMLElement */node){
		//	summary
		//	Parse the properties off the main tag
		var bRangeX=false;
		var bRangeY=false;
		if (node.getAttribute("width")){ 
			this.properties.width=node.getAttribute("width");
		}
		if (node.getAttribute("height")){
			this.properties.height=node.getAttribute("height");
		}
		if (node.getAttribute("plotType")){
			this.properties.plotType=node.getAttribute("plotType");
		}
		if (node.getAttribute("padding")){
			if (node.getAttribute("padding").indexOf(",") > -1)
				var p=node.getAttribute("padding").split(","); 
			else var p=node.getAttribute("padding").split(" ");
			if (p.length==1){
				var pad=parseFloat(p[0]);
				this.properties.padding.top=pad;
				this.properties.padding.right=pad;
				this.properties.padding.bottom=pad;
				this.properties.padding.left=pad;
			} else if(p.length==2){
				var padV=parseFloat(p[0]);
				var padH=parseFloat(p[1]);
				this.properties.padding.top=padV;
				this.properties.padding.right=padH;
				this.properties.padding.bottom=padV;
				this.properties.padding.left=padH;
			} else if(p.length==4){
				this.properties.padding.top=parseFloat(p[0]);
				this.properties.padding.right=parseFloat(p[1]);
				this.properties.padding.bottom=parseFloat(p[2]);
				this.properties.padding.left=parseFloat(p[3]);
			}
		}
		if (node.getAttribute("rangeX")){
			var p=node.getAttribute("rangeX");
			if (p.indexOf(",")>-1) p=p.split(",");
			else p=p.split(" ");
			this.properties.axes.x.range.min=parseFloat(p[0]);
			this.properties.axes.x.range.max=parseFloat(p[1]);
			bRangeX=true;
		}
		if (node.getAttribute("rangeY")){
			var p=node.getAttribute("rangeY");
			if (p.indexOf(",")>-1) p=p.split(",");
			else p=p.split(" ");
			this.properties.axes.y.range.min=parseFloat(p[0]);
			this.properties.axes.y.range.max=parseFloat(p[1]);
			bRangeY=true;
		}
		return { rangeX:bRangeX, rangeY:bRangeY };
	},
	setAxesPlot:function(/* HTMLElement */table){
		//	summary
		//	figure out where to plot the axes
		if (table.getAttribute("axisAt")){
			var p=table.getAttribute("axisAt");
			if (p.indexOf(",")>-1) p=p.split(",");
			else p=p.split(" ");
			
			//	x axis
			if (!isNaN(parseFloat(p[0]))){
				this.properties.axes.x.plotAt=parseFloat(p[0]);
			} else if (p[0].toLowerCase()=="ymin"){
				this.properties.axes.x.plotAt=this.properties.axes.y.range.min;
			} else if (p[0].toLowerCase()=="ymax"){
				this.properties.axes.x.plotAt=this.properties.axes.y.range.max;
			}

			// y axis
			if (!isNaN(parseFloat(p[1]))){
				this.properties.axes.y.plotAt=parseFloat(p[1]);
			} else if (p[1].toLowerCase()=="xmin"){
				this.properties.axes.y.plotAt=this.properties.axes.x.range.min;
			} else if (p[1].toLowerCase()=="xmax"){
				this.properties.axes.y.plotAt=this.properties.axes.x.range.max;
			}
		} else {
			this.properties.axes.x.plotAt=this.properties.axes.y.range.min;
			this.properties.axes.y.plotAt=this.properties.axes.x.range.min;
		}
	},
	drawVectorNode:function(){
		//	summary
		//	Draws the main canvas for the chart
		if(this.vectorNode){ this.destroy(); }
		this.vectorNode=document.createElement("div");
		this.vectorNode.style.width=this.properties.width+"px";
		this.vectorNode.style.height=this.properties.height+"px";
		this.vectorNode.style.position="relative";
		this.domNode.appendChild(this.vectorNode);
	},
	drawPlotArea:function(){
		//	summary
		//	Draws the plot area for the chart
		var plotWidth=this.properties.width-this.properties.padding.left-this.properties.padding.right;
		var plotHeight=this.properties.height-this.properties.padding.top-this.properties.padding.bottom;

		if(this.plotArea){
			this.plotArea.parentNode.removeChild(this.plotArea);
			this.plotArea=null;
		}
		this.plotArea=document.createElement("div");
		this.plotArea.style.position="absolute";
		this.plotArea.style.backgroundColor="#fff";
		this.plotArea.style.top=(this.properties.padding.top)-2+"px";
		this.plotArea.style.left=(this.properties.padding.left-1)+"px";
		this.plotArea.style.width=plotWidth+"px";
		this.plotArea.style.height=plotHeight+"px";
		this.plotArea.style.clip="rect(0 "+plotWidth+" "+plotHeight+" 0)";
		this.vectorNode.appendChild(this.plotArea);
	},
	drawDataGroup:function(){
		//	summary
		//	Draws the data group for the chart
		var plotWidth=this.properties.width-this.properties.padding.left-this.properties.padding.right;
		var plotHeight=this.properties.height-this.properties.padding.top-this.properties.padding.bottom;

		if(this.dataGroup){
			this.dataGroup.parentNode.removeChild(this.dataGroup);
			this.dataGroup=null;
		}
		this.dataGroup=document.createElement("div");
		this.dataGroup.style.position="absolute";
		this.dataGroup.setAttribute("title", "Data Group");
		this.dataGroup.style.top="0px";
		this.dataGroup.style.left="0px";
		this.dataGroup.style.width=plotWidth+"px";
		this.dataGroup.style.height=plotHeight+"px";
		this.plotArea.appendChild(this.dataGroup);
	},
	drawAxes:function(){
		//	summary
		//	Draws the axes for the chart
		var plotWidth=this.properties.width-this.properties.padding.left-this.properties.padding.right;
		var plotHeight=this.properties.height-this.properties.padding.top-this.properties.padding.bottom;

		if(this.axisGroup){
			this.axisGroup.parentNode.removeChild(this.axisGroup);
			this.axisGroup=null;
		}
		this.axisGroup=document.createElement("div");
		this.axisGroup.style.position="absolute";
		this.axisGroup.setAttribute("title", "Axis Group");
		this.axisGroup.style.top="0px";
		this.axisGroup.style.left="0px";
		this.axisGroup.style.width=plotWidth+"px";
		this.axisGroup.style.height=plotHeight+"px";
		this.plotArea.appendChild(this.axisGroup);
		var stroke=1;

		//	x axis
		var line=document.createElement("v:line");
		var y=dojo.widget.vml.Chart.Plotter.getY(this.properties.axes.x.plotAt, this);
		line.setAttribute("from", "0px,"+y+"px");
		line.setAttribute("to", plotWidth+"px,"+y+"px");
		line.style.position="absolute";
		line.style.top="0px";
		line.style.left="0px";
		line.style.antialias="false";
		line.setAttribute("strokecolor", "#666");
		line.setAttribute("strokeweight", stroke*2+"px");
		this.axisGroup.appendChild(line);

		//	y axis
		var line=document.createElement("v:line");
		var x=dojo.widget.vml.Chart.Plotter.getX(this.properties.axes.y.plotAt, this);
		line.setAttribute("from", x+"px,0px");
		line.setAttribute("to", x+"px,"+plotHeight+"px");
		line.style.position="absolute";
		line.style.top="0px";
		line.style.left="0px";
		line.style.antialias="false";
		line.setAttribute("strokecolor", "#666");
		line.setAttribute("strokeweight", stroke*2+"px");
		this.axisGroup.appendChild(line);
		
		//	labels
		var size=10;

		//	x axis labels.
		var t=document.createElement("div");
		t.style.position="absolute";
		t.style.top=(this.properties.height-this.properties.padding.bottom)+"px";
		t.style.left=this.properties.padding.left+"px";
		t.style.fontFamily="sans-serif";
		t.style.fontSize=size+"px";
		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.x.range.min),2);
		this.vectorNode.appendChild(t);

		t=document.createElement("div");
		t.style.position="absolute";
		t.style.top=(this.properties.height-this.properties.padding.bottom)+"px";
		t.style.left=(this.properties.width-this.properties.padding.right-size)+"px";
		t.style.fontFamily="sans-serif";
		t.style.fontSize=size+"px";
		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.x.range.max),2);
		this.vectorNode.appendChild(t);

		//	y axis labels.
		t=document.createElement("div");
		t.style.position="absolute";
		t.style.top=(size/2)+"px";
		t.style.left="0px";
		t.style.width=this.properties.padding.left + "px";
		t.style.textAlign="right";
		t.style.paddingRight="4px";
		t.style.fontFamily="sans-serif";
		t.style.fontSize=size+"px";
		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.y.range.max),2);
		this.vectorNode.appendChild(t);
		
		t=document.createElement("div");
		t.style.position="absolute";
		t.style.top=(this.properties.height-this.properties.padding.bottom-size)+"px";
		t.style.left="0px";
		t.style.width=this.properties.padding.left + "px";
		t.style.textAlign="right";
		t.style.paddingRight="4px";
		t.style.fontFamily="sans-serif";
		t.style.fontSize=size+"px";
		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.y.range.min),2);
		this.vectorNode.appendChild(t);
	},
	
	init:function(){
		//	summary
		//	Initialize the chart
		if(!this.properties.width || !this.properties.height){
			var box=dojo.html.getContentBox(this.domNode);
			if(!this.properties.width){
				this.properties.width=(box.width<32)?this.properties.defaultWidth:box.width;
			}
			if(!this.properties.height){
				this.properties.height=(box.height<32)?this.properties.defaultHeight:box.height;
			}
		}

		//	set up the chart; each is a method so that it can be selectively overridden.
		this.drawVectorNode();
		this.drawPlotArea();
		this.drawDataGroup();
		this.drawAxes();

		//	this is last.
		this.assignColors();
		this._isInitialized=true;
	},
	destroy:function(){
		//	summary
		//	Node cleanup
		while(this.domNode.childNodes.length>0){
			this.domNode.removeChild(this.domNode.childNodes[0]);
		}
		this.vectorNode=this.plotArea=this.dataGroup=this.axisGroup=null;
	},
	render:function(){
		//	summary
		//	Draws the data on the chart
		if (this.dataGroup){
			while(this.dataGroup.childNodes.length>0){
				this.dataGroup.removeChild(this.dataGroup.childNodes[0]);
			}
		} else {
			this.init();
		}
		for(var i=0; i<this.series.length; i++){
			dojo.widget.vml.Chart.Plotter.plot(this.series[i], this);
		}
	},
	postCreate:function(){
		//	summary
		//	Parse any data if included with the chart, and kick off the rendering.
		var table=this.domNode.getElementsByTagName("table")[0];
		if (table){
			var ranges=this.parseProperties(table);
			var bRangeX=false;
			var bRangeY=false;
		
			//	fix the axes
			var axisValues = this.parseData(table);
			if(!bRangeX){
				this.properties.axes.x.range={min:axisValues.x.min, max:axisValues.x.max};
			}
			if(!bRangeY){
				this.properties.axes.y.range={min:axisValues.y.min, max:axisValues.y.max};
			}
			this.setAxesPlot(table);

			//	table values should be populated, now pop it off.
			this.domNode.removeChild(table);
		}
		if(this.series.length>0){
			this.render();
		}
	}
});

dojo.widget.vml.Chart.Plotter=new function(){
	//	summary
	//	Singleton for plotting series of data.
	var self=this;
	var plotters = {};
	var types=dojo.widget.Chart.PlotTypes;
	
	this.getX=function(/* string||number */value, /* dojo.widget.Chart */chart){
		//	summary
		//	Calculate the x coord on the passed chart for the passed value
		var v=parseFloat(value);
		var min=chart.properties.axes.x.range.min;
		var max=chart.properties.axes.x.range.max;
		var ofst=0-min;
		min+=ofst; max+=ofst; v+=ofst;

		var xmin = 0;
		var xmax=chart.properties.width-chart.properties.padding.left-chart.properties.padding.right;
		var x=(v*((xmax-xmin)/max))+xmin;
		return x;
	};
	this.getY=function(/* string||number */value, /* dojo.widget.Chart */chart){
		//	summary
		//	Calculate the y coord on the passed chart for the passed value
		var v=parseFloat(value);
		var max=chart.properties.axes.y.range.max;
		var min=chart.properties.axes.y.range.min;
		var ofst=0;
		if(min<0)ofst+=Math.abs(min);
		min+=ofst; max+=ofst; v+=ofst;
		
		var ymin=chart.properties.height-chart.properties.padding.top-chart.properties.padding.bottom;
		var ymax = 0;
		var y=(((ymin-ymax)/(max-min))*(max-v))+ymax;
		return y;
	};

	this.addPlotter=function(/* string */name, /* function */func){
		//	summary
		//	add a custom plotter function to this object.
		plotters[name]=func;
	};
	this.plot=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series.
		if (series.values.length==0) return;	//	void
		if (series.plotType && plotters[series.plotType]){
			return plotters[series.plotType](series, chart);	//	void
		}
		else if (chart.plotType && plotters[chart.plotType]){
			return plotters[chart.plotType](series, chart);		//	void
		}
	};

	//	plotting
	plotters["bar"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a set of bars.
		var space=1;
		var lastW = 0;
		var ys = [];
		var yAxis=self.getY(chart.properties.axes.x.plotAt, chart);
		var yA = yAxis;
		for (var i=0; i<series.values.length; i++){
			var x=self.getX(series.values[i].x, chart);
			var w;
			if (i==series.values.length-1){
				w=lastW;
			} else{
				w=self.getX(series.values[i+1].x, chart)-x-space;
				lastW=w;
			}
			x-=(w/2);

			var y=self.getY(series.values[i].value, chart);
			var h=Math.abs(yA-y);
			if (parseFloat(series.values[i].value) < chart.properties.axes.x.plotAt){
				y=yA;
			}

			var bar=document.createElement("v:rect");
			bar.style.position="absolute";
			bar.style.top=y+"px";
			bar.style.left=x+"px";
			bar.style.width=w+"px";
			bar.style.height=h+"px";
			bar.setAttribute("fillColor", series.color);
			bar.setAttribute("stroked", "false");
			bar.style.antialias="false";
			bar.setAttribute("title", series.label + " (" + i + "): " + series.values[i].value);
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.9");
			bar.appendChild(fill);
			chart.dataGroup.appendChild(bar);
		}
	};	
	plotters["line"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a line with tensioning
		var tension=1.5;

		var line=document.createElement("v:shape");
		line.setAttribute("strokeweight", "2px");
		line.setAttribute("strokecolor", series.color);
		line.setAttribute("fillcolor", "none");
		line.setAttribute("filled", "false");
		line.setAttribute("title", series.label);
		line.setAttribute("coordsize", chart.properties.width + "," + chart.properties.height);
		line.style.position="absolute";
		line.style.top="0px";
		line.style.left="0px";
		line.style.width= chart.properties.width+"px";
		line.style.height=chart.properties.height+"px";
		var stroke=document.createElement("v:stroke");
		stroke.setAttribute("opacity", "0.85");
		line.appendChild(stroke);

		var path = [];
		for (var i=0; i<series.values.length; i++){
			var x = Math.round(self.getX(series.values[i].x, chart));
			var y = Math.round(self.getY(series.values[i].value, chart));

			if (i==0){
				path.push("m");
				path.push(x+","+y);
			}else{
				var lastx=Math.round(self.getX(series.values[i-1].x, chart));
				var lasty=Math.round(self.getY(series.values[i-1].value, chart));
				var dx=x-lastx;
				var dy=y-lasty;
				
				path.push("c");
				var cx=Math.round((x-(tension-1)*(dx/tension)));
				path.push(cx+","+lasty);
				cx=Math.round((x-(dx/tension)));
				path.push(cx+","+y);
				path.push(x+","+y);
			}
		}
		line.setAttribute("path", path.join(" ")+" e");
		chart.dataGroup.appendChild(line);
	};
	plotters["area"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as an area with tensioning.
		var tension=1.5;

		var line=document.createElement("v:shape");
		line.setAttribute("strokeweight", "1px");
		line.setAttribute("strokecolor", series.color);
		line.setAttribute("fillcolor", series.color);
		line.setAttribute("title", series.label);
		line.setAttribute("coordsize", chart.properties.width + "," + chart.properties.height);
		line.style.position="absolute";
		line.style.top="0px";
		line.style.left="0px";
		line.style.width= chart.properties.width+"px";
		line.style.height=chart.properties.height+"px";
		var stroke=document.createElement("v:stroke");
		stroke.setAttribute("opacity", "0.8");
		line.appendChild(stroke);
		var fill=document.createElement("v:fill");
		fill.setAttribute("opacity", "0.4");
		line.appendChild(fill);

		var path = [];
		for (var i=0; i<series.values.length; i++){
			var x = Math.round(self.getX(series.values[i].x, chart));
			var y = Math.round(self.getY(series.values[i].value, chart));

			if (i==0){
				path.push("m");
				path.push(x+","+y);
			}else{
				var lastx=Math.round(self.getX(series.values[i-1].x, chart));
				var lasty=Math.round(self.getY(series.values[i-1].value, chart));
				var dx=x-lastx;
				var dy=y-lasty;
				
				path.push("c");
				var cx=Math.round((x-(tension-1)*(dx/tension)));
				path.push(cx+","+lasty);
				cx=Math.round((x-(dx/tension)));
				path.push(cx+","+y);
				path.push(x+","+y);
			}
		}
		path.push("l");
		path.push(x + "," + self.getY(0, chart));
		path.push("l");
		path.push(self.getX(0, chart) + "," + self.getY(0,chart));
		line.setAttribute("path", path.join(" ")+" x e");
		chart.dataGroup.appendChild(line);
	};
	plotters["scatter"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a scatter chart
		var r=6;
		for (var i=0; i<series.values.length; i++){
			var x=self.getX(series.values[i].x, chart);
			var y=self.getY(series.values[i].value, chart);
			var mod=r/2;

			var point=document.createElement("v:rect");
			point.setAttribute("fillcolor", series.color);
			point.setAttribute("strokecolor", series.color);
			point.setAttribute("title", series.label + ": " + series.values[i].value);
			point.style.position="absolute";
			point.style.rotation="45";
			point.style.top=(y-mod)+"px";
			point.style.left=(x-mod)+"px";
			point.style.width=r+"px";
			point.style.height=r+"px";
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.6");
			point.appendChild(fill);
			chart.dataGroup.appendChild(point);
		}
	};	
	plotters["bubble"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
		//	summary
		//	plot the passed series as a series of bubbles (scatter with 3rd dimension)
		//	added param for series[n].value: size
		var minR=1;
		
		//	do this off the x axis?
		var min=chart.properties.axes.x.range.min;
		var max=chart.properties.axes.x.range.max;
		var ofst=0-min;

		min+=ofst; max+=ofst;
		var xmin=chart.properties.padding.left;
		var xmax=chart.properties.width-chart.properties.padding.right;
		var factor=(max-min)/(xmax-xmin)*25;
		
		for (var i=0; i<series.values.length; i++){
			var size = series.values[i].size;
			if (isNaN(parseFloat(size))) size=minR;

			var radius=(parseFloat(size)*factor)/2;
			var diameter=radius * 2;
			var cx=self.getX(series.values[i].x, chart);
			var cy=self.getY(series.values[i].value, chart);

			var top=cy-radius;
			var left=cx-radius;

			var point=document.createElement("v:oval");
			point.setAttribute("fillcolor", series.color);
			point.setAttribute("title", series.label + ": " + series.values[i].value + " (" + size + ")");
			point.setAttribute("stroked", "false");
			point.style.position="absolute";
			
			point.style.top=top+"px";
			point.style.left=left+"px";
			point.style.width=diameter+"px";
			point.style.height=diameter+"px";

			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.8");
			point.appendChild(fill);
			
			chart.dataGroup.appendChild(point);
		}
	};
}();

__CPAN_DIR__ src/lfx
__CPAN_FILE__ src/lfx/Animation.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lfx.Animation");

dojo.require("dojo.lang.func");

/*
	Animation package based on Dan Pupius' work: http://pupius.co.uk/js/Toolkit.Drawing.js
*/
dojo.lfx.Line = function(/*int*/ start, /*int*/ end){
	// summary: dojo.lfx.Line is the object used to generate values
	//			from a start value to an end value
	this.start = start;
	this.end = end;
	if(dojo.lang.isArray(start)){
		/* start: Array
		   end: Array
		   pId: a */
		var diff = [];
		dojo.lang.forEach(this.start, function(s,i){
			diff[i] = this.end[i] - s;
		}, this);
		
		this.getValue = function(/*float*/ n){
			var res = [];
			dojo.lang.forEach(this.start, function(s, i){
				res[i] = (diff[i] * n) + s;
			}, this);
			return res; // Array
		}
	}else{
		var diff = end - start;
			
		this.getValue = function(/*float*/ n){
			//	summary: returns the point on the line
			//	n: a floating point number greater than 0 and less than 1
			return (diff * n) + this.start; // Decimal
		}
	}
}

dojo.lfx.easeDefault = function(/*Decimal?*/ n){
	//	summary: Returns the point for point n on a sin wave.
	if(dojo.render.html.khtml){
		// the cool kids are obviously not using konqueror...
		// found a very wierd bug in floats constants, 1.5 evals as 1
		// seems somebody mixed up ints and floats in 3.5.4 ??
		// FIXME: investigate more and post a KDE bug (Fredrik)
		return (parseFloat("0.5")+((Math.sin( (n+parseFloat("1.5")) * Math.PI))/2));
	}else{
		return (0.5+((Math.sin( (n+1.5) * Math.PI))/2));
	}
}

dojo.lfx.easeIn = function(/*Decimal?*/ n){
	//	summary: returns the point on an easing curve
	//	n: a floating point number greater than 0 and less than 1
	return Math.pow(n, 3);
}

dojo.lfx.easeOut = function(/*Decimal?*/ n){
	//	summary: returns the point on the line
	//	n: a floating point number greater than 0 and less than 1
	return ( 1 - Math.pow(1 - n, 3) );
}

dojo.lfx.easeInOut = function(/*Decimal?*/ n){
	//	summary: returns the point on the line
	//	n: a floating point number greater than 0 and less than 1
	return ( (3 * Math.pow(n, 2)) - (2 * Math.pow(n, 3)) );
}

dojo.lfx.IAnimation = function(){
	// summary: dojo.lfx.IAnimation is an interface that implements
	//			commonly used functions of animation objects
}
dojo.lang.extend(dojo.lfx.IAnimation, {
	// public properties
	curve: null,
	duration: 1000,
	easing: null,
	repeatCount: 0,
	rate: 25,
	
	// events
	handler: null,
	beforeBegin: null,
	onBegin: null,
	onAnimate: null,
	onEnd: null,
	onPlay: null,
	onPause: null,
	onStop: null,
	
	// public methods
	play: null,
	pause: null,
	stop: null,
	
	connect: function(/*Event*/ evt, /*Object*/ scope, /*Function*/ newFunc){
		// summary: Convenience function.  Quickly connect to an event
		//			of this object and save the old functions connected to it.
		// evt: The name of the event to connect to.
		// scope: the scope in which to run newFunc.
		// newFunc: the function to run when evt is fired.
		if(!newFunc){
			/* scope: Function
			   newFunc: null
			   pId: f */
			newFunc = scope;
			scope = this;
		}
		newFunc = dojo.lang.hitch(scope, newFunc);
		var oldFunc = this[evt]||function(){};
		this[evt] = function(){
			var ret = oldFunc.apply(this, arguments);
			newFunc.apply(this, arguments);
			return ret;
		}
		return this; // dojo.lfx.IAnimation
	},

	fire: function(/*Event*/ evt, /*Array*/ args){
		// summary: Convenience function.  Fire event "evt" and pass it
		//			the arguments specified in "args".
		// evt: The event to fire.
		// args: The arguments to pass to the event.
		if(this[evt]){
			this[evt].apply(this, (args||[]));
		}
		return this; // dojo.lfx.IAnimation
	},
	
	repeat: function(/*int*/ count){
		// summary: Set the repeat count of this object.
		// count: How many times to repeat the animation.
		this.repeatCount = count;
		return this; // dojo.lfx.IAnimation
	},

	// private properties
	_active: false,
	_paused: false
});

dojo.lfx.Animation = function(	/*Object*/ handlers, 
								/*int*/ duration, 
								/*dojo.lfx.Line*/ curve, 
								/*function*/ easing, 
								/*int*/ repeatCount, 
								/*int*/ rate){
	//	summary
	//		a generic animation object that fires callbacks into it's handlers
	//		object at various states
	//	handlers: { handler: Function?, onstart: Function?, onstop: Function?, onanimate: Function? }
	dojo.lfx.IAnimation.call(this);
	if(dojo.lang.isNumber(handlers)||(!handlers && duration.getValue)){
		// no handlers argument:
		rate = repeatCount;
		repeatCount = easing;
		easing = curve;
		curve = duration;
		duration = handlers;
		handlers = null;
	}else if(handlers.getValue||dojo.lang.isArray(handlers)){
		// no handlers or duration:
		rate = easing;
		repeatCount = curve;
		easing = duration;
		curve = handlers;
		duration = null;
		handlers = null;
	}
	if(dojo.lang.isArray(curve)){
		/* curve: Array
		   pId: a */
		this.curve = new dojo.lfx.Line(curve[0], curve[1]);
	}else{
		this.curve = curve;
	}
	if(duration != null && duration > 0){ this.duration = duration; }
	if(repeatCount){ this.repeatCount = repeatCount; }
	if(rate){ this.rate = rate; }
	if(handlers){
		dojo.lang.forEach([
				"handler", "beforeBegin", "onBegin", 
				"onEnd", "onPlay", "onStop", "onAnimate"
			], function(item){
				if(handlers[item]){
					this.connect(item, handlers[item]);
				}
			}, this);
	}
	if(easing && dojo.lang.isFunction(easing)){
		this.easing=easing;
	}
}
dojo.inherits(dojo.lfx.Animation, dojo.lfx.IAnimation);
dojo.lang.extend(dojo.lfx.Animation, {
	// "private" properties
	_startTime: null,
	_endTime: null,
	_timer: null,
	_percent: 0,
	_startRepeatCount: 0,

	// public methods
	play: function(/*int?*/ delay, /*bool?*/ gotoStart){
		// summary: Start the animation.
		// delay: How many milliseconds to delay before starting.
		// gotoStart: If true, starts the animation from the beginning; otherwise,
		//            starts it from its current position.
		if(gotoStart){
			clearTimeout(this._timer);
			this._active = false;
			this._paused = false;
			this._percent = 0;
		}else if(this._active && !this._paused){
			return this; // dojo.lfx.Animation
		}
		
		this.fire("handler", ["beforeBegin"]);
		this.fire("beforeBegin");

		if(delay > 0){
			setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
			return this; // dojo.lfx.Animation
		}
		
		this._startTime = new Date().valueOf();
		if(this._paused){
			this._startTime -= (this.duration * this._percent / 100);
		}
		this._endTime = this._startTime + this.duration;

		this._active = true;
		this._paused = false;
		
		var step = this._percent / 100;
		var value = this.curve.getValue(step);
		if(this._percent == 0 ){
			if(!this._startRepeatCount){
				this._startRepeatCount = this.repeatCount;
			}
			this.fire("handler", ["begin", value]);
			this.fire("onBegin", [value]);
		}

		this.fire("handler", ["play", value]);
		this.fire("onPlay", [value]);

		this._cycle();
		return this; // dojo.lfx.Animation
	},

	pause: function(){
		// summary: Pauses a running animation.
		clearTimeout(this._timer);
		if(!this._active){ return this; /*dojo.lfx.Animation*/}
		this._paused = true;
		var value = this.curve.getValue(this._percent / 100);
		this.fire("handler", ["pause", value]);
		this.fire("onPause", [value]);
		return this; // dojo.lfx.Animation
	},

	gotoPercent: function(/*Decimal*/ pct, /*bool?*/ andPlay){
		// summary: Sets the progress of the animation.
		// pct: A percentage in decimal notation (between and including 0.0 and 1.0).
		// andPlay: If true, play the animation after setting the progress.
		clearTimeout(this._timer);
		this._active = true;
		this._paused = true;
		this._percent = pct;
		if(andPlay){ this.play(); }
		return this; // dojo.lfx.Animation
	},

	stop: function(/*bool?*/ gotoEnd){
		// summary: Stops a running animation.
		// gotoEnd: If true, the animation will end.
		clearTimeout(this._timer);
		var step = this._percent / 100;
		if(gotoEnd){
			step = 1;
		}
		var value = this.curve.getValue(step);
		this.fire("handler", ["stop", value]);
		this.fire("onStop", [value]);
		this._active = false;
		this._paused = false;
		return this; // dojo.lfx.Animation
	},

	status: function(){
		// summary: Returns a string representation of the status of
		//			the animation.
		if(this._active){
			return this._paused ? "paused" : "playing"; // String
		}else{
			return "stopped"; // String
		}
		return this;
	},

	// "private" methods
	_cycle: function(){
		clearTimeout(this._timer);
		if(this._active){
			var curr = new Date().valueOf();
			var step = (curr - this._startTime) / (this._endTime - this._startTime);

			if(step >= 1){
				step = 1;
				this._percent = 100;
			}else{
				this._percent = step * 100;
			}
			
			// Perform easing
			if((this.easing)&&(dojo.lang.isFunction(this.easing))){
				step = this.easing(step);
			}

			var value = this.curve.getValue(step);
			this.fire("handler", ["animate", value]);
			this.fire("onAnimate", [value]);

			if( step < 1 ){
				this._timer = setTimeout(dojo.lang.hitch(this, "_cycle"), this.rate);
			}else{
				this._active = false;
				this.fire("handler", ["end"]);
				this.fire("onEnd");

				if(this.repeatCount > 0){
					this.repeatCount--;
					this.play(null, true);
				}else if(this.repeatCount == -1){
					this.play(null, true);
				}else{
					if(this._startRepeatCount){
						this.repeatCount = this._startRepeatCount;
						this._startRepeatCount = 0;
					}
				}
			}
		}
		return this; // dojo.lfx.Animation
	}
});

dojo.lfx.Combine = function(/*dojo.lfx.IAnimation...*/ animations){
	// summary: An animation object to play animations passed to it at the same time.
	dojo.lfx.IAnimation.call(this);
	this._anims = [];
	this._animsEnded = 0;
	
	var anims = arguments;
	if(anims.length == 1 && (dojo.lang.isArray(anims[0]) || dojo.lang.isArrayLike(anims[0]))){
		/* animations: dojo.lfx.IAnimation[]
		   pId: a */
		anims = anims[0];
	}
	
	dojo.lang.forEach(anims, function(anim){
		this._anims.push(anim);
		anim.connect("onEnd", dojo.lang.hitch(this, "_onAnimsEnded"));
	}, this);
}
dojo.inherits(dojo.lfx.Combine, dojo.lfx.IAnimation);
dojo.lang.extend(dojo.lfx.Combine, {
	// private members
	_animsEnded: 0,
	
	// public methods
	play: function(/*int?*/ delay, /*bool?*/ gotoStart){
		// summary: Start the animations.
		// delay: How many milliseconds to delay before starting.
		// gotoStart: If true, starts the animations from the beginning; otherwise,
		//            starts them from their current position.
		if( !this._anims.length ){ return this; /*dojo.lfx.Combine*/}

		this.fire("beforeBegin");

		if(delay > 0){
			setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
			return this; // dojo.lfx.Combine
		}
		
		if(gotoStart || this._anims[0].percent == 0){
			this.fire("onBegin");
		}
		this.fire("onPlay");
		this._animsCall("play", null, gotoStart);
		return this; // dojo.lfx.Combine
	},
	
	pause: function(){
		// summary: Pauses the running animations.
		this.fire("onPause");
		this._animsCall("pause"); 
		return this; // dojo.lfx.Combine
	},
	
	stop: function(/*bool?*/ gotoEnd){
		// summary: Stops the running animations.
		// gotoEnd: If true, the animations will end.
		this.fire("onStop");
		this._animsCall("stop", gotoEnd);
		return this; // dojo.lfx.Combine
	},
	
	// private methods
	_onAnimsEnded: function(){
		this._animsEnded++;
		if(this._animsEnded >= this._anims.length){
			this.fire("onEnd");
		}
		return this; // dojo.lfx.Combine
	},
	
	_animsCall: function(/*String*/ funcName){
		var args = [];
		if(arguments.length > 1){
			for(var i = 1 ; i < arguments.length ; i++){
				args.push(arguments[i]);
			}
		}
		var _this = this;
		dojo.lang.forEach(this._anims, function(anim){
			anim[funcName](args);
		}, _this);
		return this; // dojo.lfx.Combine
	}
});

dojo.lfx.Chain = function(/*dojo.lfx.IAnimation...*/ animations) {
	// summary: An animation object to play animations passed to it
	//			one after another.
	dojo.lfx.IAnimation.call(this);
	this._anims = [];
	this._currAnim = -1;
	
	var anims = arguments;
	if(anims.length == 1 && (dojo.lang.isArray(anims[0]) || dojo.lang.isArrayLike(anims[0]))){
		/* animations: dojo.lfx.IAnimation[]
		   pId: a */
		anims = anims[0];
	}
	
	var _this = this;
	dojo.lang.forEach(anims, function(anim, i, anims_arr){
		this._anims.push(anim);
		if(i < anims_arr.length - 1){
			anim.connect("onEnd", dojo.lang.hitch(this, "_playNext") );
		}else{
			anim.connect("onEnd", dojo.lang.hitch(this, function(){ this.fire("onEnd"); }) );
		}
	}, this);
}
dojo.inherits(dojo.lfx.Chain, dojo.lfx.IAnimation);
dojo.lang.extend(dojo.lfx.Chain, {
	// private members
	_currAnim: -1,
	
	// public methods
	play: function(/*int?*/ delay, /*bool?*/ gotoStart){
		// summary: Start the animation sequence.
		// delay: How many milliseconds to delay before starting.
		// gotoStart: If true, starts the sequence from the beginning; otherwise,
		//            starts it from its current position.
		if( !this._anims.length ) { return this; /*dojo.lfx.Chain*/}
		if( gotoStart || !this._anims[this._currAnim] ) {
			this._currAnim = 0;
		}

		var currentAnimation = this._anims[this._currAnim];

		this.fire("beforeBegin");
		if(delay > 0){
			setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
			return this; // dojo.lfx.Chain
		}
		
		if(currentAnimation){
			if(this._currAnim == 0){
				this.fire("handler", ["begin", this._currAnim]);
				this.fire("onBegin", [this._currAnim]);
			}
			this.fire("onPlay", [this._currAnim]);
			currentAnimation.play(null, gotoStart);
		}
		return this; // dojo.lfx.Chain
	},
	
	pause: function(){
		// summary: Pauses the running animation sequence.
		if( this._anims[this._currAnim] ) {
			this._anims[this._currAnim].pause();
			this.fire("onPause", [this._currAnim]);
		}
		return this; // dojo.lfx.Chain
	},
	
	playPause: function(){
		// summary: If the animation sequence is playing, pause it; otherwise,
		//			play it.
		if(this._anims.length == 0){ return this; }
		if(this._currAnim == -1){ this._currAnim = 0; }
		var currAnim = this._anims[this._currAnim];
		if( currAnim ) {
			if( !currAnim._active || currAnim._paused ) {
				this.play();
			} else {
				this.pause();
			}
		}
		return this; // dojo.lfx.Chain
	},
	
	stop: function(){
		// summary: Stops the running animations.
		var currAnim = this._anims[this._currAnim];
		if(currAnim){
			currAnim.stop();
			this.fire("onStop", [this._currAnim]);
		}
		return currAnim; // dojo.lfx.IAnimation
	},
	
	// private methods
	_playNext: function(){
		if( this._currAnim == -1 || this._anims.length == 0 ) { return this; }
		this._currAnim++;
		if( this._anims[this._currAnim] ){
			this._anims[this._currAnim].play(null, true);
		}
		return this; // dojo.lfx.Chain
	}
});

dojo.lfx.combine = function(/*dojo.lfx.IAnimation...*/ animations){
	// summary: Convenience function.  Returns a dojo.lfx.Combine created
	//			using the animations passed in.
	var anims = arguments;
	if(dojo.lang.isArray(arguments[0])){
		/* animations: dojo.lfx.IAnimation[]
		   pId: a */
		anims = arguments[0];
	}
	if(anims.length == 1){ return anims[0]; }
	return new dojo.lfx.Combine(anims); // dojo.lfx.Combine
}

dojo.lfx.chain = function(/*dojo.lfx.IAnimation...*/ animations){
	// summary: Convenience function.  Returns a dojo.lfx.Chain created
	//			using the animations passed in.
	var anims = arguments;
	if(dojo.lang.isArray(arguments[0])){
		/* animations: dojo.lfx.IAnimation[]
		   pId: a */
		anims = arguments[0];
	}
	if(anims.length == 1){ return anims[0]; }
	return new dojo.lfx.Chain(anims); // dojo.lfx.Combine
}

__CPAN_FILE__ src/lfx/html.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lfx.html");

dojo.require("dojo.gfx.color");
dojo.require("dojo.lfx.Animation");
dojo.require("dojo.lang.array");
dojo.require("dojo.html.display");
dojo.require("dojo.html.color");
dojo.require("dojo.html.layout");

dojo.lfx.html._byId = function(nodes){
	if(!nodes){ return []; }
	if(dojo.lang.isArrayLike(nodes)){
		if(!nodes.alreadyChecked){
			var n = [];
			dojo.lang.forEach(nodes, function(node){
				n.push(dojo.byId(node));
			});
			n.alreadyChecked = true;
			return n;
		}else{
			return nodes;
		}
	}else{
		var n = [];
		n.push(dojo.byId(nodes));
		n.alreadyChecked = true;
		return n;
	}
}

dojo.lfx.html.propertyAnimation = function(	/*DOMNode[]*/ nodes, 
											/*Object[]*/ propertyMap, 
											/*int*/ duration,
											/*function*/ easing,
											/*Object*/ handlers){
	// summary: Returns an animation that will transition the properties of "nodes"
	//			depending how they are defined in "propertyMap".
	// nodes: An array of DOMNodes or one DOMNode.
	// propertyMap: { property: String, start: Decimal?, end: Decimal?, units: String? }
	//				An array of objects defining properties to change.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// handlers: { handler: Function?, onstart: Function?, onstop: Function?, onanimate: Function? }
	nodes = dojo.lfx.html._byId(nodes);

	var targs = {
		"propertyMap": propertyMap,
		"nodes": nodes,
		"duration": duration,
		"easing": easing||dojo.lfx.easeDefault
	};
	
	var setEmUp = function(args){
		if(args.nodes.length==1){
			// FIXME: we're only supporting start-value filling when one node is
			// passed
			
			var pm = args.propertyMap;
			if(!dojo.lang.isArray(args.propertyMap)){
				// it's stupid to have to pack an array with a set of objects
				// when you can just pass in an object list
				var parr = [];
				for(var pname in pm){
					pm[pname].property = pname;
					parr.push(pm[pname]);
				}
				pm = args.propertyMap = parr;
			}
			dojo.lang.forEach(pm, function(prop){
				if(dj_undef("start", prop)){
					if(prop.property != "opacity"){
						prop.start = parseInt(dojo.html.getComputedStyle(args.nodes[0], prop.property));
					}else{
						prop.start = dojo.html.getOpacity(args.nodes[0]);
					}
				}
			});
		}
	}

	var coordsAsInts = function(coords){
		var cints = [];
		dojo.lang.forEach(coords, function(c){ 
			cints.push(Math.round(c));
		});
		return cints;
	}

	var setStyle = function(n, style){
		n = dojo.byId(n);
		if(!n || !n.style){ return; }
		for(var s in style){
			if(s == "opacity"){
				dojo.html.setOpacity(n, style[s]);
			}else{
				n.style[s] = style[s];
			}
		}
	}

	var propLine = function(properties){
		this._properties = properties;
		this.diffs = new Array(properties.length);
		dojo.lang.forEach(properties, function(prop, i){
			// calculate the end - start to optimize a bit
			if(dojo.lang.isFunction(prop.start)){
				prop.start = prop.start(prop, i);
			}
			if(dojo.lang.isFunction(prop.end)){
				prop.end = prop.end(prop, i);
			}
			if(dojo.lang.isArray(prop.start)){
				// don't loop through the arrays
				this.diffs[i] = null;
			}else if(prop.start instanceof dojo.gfx.color.Color){
				// save these so we don't have to call toRgb() every getValue() call
				prop.startRgb = prop.start.toRgb();
				prop.endRgb = prop.end.toRgb();
			}else{
				this.diffs[i] = prop.end - prop.start;
			}
		}, this);

		this.getValue = function(n){
			var ret = {};
			dojo.lang.forEach(this._properties, function(prop, i){
				var value = null;
				if(dojo.lang.isArray(prop.start)){
					// FIXME: what to do here?
				}else if(prop.start instanceof dojo.gfx.color.Color){
					value = (prop.units||"rgb") + "(";
					for(var j = 0 ; j < prop.startRgb.length ; j++){
						value += Math.round(((prop.endRgb[j] - prop.startRgb[j]) * n) + prop.startRgb[j]) + (j < prop.startRgb.length - 1 ? "," : "");
					}
					value += ")";
				}else{
					value = ((this.diffs[i]) * n) + prop.start + (prop.property != "opacity" ? prop.units||"px" : "");
				}
				ret[dojo.html.toCamelCase(prop.property)] = value;
			}, this);
			return ret;
		}
	}
	
	var anim = new dojo.lfx.Animation({
			beforeBegin: function(){ 
				setEmUp(targs); 
				anim.curve = new propLine(targs.propertyMap);
			},
			onAnimate: function(propValues){
				dojo.lang.forEach(targs.nodes, function(node){
					setStyle(node, propValues);
				});
			}
		},
		targs.duration, 
		null,
		targs.easing
	);
	if(handlers){
		for(var x in handlers){
			if(dojo.lang.isFunction(handlers[x])){
				anim.connect(x, anim, handlers[x]);
			}
		}
	}
	
	return anim; // dojo.lfx.Animation
}

dojo.lfx.html._makeFadeable = function(nodes){
	var makeFade = function(node){
		if(dojo.render.html.ie){
			// only set the zoom if the "tickle" value would be the same as the
			// default
			if( (node.style.zoom.length == 0) &&
				(dojo.html.getStyle(node, "zoom") == "normal") ){
				// make sure the node "hasLayout"
				// NOTE: this has been tested with larger and smaller user-set text
				// sizes and works fine
				node.style.zoom = "1";
				// node.style.zoom = "normal";
			}
			// don't set the width to auto if it didn't already cascade that way.
			// We don't want to f anyones designs
			if(	(node.style.width.length == 0) &&
				(dojo.html.getStyle(node, "width") == "auto") ){
				node.style.width = "auto";
			}
		}
	}
	if(dojo.lang.isArrayLike(nodes)){
		dojo.lang.forEach(nodes, makeFade);
	}else{
		makeFade(nodes);
	}
}

dojo.lfx.html.fade = function(/*DOMNode[]*/ nodes,
							  /*Object*/values,
							  /*int?*/ duration,
							  /*Function?*/ easing,
							  /*Function?*/ callback){
	// summary:Returns an animation that will fade the "nodes" from the start to end values passed.
	// nodes: An array of DOMNodes or one DOMNode.
	// values: { start: Decimal?, end: Decimal? }
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var props = { property: "opacity" };
	if(!dj_undef("start", values)){
		props.start = values.start;
	}else{
		props.start = function(){ return dojo.html.getOpacity(nodes[0]); };
	}

	if(!dj_undef("end", values)){
		props.end = values.end;
	}else{
		dojo.raise("dojo.lfx.html.fade needs an end value");
	}

	var anim = dojo.lfx.propertyAnimation(nodes, [ props ], duration, easing);
	anim.connect("beforeBegin", function(){
		dojo.lfx.html._makeFadeable(nodes);
	});
	if(callback){
		anim.connect("onEnd", function(){ callback(nodes, anim); });
	}

	return anim; // dojo.lfx.Animation
}

dojo.lfx.html.fadeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will fade "nodes" from its current opacity to fully opaque.
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	return dojo.lfx.html.fade(nodes, { end: 1 }, duration, easing, callback); // dojo.lfx.Animation
}

dojo.lfx.html.fadeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will fade "nodes" from its current opacity to fully transparent.
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.	
	return dojo.lfx.html.fade(nodes, { end: 0 }, duration, easing, callback); // dojo.lfx.Animation
}

dojo.lfx.html.fadeShow = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will fade "nodes" from transparent to opaque and shows
	//			"nodes" at the end if it is hidden.
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.	
	nodes=dojo.lfx.html._byId(nodes);
	dojo.lang.forEach(nodes, function(node){
		dojo.html.setOpacity(node, 0.0);
	});

	var anim = dojo.lfx.html.fadeIn(nodes, duration, easing, callback);
	anim.connect("beforeBegin", function(){ 
		if(dojo.lang.isArrayLike(nodes)){
			dojo.lang.forEach(nodes, dojo.html.show);
		}else{
			dojo.html.show(nodes);
		}
	});

	return anim; // dojo.lfx.Animation
}

dojo.lfx.html.fadeHide = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will fade "nodes" from its current opacity to opaque and hides
	//			"nodes" at the end.
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	var anim = dojo.lfx.html.fadeOut(nodes, duration, easing, function(){
		if(dojo.lang.isArrayLike(nodes)){
			dojo.lang.forEach(nodes, dojo.html.hide);
		}else{
			dojo.html.hide(nodes);
		}
		if(callback){ callback(nodes, anim); }
	});
	
	return anim; // dojo.lfx.Animation
}

dojo.lfx.html.wipeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will show and wipe in "nodes".
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];

	dojo.lang.forEach(nodes, function(node){
		var oprop = {  };	// old properties of node (before we mucked w/them)
		
		// get node height, either it's natural height or it's height specified via style or class attributes
		// (for FF, the node has to be (temporarily) rendered to measure height)
		dojo.html.show(node);
		var height = dojo.html.getBorderBox(node).height;
		dojo.html.hide(node);

		var anim = dojo.lfx.propertyAnimation(node,
			{	"height": {
					start: 1, // 0 causes IE to display the whole panel
					end: function(){ return height; } 
				}
			}, 
			duration, 
			easing);
	
		anim.connect("beforeBegin", function(){
			oprop.overflow = node.style.overflow;
			oprop.height = node.style.height;
			with(node.style){
				overflow = "hidden";
				height = "1px"; // 0 causes IE to display the whole panel
			}
			dojo.html.show(node);
		});
		
		anim.connect("onEnd", function(){ 
			with(node.style){
				overflow = oprop.overflow;
				height = oprop.height;
			}
			if(callback){ callback(node, anim); }
		});
		anims.push(anim);
	});
	
	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lfx.html.wipeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will wipe out and hide "nodes".
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];
	
	dojo.lang.forEach(nodes, function(node){
		var oprop = {  };	// old properties of node (before we mucked w/them)
		var anim = dojo.lfx.propertyAnimation(node,
			{	"height": {
					start: function(){ return dojo.html.getContentBox(node).height; },
					end: 1 // 0 causes IE to display the whole panel
				} 
			},
			duration,
			easing,
			{
				"beforeBegin": function(){
					oprop.overflow = node.style.overflow;
					oprop.height = node.style.height;
					with(node.style){
						overflow = "hidden";
					}
					dojo.html.show(node);
				},
				
				"onEnd": function(){ 
					dojo.html.hide(node);
					with(node.style){
						overflow = oprop.overflow;
						height = oprop.height;
					}
					if(callback){ callback(node, anim); }
				}
			}
		);
		anims.push(anim);
	});

	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lfx.html.slideTo = function(/*DOMNode*/ nodes,
								 /*Object*/ coords,
								 /*int?*/ duration,
								 /*Function?*/ easing,
								 /*Function?*/ callback){
	// summary: Returns an animation that will slide "nodes" from its current position to
	//			the position defined in "coords".
	// nodes: An array of DOMNodes or one DOMNode.
	// coords: { top: Decimal?, left: Decimal? }
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];
	var compute = dojo.html.getComputedStyle;
	
	if(dojo.lang.isArray(coords)){
		/* coords: Array
		   pId: a */
		dojo.deprecated('dojo.lfx.html.slideTo(node, array)', 'use dojo.lfx.html.slideTo(node, {top: value, left: value});', '0.5');
		coords = { top: coords[0], left: coords[1] };
	}
	dojo.lang.forEach(nodes, function(node){
		var top = null;
		var left = null;
		
		var init = (function(){
			var innerNode = node;
			return function(){
				var pos = compute(innerNode, 'position');
				top = (pos == 'absolute' ? node.offsetTop : parseInt(compute(node, 'top')) || 0);
				left = (pos == 'absolute' ? node.offsetLeft : parseInt(compute(node, 'left')) || 0);

				if (!dojo.lang.inArray(['absolute', 'relative'], pos)) {
					var ret = dojo.html.abs(innerNode, true);
					dojo.html.setStyleAttributes(innerNode, "position:absolute;top:"+ret.y+"px;left:"+ret.x+"px;");
					top = ret.y;
					left = ret.x;
				}
			}
		})();
		init();
		
		var anim = dojo.lfx.propertyAnimation(node,
			{	"top": { start: top, end: (coords.top||0) },
				"left": { start: left, end: (coords.left||0)  }
			},
			duration,
			easing,
			{ "beforeBegin": init }
		);

		if(callback){
			anim.connect("onEnd", function(){ callback(nodes, anim); });
		}

		anims.push(anim);
	});
	
	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lfx.html.slideBy = function(/*DOMNode*/ nodes, /*Object*/ coords, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will slide "nodes" from its current position
	//			to its current position plus the numbers defined in "coords".
	// nodes: An array of DOMNodes or one DOMNode.
	// coords: { top: Decimal?, left: Decimal? }
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];
	var compute = dojo.html.getComputedStyle;

	if(dojo.lang.isArray(coords)){
		/* coords: Array
		   pId: a */
		dojo.deprecated('dojo.lfx.html.slideBy(node, array)', 'use dojo.lfx.html.slideBy(node, {top: value, left: value});', '0.5');
		coords = { top: coords[0], left: coords[1] };
	}

	dojo.lang.forEach(nodes, function(node){
		var top = null;
		var left = null;
		
		var init = (function(){
			var innerNode = node;
			return function(){
				var pos = compute(innerNode, 'position');
				top = (pos == 'absolute' ? node.offsetTop : parseInt(compute(node, 'top')) || 0);
				left = (pos == 'absolute' ? node.offsetLeft : parseInt(compute(node, 'left')) || 0);

				if (!dojo.lang.inArray(['absolute', 'relative'], pos)) {
					var ret = dojo.html.abs(innerNode, true);
					dojo.html.setStyleAttributes(innerNode, "position:absolute;top:"+ret.y+"px;left:"+ret.x+"px;");
					top = ret.y;
					left = ret.x;
				}
			}
		})();
		init();
		
		var anim = dojo.lfx.propertyAnimation(node,
			{
				"top": { start: top, end: top+(coords.top||0) },
				"left": { start: left, end: left+(coords.left||0) }
			},
			duration,
			easing).connect("beforeBegin", init);

		if(callback){
			anim.connect("onEnd", function(){ callback(nodes, anim); });
		}

		anims.push(anim);
	});

	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lfx.html.explode = function(/*DOMNode*/ start,
								 /*DOMNode*/ endNode,
								 /*int?*/ duration,
								 /*Function?*/ easing,
								 /*Function?*/ callback){
	// summary: Returns an animation that will 
	// start:
	// endNode:
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	var h = dojo.html;
	start = dojo.byId(start);
	endNode = dojo.byId(endNode);
	var startCoords = h.toCoordinateObject(start, true);
	var outline = document.createElement("div");
	h.copyStyle(outline, endNode);
	if (endNode.explodeClassName) { outline.className = endNode.explodeClassName; }
	with(outline.style){
		position = "absolute";
		display = "none";
		// border = "1px solid black";
	}
	dojo.body().appendChild(outline);

	with(endNode.style){
		visibility = "hidden";
		display = "block";
	}
	var endCoords = h.toCoordinateObject(endNode, true);
	with(endNode.style){
		display = "none";
		visibility = "visible";
	}

	var props = { opacity: { start: 0.5, end: 1.0 } };
	dojo.lang.forEach(["height", "width", "top", "left"], function(type){
		props[type] = { start: startCoords[type], end: endCoords[type] }
	});
	
	var anim = new dojo.lfx.propertyAnimation(outline, 
		props,
		duration,
		easing,
		{
			"beforeBegin": function(){
				h.setDisplay(outline, "block");
			},
			"onEnd": function(){
				h.setDisplay(endNode, "block");
				outline.parentNode.removeChild(outline);
			}
		}
	);

	if(callback){
		anim.connect("onEnd", function(){ callback(endNode, anim); });
	}
	return anim; // dojo.lfx.Animation
}

dojo.lfx.html.implode = function(/*DOMNode*/ startNode,
								 /*DOMNode*/ end,
								 /*int?*/ duration,
								 /*Function?*/ easing,
								 /*Function?*/ callback){
	// summary: Returns an animation that will 
	// startNode:
	// end:
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	var h = dojo.html;
	startNode = dojo.byId(startNode);
	end = dojo.byId(end);
	var startCoords = dojo.html.toCoordinateObject(startNode, true);
	var endCoords = dojo.html.toCoordinateObject(end, true);

	var outline = document.createElement("div");
	dojo.html.copyStyle(outline, startNode);
	if (startNode.explodeClassName) { outline.className = startNode.explodeClassName; }
	dojo.html.setOpacity(outline, 0.3);
	with(outline.style){
		position = "absolute";
		display = "none";
		backgroundColor = h.getStyle(startNode, "background-color").toLowerCase();
	}
	dojo.body().appendChild(outline);

	var props = { opacity: { start: 1.0, end: 0.5 } };
	dojo.lang.forEach(["height", "width", "top", "left"], function(type){
		props[type] = { start: startCoords[type], end: endCoords[type] }
	});
	
	var anim = new dojo.lfx.propertyAnimation(outline,
		props,
		duration,
		easing,
		{
			"beforeBegin": function(){
				dojo.html.hide(startNode);
				dojo.html.show(outline);
			},
			"onEnd": function(){
				outline.parentNode.removeChild(outline);
			}
		}
	);

	if(callback){
		anim.connect("onEnd", function(){ callback(startNode, anim); });
	}
	return anim; // dojo.lfx.Animation
}

dojo.lfx.html.highlight = function(/*DOMNode[]*/ nodes,
								   /*dojo.gfx.color.Color*/ startColor,
								   /*int?*/ duration,
								   /*Function?*/ easing,
								   /*Function?*/ callback){
	// summary: Returns an animation that will set the background color
	//			of "nodes" to startColor and transition it to "nodes"
	//			original color.
	// startColor: Color to transition from.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];

	dojo.lang.forEach(nodes, function(node){
		var color = dojo.html.getBackgroundColor(node);
		var bg = dojo.html.getStyle(node, "background-color").toLowerCase();
		var bgImage = dojo.html.getStyle(node, "background-image");
		var wasTransparent = (bg == "transparent" || bg == "rgba(0, 0, 0, 0)");
		while(color.length > 3) { color.pop(); }

		var rgb = new dojo.gfx.color.Color(startColor);
		var endRgb = new dojo.gfx.color.Color(color);

		var anim = dojo.lfx.propertyAnimation(node, 
			{ "background-color": { start: rgb, end: endRgb } }, 
			duration, 
			easing,
			{
				"beforeBegin": function(){ 
					if(bgImage){
						node.style.backgroundImage = "none";
					}
					node.style.backgroundColor = "rgb(" + rgb.toRgb().join(",") + ")";
				},
				"onEnd": function(){ 
					if(bgImage){
						node.style.backgroundImage = bgImage;
					}
					if(wasTransparent){
						node.style.backgroundColor = "transparent";
					}
					if(callback){
						callback(node, anim);
					}
				}
			}
		);

		anims.push(anim);
	});
	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lfx.html.unhighlight = function(/*DOMNode[]*/ nodes,
									 /*dojo.gfx.color.Color*/ endColor,
									 /*int?*/ duration,
									 /*Function?*/ easing,
									 /*Function?*/ callback){
	// summary: Returns an animation that will transition "nodes" background color
	//			from its current color to "endColor".
	// endColor: Color to transition to.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];

	dojo.lang.forEach(nodes, function(node){
		var color = new dojo.gfx.color.Color(dojo.html.getBackgroundColor(node));
		var rgb = new dojo.gfx.color.Color(endColor);

		var bgImage = dojo.html.getStyle(node, "background-image");
		
		var anim = dojo.lfx.propertyAnimation(node, 
			{ "background-color": { start: color, end: rgb } },
			duration, 
			easing,
			{
				"beforeBegin": function(){ 
					if(bgImage){
						node.style.backgroundImage = "none";
					}
					node.style.backgroundColor = "rgb(" + color.toRgb().join(",") + ")";
				},
				"onEnd": function(){ 
					if(callback){
						callback(node, anim);
					}
				}
			}
		);
		anims.push(anim);
	});
	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lang.mixin(dojo.lfx, dojo.lfx.html);

__CPAN_FILE__ src/lfx/rounded.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lfx.rounded");

dojo.require("dojo.lang.common");
dojo.require("dojo.html.common");
dojo.require("dojo.html.style");
dojo.require("dojo.html.display");
dojo.require("dojo.html.layout");

/*	Port of curvyCorners, by Cameron Cooke and Tim Hutchison.
 *	Original port done by Brian Lucas.
 *	Refactor and function by trt.
 */
dojo.lfx.rounded = function(/* object */settings /* ... */){
	//	summary
	//	Creates a set of rounded corners based on settings.
	var options={
		validTags:settings.validTags || ["div"],					//	tags we can apply this to
		autoPad:settings.autoPad!=null ? settings.autoPad : true,		//	automatically pad
		antiAlias:settings.antiAlias!=null ? settings.antiAlias : true,	//	anti-alias corners
		radii:{ 	//	corner radii
			tl:(settings.tl && settings.tl.radius!=null) ? settings.tl.radius:5, 
			tr:(settings.tr && settings.tr.radius!=null) ? settings.tr.radius:5, 
			bl:(settings.bl && settings.bl.radius!=null) ? settings.bl.radius:5, 
			br:(settings.br && settings.br.radius!=null) ? settings.br.radius:5 
		}
	};

	//	get the node list to operate on.
	var nodes;
	if(typeof(arguments[1]) == "string"){
		//	a CSS classname was passed, grab a node list.
		nodes=dojo.html.getElementsByClass(arguments[1]);
	} else if(dojo.lang.isArrayLike(arguments[1])){
		//	we assume that the second argument is an array of nodes to apply this to.
		nodes=arguments[1];
		for(var i=0; i<nodes.length; i++){ nodes[i]=dojo.byId(nodes[i]); }
	}
	if(nodes.length == 0) return;	//	don't bother.

	////////////////////////////////////////////////////////////////////
	for(var i=0; i<nodes.length; i++){
		dojo.lfx.rounded.applyCorners(options, nodes[i]);
	}
};

//	can call this directly if one wants.
dojo.lfx.rounded.applyCorners = function(/* object */options, /* HTMLElement */node){
	//	summary
	//	Rounds corners based on options to passed node.
	var top = null;
	var bottom = null;
	var contentNode = null;
	var fns=dojo.lfx.rounded._fns;

	//	node details
	var width = node.offsetWidth;
	var height = node.offsetHeight;
	var borderWidth = parseInt(dojo.html.getComputedStyle(node, "border-top-width"));
	var borderColor = dojo.html.getComputedStyle(node, "border-top-color");
	var color = dojo.html.getComputedStyle(node, "background-color");
	var bgImage = dojo.html.getComputedStyle(node, "background-image");
	var position = dojo.html.getComputedStyle(node, "position");
	var padding = parseInt(dojo.html.getComputedStyle(node, "padding-top"));

	//	formatting details
	//	TODO: use Dojo equivilents for these if exists.
	var format={
		height : height,
		width : width,
		borderWidth : borderWidth,
		color : fns.getRGB(color),
		padding : padding,
		borderColor : fns.getRGB(borderColor),
		borderString : borderWidth + "px" + " solid " + fns.getRGB(borderColor),
		bgImage : ((bgImage != "none")? bgImage : ""),
		content : node.innerHTML
	};

	if(!dojo.html.isPositionAbsolute(node)){ node.style.position="relative"; }
	node.style.padding="0px";
	if(dojo.render.html.ie && width=="auto" && height=="auto"){ node.style.width="100%"; }
	if(options.autoPad && format.padding>0){
		node.innerHTML="";
	}

	var topHeight=Math.max(options.radii.tl, options.radii.tr);
	var bottomHeight=Math.max(options.radii.bl, options.radii.br);

	//	build the containers.
	if(options.radii.tl || options.radii.tr){
		top = document.createElement("div");
		top.style.width="100%";
		top.style.fontSize="1px";
		top.style.overflow="hidden";
		top.style.position="absolute";
		top.style.paddingLeft=format.borderWidth+"px";
		top.style.paddingRight=format.borderWidth+"px";
		top.style.height=topHeight+"px";
		top.style.top=(0-topHeight)+"px";
		top.style.left=(0-format.borderWidth)+"px";
		node.appendChild(top);
	}
	if(options.radii.bl || options.radii.br){	//	bottom
		bottom = document.createElement("div");
		bottom.style.width="100%";
		bottom.style.fontSize="1px";
		bottom.style.overflow="hidden";
		bottom.style.position="absolute";
		bottom.style.paddingLeft=format.borderWidth+"px";
		bottom.style.paddingRight=format.borderWidth+"px";
		bottom.style.height=bottomHeight+"px";
		bottom.style.bottom=(0-bottomHeight)+"px";
		bottom.style.left=(0-format.borderWidth)+"px";
		node.appendChild(bottom);
	}

	//	turn off the borders
	if(top){ node.style.borderTopWidth = "0px"; }
	if(bottom){ node.style.borderBottomWidth = "0px"; }

	//	do the corners
	var corners = ["tr", "tl", "br", "bl"];
	for(var i=0; i<corners.length; i++){
		var cc=corners[i];
		if(options.radii[cc]==0){
			//	fill up the space with a div.
			if((cc.charAt(0)=="t"&&top) || (cc.charAt(0)=="b"&&bottom)){
				var corner=document.createElement("div");
				corner.style.position="relative";
				corner.style.fontSize="1px;";
				corner.style.overflow="hidden";
				if(format.bgImage==""){
					corner.style.backgroundColor=format.color;
				} else {
					corner.style.backgroundImage=format.bgImage;
				}
				switch(cc){
					case "tl":{
						corner.style.height=topHeight-format.borderWidth+"px";
						corner.style.marginRight=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderLeft=format.borderString;
						corner.style.borderTop=format.borderString;
						corner.style.left=-format.borderWidth+"px";
						break;
					}
					case "tr":{
						corner.style.height=topHeight-format.borderWidth+"px";
						corner.style.marginLeft=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderRight=format.borderString;
						corner.style.borderTop=format.borderString;
						corner.style.backgroundPosition="-"+(topHeight-format.borderWidth)+"px 0px";
						corner.style.left=format.borderWidth+"px";
						break;
					}
					case "bl":{
						corner.style.height=bottomHeight-format.borderWidth+"px";
						corner.style.marginRight=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderLeft=format.borderString;
						corner.style.borderBottom=format.borderString;
						corner.style.left=format.borderWidth+"px";
						corner.style.backgroundPosition="-"+format.borderWidth+"px -"+(format.height+(bottomHeight+format.borderWidth))+"px";
						break;
					}
					case "br":{
						corner.style.height=bottomHeight-format.borderWidth+"px";
						corner.style.marginLeft=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderRight=format.borderString;
						corner.style.borderBottom=format.borderString;
						corner.style.left=format.borderWidth+"px";
						corner.style.backgroundPosition="-"+(bottomHeight+format.borderWidth)+"px -"+(format.height+(bottomHeight+format.borderWidth))+"px";
						break;
					}
				}
			}
		} else {
			//	NB: this version will not do the caching they built into the
			//		current version of curvyCorners.
			var corner=document.createElement("div");
			corner.style.height=options.radii[cc]+"px";
			corner.style.width=options.radii[cc]+"px";
			corner.style.position="absolute";
			corner.style.fontSize="1px";
			corner.style.overflow="hidden";

			var borderRadius=Math.floor(options.radii[cc] - format.borderWidth);
			for(var x=0, j=options.radii[cc]; x<j; x++){
				//	figure out y coords
				var y1=Math.floor(Math.sqrt(Math.pow(borderRadius,2)-Math.pow((x+1),2)))-1;
				if((x+1) >= borderRadius){ var y1=-1; }
				var y2=Math.ceil(Math.sqrt(Math.pow(borderRadius,2)-Math.pow(x,2)));
				if(x >= borderRadius){ y2=-1; }
				var y3=Math.floor(Math.sqrt(Math.pow(j,2)-Math.pow((x+1),2)))-1;
				if((x+1) >= j){ y3=-1; }
				var y4=Math.ceil(Math.sqrt(Math.pow(j, 2)-Math.pow(x, 2)));
				if(x >= j){ y4=-1; }

				//	start drawing
				if(y1 > -1){
					fns.draw(x, 0, format.color, 100, (y1+1), corner, -1, j, topHeight, format);
				}

				// cycle the y-axis
				for(var y=(y1+1); y<y2; y++){
					if(options.antiAlias){
						if(format.bgImage != ""){
							var fract=fns.fraction(x, y, borderRadius)*100;
							if(fract < 30){
								fns.draw(x, y, format.borderColor, 100, 1, corner, 0, options.radii[cc], topHeight, format);
							} else {
								fns.draw(x, y, format.borderColor, 100, 1, corner, -1, options.radii[cc], topHeight, format);
							}
						} else {
							var clr=fns.blend(format.color, format.borderColor, fns.fraction(x, y, borderRadius));
							fns.draw(x, y, clr, 100, 1, corner, 0, options.radii[cc], topHeight, format);
						}
					}
				}

				//	bar for the border
				if(options.antiAlias){
					if(y3 >= y2){
						if(y2 == -1){ y2 = 0; }
						fns.draw(x, y2, format.borderColor, 100, (y3-y2+1), corner, 0, 0, topHeight, format)
					} else {
						if(y3 >= y1){
							fns.draw(x, (y1+1), format.borderColor, 100, (y3-y1), corner, 0, 0, topHeight, format);
						}
					}
					for(var y=(y3+1); y<y4; y++){
						fns.draw(x, y, format.borderColor, (fns.fraction(x, y, j)*100), 1, corner, (format.borderWidth>0 ? 0:-1), options.radii[cc], topHeight, format);
					}
				} else {
					y3=y1;
				}
			}

			//	reposition pixels if not the bottom right.
			if(cc != "br"){
				for(var t=0, k=corner.childNodes.length; t<k; t++){
					var bar=corner.childNodes[t];
					var barTop = parseInt(dojo.html.getComputedStyle(bar, "top"));
					var barLeft = parseInt(dojo.html.getComputedStyle(bar, "left"));
					var barHeight = parseInt(dojo.html.getComputedStyle(bar, "height"));

					//	reposition.
					if(cc.charAt(1)=="l"){ 
						bar.style.left = (options.radii[cc]-barLeft-1)+"px"; 
					}
					if(cc=="tr"){
						bar.style.top = (options.radii[cc]-barHeight-barTop)+"px";
						bar.style.backgroundPosition="-"+Math.abs((format.width-options.radii[cc]+format.borderWidth)+barLeft)
							+"px -"+Math.abs(options.radii[cc]-barHeight-barTop-format.borderWidth)+"px";
					} else if (cc=="tl"){
						bar.style.top = (options.radii[cc]-barHeight-barTop)+"px";
						bar.style.backgroundPosition="-"+Math.abs((options.radii[cc]-barLeft-1)-format.borderWidth)
							+"px -"+Math.abs(options.radii[cc]-barHeight-barTop-format.borderWidth)+"px";
					} else {
						bar.style.backgroundPosition="-"+Math.abs((options.radii[cc]+barLeft)+format.borderWidth)
							+"px -"+Math.abs((format.height+options.radii[cc]+barTop)-format.borderWidth)+"px";
					}
				}
			}
		}

		if(corner){
			//	position the container.
			var psn=[];
			if(cc.charAt(0)=="t"){ psn.push("top"); }
			else { psn.push("bottom"); }
			if(cc.charAt(1)=="l"){ psn.push("left"); }
			else { psn.push("right"); }
			
			if(corner.style.position=="absolute"){
				for(var z=0; z<psn.length; z++){ corner.style[psn[z]]="0px"; }
			}
			
			if(psn[0]=="top"){ 
				if(top){ top.appendChild(corner); }
			} else {
				if(bottom){ bottom.appendChild(corner); }
			}
		}
	}

	//	draw fillers.
	var diff={ 
		t: Math.abs(options.radii.tl - options.radii.tr),
		b: Math.abs(options.radii.bl - options.radii.br)
	};
	for(var z in diff){
		var smaller=(options.radii[z+"l"]<options.radii[z+"r"] ? z+"l":z+"r");
		var filler=document.createElement("div");
		filler.style.height=diff[z]+"px";
		filler.style.width=options.radii[smaller]+"px";
		filler.style.position="absolute";
		filler.style.fontSize="1px";
		filler.style.overflow="hidden";
		filler.style.backgroundColor=format.color;
		switch(smaller){
			case "tl":{
				filler.style.bottom="0px";
				filler.style.left="0px";
				filler.style.borderLeft=format.borderString;
				top.appendChild(filler);
				break;
			}
			case "tr":{
				filler.style.bottom="0px";
				filler.style.right="0px";
				filler.style.borderRight=format.borderString;
				top.appendChild(filler);
				break;
			}
			case "bl":{
				filler.style.top="0px";
				filler.style.left="0px";
				filler.style.borderLeft=format.borderString;
				bottom.appendChild(filler);
				break;
			}
			case "br":{
				filler.style.top="0px";
				filler.style.right="0px";
				filler.style.borderRight=format.borderString;
				bottom.appendChild(filler);
				break;
			}
		}

		var fillBar=document.createElement("div");
		fillBar.style.position="relative";
		fillBar.style.fontSize="1px";
		fillBar.style.overflow="hidden";
		fillBar.style.backgroundColor=format.color;
		fillBar.style.backgroundImage=format.bgImage;
		if(z=="t"){
			if(top){
				if(options.radii.tl && options.radii.tr){
					fillBar.style.height=(topHeight-format.borderWidth) + "px";
					fillBar.style.marginLeft=(options.radii.tl-format.borderWidth)+"px";
					fillBar.style.marginRight=(options.radii.tr-format.borderWidth)+"px";
					fillBar.style.borderTop=format.borderString;
					if(format.bgImage!=""){
						fillBar.style.backgroundPosition="-"+(topHeight+format.borderWidth)+"px 0px";
					}
				}
				top.appendChild(fillBar);
			}
		} else {
			if(bottom){
				if(options.radii.bl && options.radii.br){
					fillBar.style.height=(bottomHeight-format.borderWidth) + "px";
					fillBar.style.marginLeft=(options.radii.bl-format.borderWidth)+"px";
					fillBar.style.marginRight=(options.radii.br-format.borderWidth)+"px";
					fillBar.style.borderBottom=format.borderString;
					if(format.bgImage!=""){
						fillBar.style.backgroundPosition="-"+(bottomHeight+format.borderWidth)+"px -"
							+ (format.height + (topHeight+format.borderWidth))+"px";
					}
				}
				bottom.appendChild(fillBar);
			}
		}
	}

	//	finally, set up the padding.
	if(options.autoPad && format.padding>0){
		var content=document.createElement("div");
		content.style.position="relative";
		content.innerHTML=format.content;
		content.className="autoPadDiv";
		if(topHeight < format.padding){
			content.style.paddingTop = Math.abs(topHeight-format.padding)+"px";
		}
		if(bottomHeight < format.padding){
			content.style.paddingBottom = Math.abs(bottomHeight-format.padding)+"px";
		}
		content.style.paddingLeft=format.padding+"px";
		content.style.paddingRight=format.padding+"px";
		node.appendChild(content);
	}
};

var count=0;

//	helper methods.
dojo.lfx.rounded._fns={
	blend:function(clr1, clr2, frac){
		var c1={
			r:parseInt(clr1.substr(1,2),16),
			g:parseInt(clr1.substr(3,2),16),
			b:parseInt(clr1.substr(5,2),16)
		};
		var c2={
			r:parseInt(clr2.substr(1,2),16),
			g:parseInt(clr2.substr(3,2),16),
			b:parseInt(clr2.substr(5,2),16)
		};
		if(frac>1||frac<0){ frac=1; }
		var ret=[
			Math.min(Math.max(Math.round((c1.r*frac)+(c2.r*(1-frac))),0),255),
			Math.min(Math.max(Math.round((c1.g*frac)+(c2.g*(1-frac))),0),255),
			Math.min(Math.max(Math.round((c1.b*frac)+(c2.b*(1-frac))),0),255)
		];
		for(var i=0; i<ret.length; i++){
			var n=ret[i].toString(16);
			if(n.length<2){ n="0"+n; }
			ret[i]=n;
		}
		return "#"+ret.join("");
	},
	fraction:function(x, y, r){
		var frac=0;
		var xval=[];
		var yval=[];
		var point=0;
		var whatsides="";

		var intersect=Math.sqrt((Math.pow(r,2)-Math.pow(x,2)));
		if(intersect >=y && intersect < (y+1)){
			whatsides="Left";
			xval[point]=0;
			yval[point++]=intersect-y;
		}

		intersect=Math.sqrt((Math.pow(r,2)-Math.pow(y+1,2)));
		if(intersect >=x && intersect < (x+1)){
			whatsides += "Top";
			xval[point]=intersect-x;
			yval[point++]=1;
		}
		
		intersect=Math.sqrt((Math.pow(r,2)-Math.pow(x+1,2)));
		if(intersect >= y && intersect < (y+1)){
			whatsides += "Right";
			xval[point]=1;
			yval[point++] = intersect-y;
		}

		intersect=Math.sqrt((Math.pow(r,2)-Math.pow(y,2)));
		if(intersect >=x && intersect < (x+1)){
			whatsides += "Bottom";
			xval[point]=intersect-x;
			yval[point]=1;
		}

		switch(whatsides){
			case "LeftRight":
				return Math.min(yval[0],yval[1]) + ((Math.max(yval[0],yval[1])-Math.min(yval[0],yval[1]))/2);
			case "TopRight":
				return 1-(((1-xval[0])*(1-yval[1]))/2);
			case "TopBottom":
				return Math.min(xval[0],xval[1]) + ((Math.max(xval[0],xval[1])-Math.min(xval[0],xval[1]))/2);
			case "LeftBottom":
				return (yval[0]*xval[1])/2;
			default: return 1;
		}
	},
	draw:function(x, y, color, opac, height, corner, image, radius, top, format){
		var px=document.createElement("div");
		px.style.height=height+"px"
		px.style.width="1px";
		px.style.position="absolute";
		px.style.fontSize="1px";
		px.style.overflow="hidden";
		if(image==-1 && format.bgImage!=""){
			px.style.backgroundImage=format.bgImage;
			px.style.backgroundPosition="-"+(format.width-(radius-x)+format.borderWidth)
				+"px -"+((format.height+top+y)-format.borderWidth)+"px";
		} else { 
			px.style.backgroundColor=color; 
		}
		if(opac!=100){ dojo.html.setOpacity(px, (opac/100)); }
		px.style.top=y+"px";
		px.style.left=x+"px";
		corner.appendChild(px);
	},
	getRGB:function(clr){
		var ret="#ffffff";
		if(clr!="" && clr!="transparent"){
			if(clr.substr(0,3)=="rgb"){
				var t=clr.substring(4, clr.indexOf(")"));
				t=t.split(",");
				for(var i=0; i<t.length; i++){
					var n=parseInt(t[i]).toString(16);
					if(n.length<2){ n = "0"+n; }
					t[i]=n;
				}
				ret = "#"+t.join("");
			}
			else if(clr.length==4){
				ret = "#"+clr.substring(1,2)+clr.substring(1,2)
					+ clr.substring(2,3)+clr.substring(2,3)
					+ clr.substring(3,4)+clr.substring(3,4);
			}
			else {
				ret = clr;
			}
		}
		return ret;
	}
};

__CPAN_FILE__ src/lfx/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	browser: ["dojo.lfx.html"],
	dashboard: ["dojo.lfx.html"]
});
dojo.provide("dojo.lfx.*");
__CPAN_FILE__ src/lfx/shadow.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lfx.shadow");

dojo.require("dojo.lang.common");
dojo.require("dojo.uri.Uri");

dojo.lfx.shadow = function(/* HTMLElement */node) {
	//	summary
	//	creates a shadow underneath node.
	this.shadowPng = dojo.uri.dojoUri("src/html/images/shadow");
	this.shadowThickness = 8;
	this.shadowOffset = 15;
	this.init(node);
}

dojo.extend(dojo.lfx.shadow, {
	init: function(/* HTMLElement */node){
		//	summary
		//	Initializes the shadow.
		this.node=node;

		// make all the pieces of the shadow, and position/size them as much
		// as possible (but a lot of the coordinates are set in sizeShadow
		this.pieces={};
		var x1 = -1 * this.shadowThickness;
		var y0 = this.shadowOffset;
		var y1 = this.shadowOffset + this.shadowThickness;
		this._makePiece("tl", "top", y0, "left", x1);
		this._makePiece("l", "top", y1, "left", x1, "scale");
		this._makePiece("tr", "top", y0, "left", 0);
		this._makePiece("r", "top", y1, "left", 0, "scale");
		this._makePiece("bl", "top", 0, "left", x1);
		this._makePiece("b", "top", 0, "left", 0, "crop");
		this._makePiece("br", "top", 0, "left", 0);
	},

	_makePiece: function(name, vertAttach, vertCoord, horzAttach, horzCoord, sizing){
		var img;
		var url = this.shadowPng + name.toUpperCase() + ".png";
		if(dojo.render.html.ie55 || dojo.render.html.ie60){
			img=dojo.doc().createElement("div");
			img.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"'"+
			(sizing?", sizingMethod='"+sizing+"'":"") + ")";
		}else{
			img=dojo.doc().createElement("img");
			img.src=url;
		}
		img.style.position="absolute";
		img.style[vertAttach]=vertCoord+"px";
		img.style[horzAttach]=horzCoord+"px";
		img.style.width=this.shadowThickness+"px";
		img.style.height=this.shadowThickness+"px";
		this.pieces[name]=img;
		this.node.appendChild(img);
	},

	size: function(/* int */width, /* int */height){
		//	summary
		//	Resizes the shadow based on width and height.
		var sideHeight = height - (this.shadowOffset+this.shadowThickness+1);
		if (sideHeight < 0) { sideHeight = 0; }
		if (height < 1) { height = 1; }
		if (width < 1) { width = 1; }
		with(this.pieces){
			l.style.height = sideHeight+"px";
			r.style.height = sideHeight+"px";
			b.style.width = (width-1)+"px";
			bl.style.top = (height-1)+"px";
			b.style.top = (height-1)+"px";
			br.style.top = (height-1)+"px";
			tr.style.left = (width-1)+"px";
			r.style.left = (width-1)+"px";
			br.style.left = (width-1)+"px";
		}
	}
});


__CPAN_FILE__ src/lfx/toggle.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lfx.toggle");
dojo.require("dojo.lfx.*");

dojo.lfx.toggle.plain = {
	show: function(node, duration, easing, callback){
		dojo.html.show(node);
		if(dojo.lang.isFunction(callback)){ callback(); }
	},
	
	hide: function(node, duration, easing, callback){
		dojo.html.hide(node);
		if(dojo.lang.isFunction(callback)){ callback(); }
	}
}

dojo.lfx.toggle.fade = {
	show: function(node, duration, easing, callback){
		dojo.lfx.fadeShow(node, duration, easing, callback).play();
	},

	hide: function(node, duration, easing, callback){
		dojo.lfx.fadeHide(node, duration, easing, callback).play();
	}
}

dojo.lfx.toggle.wipe = {
	show: function(node, duration, easing, callback){
		dojo.lfx.wipeIn(node, duration, easing, callback).play();
	},

	hide: function(node, duration, easing, callback){
		dojo.lfx.wipeOut(node, duration, easing, callback).play();
	}
}

dojo.lfx.toggle.explode = {
	show: function(node, duration, easing, callback, explodeSrc){
		dojo.lfx.explode(explodeSrc||{x:0,y:0,width:0,height:0}, node, duration, easing, callback).play();
	},

	hide: function(node, duration, easing, callback, explodeSrc){
		dojo.lfx.implode(node, explodeSrc||{x:0,y:0,width:0,height:0}, duration, easing, callback).play();
	}
}

__CPAN_FILE__ src/lfx/extras.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lfx.extras");

dojo.require("dojo.lfx.html");
dojo.require("dojo.lfx.Animation");

dojo.lfx.html.fadeWipeIn = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will fade "nodes" from its current
	//			opacity to fully opaque while wiping it in.
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anim = dojo.lfx.combine(
		dojo.lfx.fadeIn(nodes, duration, easing),
		dojo.lfx.wipeIn(nodes, duration, easing)
	);
	
	if(callback){
		anim.connect("onEnd", function(){
			callback(nodes, anim);
		});
	}
	
	return anim; // dojo.lfx.Combine
}

dojo.lfx.html.fadeWipeOut = function(/*DOMNode[]*/ nodes, /*int?*/ duration, /*Function?*/ easing, /*Function?*/ callback){
	// summary: Returns an animation that will fade "nodes" from its current
	//			opacity to fully transparent while wiping it out.
	// nodes: An array of DOMNodes or one DOMNode.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anim = dojo.lfx.combine(
		dojo.lfx.fadeOut(nodes, duration, easing),
		dojo.lfx.wipeOut(nodes, duration, easing)
	);
	
	if(callback){
		/* callback: Function
		   pId: f */
		anim.connect("onEnd", function(){
			callback(nodes, anim);
		});
	}

	return anim; // dojo.lfx.Combine
}

dojo.lfx.html.scale = function(/*DOMNode[]*/nodes,
							   /*int*/ percentage,
							   /*bool?*/ scaleContent,
							   /*bool?*/ fromCenter,
							   /*int?*/ duration,
							   /*Function?*/ easing,
							   /*Function?*/ callback){
	// summary: Returns an animation that will scale "nodes" by "percentage".
	// nodes: An array of DOMNodes or one DOMNode.
	// percentage: A whole number representing the percentage to scale "nodes".
	// scaleContent: If true, will scale the contents of "nodes".
	// fromCenter: If true, will scale "nodes" from its center rather than the
	//			   lower right corner.
	// duration: Duration of the animation in milliseconds.
	// easing: An easing function.
	// callback: Function to run at the end of the animation.
	nodes = dojo.lfx.html._byId(nodes);
	var anims = [];

	dojo.lang.forEach(nodes, function(node){
		var outer = dojo.html.getMarginBox(node);

		var actualPct = percentage/100.0;
		var props = [
			{	property: "width",
				start: outer.width,
				end: outer.width * actualPct
			},
			{	property: "height",
				start: outer.height,
				end: outer.height * actualPct
			}];
		
		if(scaleContent){
			var fontSize = dojo.html.getStyle(node, 'font-size');
			var fontSizeType = null;
			if(!fontSize){
				fontSize = parseFloat('100%');
				fontSizeType = '%';
			}else{
				dojo.lang.some(['em','px','%'], function(item, index, arr){
					if(fontSize.indexOf(item)>0){
						fontSize = parseFloat(fontSize);
						fontSizeType = item;
						return true;
					}
				});
			}
			props.push({
				property: "font-size",
				start: fontSize,
				end: fontSize * actualPct,
				units: fontSizeType });
		}
		
		if(fromCenter){
			var positioning = dojo.html.getStyle(node, "position");
			var originalTop = node.offsetTop;
			var originalLeft = node.offsetLeft;
			var endTop = ((outer.height * actualPct) - outer.height)/2;
			var endLeft = ((outer.width * actualPct) - outer.width)/2;
			props.push({
				property: "top",
				start: originalTop,
				end: (positioning == "absolute" ? originalTop - endTop : (-1*endTop))
			});
			props.push({
				property: "left",
				start: originalLeft,
				end: (positioning == "absolute" ? originalLeft - endLeft : (-1*endLeft))
			});
		}
		
		var anim = dojo.lfx.propertyAnimation(node, props, duration, easing);
		if(callback){
			anim.connect("onEnd", function(){
				callback(node, anim);
			});
		}

		anims.push(anim);
	});
	
	return dojo.lfx.combine(anims); // dojo.lfx.Combine
}

dojo.lang.mixin(dojo.lfx, dojo.lfx.html);

__CPAN_DIR__ src/i18n
__CPAN_FILE__ src/i18n/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.i18n.common");

dojo.i18n.getLocalization = function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){
//	summary:
//		Returns an Object containing the localization for a given resource bundle
//		in a package, matching the specified locale.
//
//	description:
//		Returns a hash containing name/value pairs in its prototypesuch that values can be easily overridden.
//		Throws an exception if the bundle is not found.
//		Bundle must have already been loaded by dojo.requireLocalization() or by a build optimization step.
//
//	packageName: package which is associated with this resource
//	bundleName: the base filename of the resource bundle (without the ".js" suffix)
//	locale: the variant to load (optional).  By default, the locale defined by the
//		host environment: dojo.locale

	dojo.hostenv.preloadLocalizations();
	locale = dojo.hostenv.normalizeLocale(locale);

	// look for nearest locale match
	var elements = locale.split('-');
	var module = [packageName,"nls",bundleName].join('.');
	var bundle = dojo.hostenv.findModule(module, true);

	var localization;
	for(var i = elements.length; i > 0; i--){
		var loc = elements.slice(0, i).join('_');
		if(bundle[loc]){
			localization = bundle[loc];
			break;
		}
	}
	if(!localization){
		localization = bundle.ROOT;
	}

	// make a singleton prototype so that the caller won't accidentally change the values globally
	if(localization){
		var clazz = function(){};
		clazz.prototype = localization;
		return new clazz(); // Object
	}

	dojo.raise("Bundle not found: " + bundleName + " in " + packageName+" , locale=" + locale);
};

dojo.i18n.isLTR = function(/*String?*/locale){
//	summary:
//		Is the language read left-to-right?  Most exceptions are for middle eastern languages.
//
//	locale: a string representing the locale.  By default, the locale defined by the
//		host environment: dojo.locale

	var lang = dojo.hostenv.normalizeLocale(locale).split('-')[0];
	var RTL = {ar:true,fa:true,he:true,ur:true,yi:true};
	return !RTL[lang]; // Boolean
};

__CPAN_FILE__ src/i18n/currency.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.i18n.currency");

dojo.require("dojo.experimental");
dojo.experimental("dojo.i18n.currency");

dojo.require("dojo.regexp");
dojo.require("dojo.i18n.common");
dojo.require("dojo.i18n.number");
dojo.require("dojo.lang.common");

/**
* Method to Format and validate a given number a monetary value
*
* @param Number value
*	The number to be formatted and validated.
* @param String iso the ISO 4217 currency code
* @param Object flags
*   flags.places The number of decimal places to be included in the formatted number
* @param String locale the locale to determine formatting used.  By default, the locale defined by the
*   host environment: dojo.locale
* @return String
* 	the formatted currency of type String if successful; Nan if an
* 	invalid currency is provided or null if an unsupported locale value was provided.
**/
dojo.i18n.currency.format = function(value, iso, flags /*optional*/, locale /*optional*/){
	flags = (typeof flags == "object") ? flags : {};

	var formatData = dojo.i18n.currency._mapToLocalizedFormatData(dojo.i18n.currency.FORMAT_TABLE, iso, locale);
	if (typeof flags.places == "undefined") {flags.places = formatData.places;}
	if (typeof flags.places == "undefined") {flags.places = 2;}
	flags.signed = false;

	var result = dojo.i18n.number.format(value, flags, locale);

	var sym = formatData.symbol;
	if (formatData.adjSpace == "symbol"){ 
		if (formatData.placement == "after"){
			sym = " " + sym;// TODO: nbsp?
		}else{
			sym = sym + " ";// TODO: nbsp?
		}
	}

	if (value < 0){
		if (formatData.signPlacement == "before"){
			sym = "-" + sym;
		}else if (formatData.signPlacement == "after"){
			sym = sym + "-";
		}
	}

	var spc = (formatData.adjSpace == "number") ? " " : ""; // TODO: nbsp?
	if (formatData.placement == "after"){
		result = result + spc + sym;
	}else{
		result = sym + spc + result;
	}

	if (value < 0){
		if (formatData.signPlacement == "around"){
			result = "(" + result + ")";
		}else if (formatData.signPlacement == "end"){
			result = result + "-";
		}else if (!formatData.signPlacement || formatData.signPlacement == "begin"){
			result = "-" + result;
		}
	}

	return result;
};

/**
* Method to convert a properly formatted monetary value to a primative numeric value.
*
* @param String value
*	The int string to be convertted
  @param String iso the ISO 4217 currency code
* @param String locale the locale to determine formatting used.  By default, the locale defined by the
*   host environment: dojo.locale
* @param Object flags
*   flags.validate true to check the string for strict adherence to the locale settings for separator, sign, etc.
*     Default is true
* @return Number
* 	Returns a primative numeric value, Number.NaN if unable to convert to a number, or null if an unsupported locale is provided.
**/
dojo.i18n.currency.parse = function(value, iso, locale, flags /*optional*/){
	if (typeof flags.validate == "undefined") {flags.validate = true;}

	if (flags.validate && !dojo.i18n.number.isCurrency(value, iso, locale, flags)) {
		return Number.NaN;
	}

	var sign = (value.indexOf('-') != -1);
	var abs = abs.replace(/\-/, "");

	var formatData = dojo.i18n.currency._mapToLocalizedFormatData(dojo.i18n.currency.FORMAT_TABLE, iso, locale);
	abs = abs.replace(new RegExp("\\" + formatData.symbol), "");
	//TODO: trim?

	var number = dojo.i18n.number.parse(abs, locale, flags);
	if (sign){number = number * -1;}
	return number;
};

/**
  Validates whether a string denotes a monetary value. 

  @param value  A string
  @param iso the ISO 4217 currency code
  @param locale the locale to determine formatting used.  By default, the locale defined by the
    host environment: dojo.locale
  @param flags  An object
    flags.symbol  A currency symbol such as Yen "ï¿½", Pound "ï¿½", or the Euro sign "ï¿½".  
        The default is specified by the iso code.  For more than one symbol use an array, e.g. ["$", ""], makes $ optional.
        The empty array [] makes the default currency symbol optional.
    flags.placement  The symbol can come "before" or "after".  The default is specified by the iso code.
    flags.signed  The leading plus-or-minus sign.  Can be true, false, or [true, false].
      Default is [true, false], (i.e. sign is optional).
    flags.signPlacement  The sign can come "before" or "after" the symbol or "around" the whole expression
    	with parenthesis, such as CAD: (123$).  The default is specified by the iso code.
    flags.separator  The character used as the thousands separator. The default is specified by the locale.
        The empty array [] makes the default separator optional.
    flags.fractional  The appropriate number of decimal places for fractional currency (e.g. cents)
      Can be true, false, or [true, false].  Default is [true, false], (i.e. cents are optional).
    flags.places  The integer number of decimal places.
      If not given, an amount appropriate to the iso code is used.
    flags.fractional  The appropriate number of decimal places for fractional currency (e.g. cents)
      Can be true, false, or [true, false].  Default is [true, false], (i.e. cents are optional).
    flags.decimal  The character used for the decimal point.  The default is specified by the locale.
  @return  true or false.
*/
dojo.i18n.currency.isCurrency = function(value, iso, locale /*optional*/, flags){
	flags = (typeof flags == "object") ? flags : {};

	var numberFormatData = dojo.i18n.number._mapToLocalizedFormatData(dojo.i18n.number.FORMAT_TABLE, locale);
	if (typeof flags.separator == "undefined") {flags.separator = numberFormatData[0];}
	else if (dojo.lang.isArray(flags.separator) && flags.separator.length == 0){flags.separator = [numberFormatData[0],""];}
	if (typeof flags.decimal == "undefined") {flags.decimal = numberFormatData[2];}
	if (typeof flags.groupSize == "undefined") {flags.groupSize = numberFormatData[3];}
	if (typeof flags.groupSize2 == "undefined") {flags.groupSize2 = numberFormatData[4];}

	var formatData = dojo.i18n.currency._mapToLocalizedFormatData(dojo.i18n.currency.FORMAT_TABLE, iso, locale);
	if (typeof flags.places == "undefined") {flags.places = formatData.places;}
	if (typeof flags.places == "undefined") {flags.places = 2;}
	if (typeof flags.symbol == "undefined") {flags.symbol = formatData.symbol;}
	else if (dojo.lang.isArray(flags.symbol) && flags.symbol.length == 0){flags.symbol = [formatData.symbol,""];}
	if (typeof flags.placement == "undefined") {flags.placement = formatData.placement;}
	//TODO more... or mixin?

	var re = new RegExp("^" + dojo.regexp.currency(flags) + "$");
//dojo.debug(value+":"+dojo.regexp.currency(flags)+"="+re.test(value));
	return re.test(value);
};

dojo.i18n.currency._mapToLocalizedFormatData = function(table, iso, locale /*optional*/){
	var formatData = dojo.i18n.currency.FORMAT_TABLE[iso];
	if (!dojo.lang.isArray(formatData)){
		return formatData;
	}

	return dojo.i18n.number._mapToLocalizedFormatData(formatData[0], locale);
};

(function() {
	var arabic = {symbol: "\u062C", placement: "after", htmlSymbol: "?"};
	var euro = {symbol: "\u20AC", placement: "before", adjSpace: "symbol", htmlSymbol: "&euro;"};
	var euroAfter = {symbol: "\u20AC", placement: "after", htmlSymbol: "&euro;"};

//Q: Do European countries still use their old ISO symbols instead of just EUR?
//Q: are signPlacement and currency symbol placement ISO-dependent or are they really locale-dependent?
//TODO: htmlSymbol is for html entities, need images? (IBM: why? why can't we just use unicode everywhere?)
//TODO: hide visibility of this table?
//for html entities, need a image for arabic symbol "BHD" as "DZD", "EGP", "JOD", "KWD" "LBP", "MAD", "OMR", "QAR", "SAR", "SYP", "TND", "AED", "YER"
//Note: html entities not used at the moment
//placement: placement of currency symbol, before or after number
//signPlacement: placement of negative sign, before or after symbol, or begin or end of expression, or around with parentheses
// This table assumes defaults of
//	places: 2, placement: "before", signPlacement: "begin", adjSpace: undefined, htmlSymbol: undefined]
dojo.i18n.currency.FORMAT_TABLE = {
	AED: {symbol: "\u062c", placement: "after"},
	ARS: {symbol: "$", signPlacement: "after"},
	//Old ATS: {symbol: "S", adjSpace: "symbol"},
	ATS: {symbol: "\u20AC", adjSpace: "number", signPlacement: "after", htmlSymbol: "&euro;"}, 	//Austria using "EUR" // neg should read euro + sign + space + number
	AUD: {symbol: "$"},
	BOB: {symbol: "$b"},
	BRL: {symbol: "R$", adjSpace: "symbol"},
	//Old BEF: {symbol: "BF", placement: "after", adjSpace: "symbol"},
	BEF: euroAfter,	//Belgium using "EUR"
	//Old BHD: {symbol: "\u062C", signPlacement: "end", places: 3, htmlSymbol: "?"},
	BHD: arabic,
	//TODO: I'm suspicious that all the other entries have locale-specific data in them, too?
	//Q: which attributes are iso-specific and which are locale specific?
	CAD: [{
			'*' : {symbol: "$"},
			'fr-ca' : {symbol: "$", placement: "after", signPlacement: "around"}
		}],
	CHF: {symbol: "CHF", adjSpace: "symbol", signPlacement: "after"},
	CLP: {symbol: "$"},
	COP: {symbol: "$", signPlacement: "around"},
	CNY: {symbol: "\u00A5", htmlSymbol: "&yen;"},
	//// Costa Rica  - Spanish slashed C. need to find out the html entity image
	CRC: {symbol: "\u20A1", signPlacement: "after", htmlSymbol: "?"},
	// Czech Republic  - Czech //need image for html entities
	CZK: {symbol: "Kc", adjSpace: "symbol", signPlacement: "after"},
	DEM: euroAfter,
	DKK: {symbol: "kr.", adjSpace: "symbol", signPlacement: "after"},
	DOP: {symbol: "$"},
	//for html entities, need a image, bidi, using "rtl", so from the link, symbol is suffix
	//Old DZD: {symbol: "\u062C", signPlacement: "end", places: 3, htmlSymbol: "?"},
	DZD: arabic,
	//Ecuador using "USD"
	ECS: {symbol: "$", signPlacement: "after"},
	EGP: arabic,
	//Old ESP: {symbol: "Pts", placement: "after", adjSpace: "symbol", places: 0},
	ESP: euroAfter,	//spain using "EUR"
	EUR: euro,
	//Old FIM: {symbol: "mk", placement: "after", adjSpace: "symbol"},
	FIM: euroAfter,	//Finland using "EUR"
	//Old FRF: {symbol: "F", placement: "after", adjSpace: "symbol"},
	FRF: euroAfter,	//France using "EUR"
	GBP: {symbol: "\u00A3", htmlSymbol: "&pound;"},
	GRD: {symbol: "\u20AC", signPlacement: "end", htmlSymbol: "&euro;"},
	GTQ: {symbol: "Q", signPlacement: "after"},
	//Hong Kong need "HK$" and "$". Now only support "HK$"
	HKD: {symbol: "HK$"},
	HNL: {symbol: "L.", signPlacement: "end"},
	HUF: {symbol: "Ft", placement: "after", adjSpace: "symbol"},
	//IEP: {symbol: "\u00A3", htmlSymbol: "&pound;"},
	IEP: {symbol: "\u20AC", htmlSymbol: "&euro;"},	//ireland using "EUR" at the front.
	//couldn't know what Israel - Hebrew symbol, some sites use "NIS", bidi, using "rtl", so from the link, symbol is suffix (IBM: huh?)
	//ILS: {symbol: "\u05E9\u0022\u05D7", signPlacement: "end", htmlSymbol: "?"},
	ILS: {symbol: "\u05E9\u0022\u05D7", placement: "after", htmlSymbol: "?"},
	INR: {symbol: "Rs."},
	//ITL: {symbol: "L", adjSpace: "symbol", signPlacement: "after", places: 0},
	ITL: {symbol: "\u20AC", signPlacement: "after", htmlSymbol: "&euro;"},	//Italy using "EUR"
	JOD: arabic,
	JPY: {symbol: "\u00a5", places: 0, htmlSymbol: "&yen;"},
	KRW: {symbol: "\u20A9", places: 0, htmlSymbol: "?"},
	KWD: arabic,
	LBP: arabic,
	//Old LUF: {symbol: "LUF", placement: "after", adjSpace: "symbol"},
	//for Luxembourg,using "EUR"
	LUF: euroAfter,
	MAD: arabic,
	MXN: {symbol: "$", signPlacement: "around"},
	NIO: {symbol: "C$", adjSpace: "symbol", signPlacement: "after"},
	//Old NLG: {symbol: "f", adjSpace: "symbol", signPlacement: "end"},
	//Netherlands, using "EUR"
	NLG: {symbol: "\u20AC", signPlacement: "end", htmlSymbol: "&euro;"},
	NOK: {symbol: "kr", adjSpace: "symbol", signPlacement: "after"},
	NZD: {symbol: "$"},
	OMR: arabic,
	PAB: {symbol: "B/", adjSpace: "symbol", signPlacement: "after"},
	PEN: {symbol: "S/", signPlacement: "after"},
	//couldn't know what the symbol is from ibm link. (IBM: what does this mean?  Is the symbol 'z' wrong?)
	PLN: {symbol: "z", placement: "after"},
	//Old PTE: {symbol: "Esc.", placement: "after", adjSpace: "symbol", places: 0},
	PTE: euroAfter,
	PYG: {symbol: "Gs.", signPlacement: "after"},
	QAR: arabic,
	RUR: {symbol: "rub.", placement: "after"},
	SAR: arabic,
	SEK: {symbol: "kr", placement: "after", adjSpace: "symbol"},
	SGD: {symbol: "$"},
	//// El Salvador - Spanish slashed C. need to find out. (IBM: need to find out what?)
	SVC: {symbol: "\u20A1", signPlacement: "after", adjSpace: "symbol"},
	//for html entities, need a image
	SYP: arabic,
	TND: arabic,
	TRL: {symbol: "TL", placement: "after"},
	TWD: {symbol: "NT$"},
	USD: {symbol: "$"},
	UYU: {symbol: "$U", signplacement: "after", adjSpace: "symbol"},
	VEB: {symbol: "Bs", signplacement: "after", adjSpace: "symbol"},
	YER: arabic,
	ZAR: {symbol: "R", signPlacement: "around"}
};

})();

__CPAN_FILE__ src/i18n/number.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.i18n.number");

dojo.require("dojo.experimental");
dojo.experimental("dojo.i18n.number");

dojo.require("dojo.regexp");
dojo.require("dojo.i18n.common");
dojo.require("dojo.lang.common");

/**
* Method to Format and validate a given number
*
* @param Number value
*	The number to be formatted and validated.
* @param Object flags
*   flags.places number of decimal places to show, default is 0 (cannot be Infinity)
*   flags.round true to round the number, false to truncate
* @param String locale
*	The locale used to determine the number format.
* @return String
* 	the formatted number of type String if successful
*   or null if an unsupported locale value was provided
**/
dojo.i18n.number.format = function(value, flags /*optional*/, locale /*optional*/){
	flags = (typeof flags == "object") ? flags : {};

	var formatData = dojo.i18n.number._mapToLocalizedFormatData(dojo.i18n.number.FORMAT_TABLE, locale);
	if (typeof flags.separator == "undefined") {flags.separator = formatData[1];}
	if (typeof flags.decimal == "undefined") {flags.decimal = formatData[2];}
	if (typeof flags.groupSize == "undefined") {flags.groupSize = formatData[3];}
	if (typeof flags.groupSize2 == "undefined") {flags.groupSize2 = formatData[4];}
	if (typeof flags.round == "undefined") {flags.round = true;}
	if (typeof flags.signed == "undefined") {flags.signed = true;}

	var output = (flags.signed && (value < 0)) ? "-" : "";
	value = Math.abs(value);
	var whole = String((((flags.places > 0) || !flags.round) ? Math.floor : Math.round)(value));

	// Splits str into substrings of size count, starting from right to left.  Is there a more clever way to do this in JS?
	function splitSubstrings(str, count){
		for(var subs = []; str.length >= count; str = str.substr(0, str.length - count)){
			subs.push(str.substr(-count));
		}
		if (str.length > 0){subs.push(str);}
		return subs.reverse();
	}

	if (flags.groupSize2 && (whole.length > flags.groupSize)){
		var groups = splitSubstrings(whole.substr(0, whole.length - flags.groupSize), flags.groupSize2);
		groups.push(whole.substr(-flags.groupSize));
		output = output + groups.join(flags.separator);
	}else if (flags.groupSize){
		output = output + splitSubstrings(whole, flags.groupSize).join(flags.separator);
	}else{
		output = output + whole;
	}

//TODO: what if flags.places is Infinity?
	if (flags.places > 0){
	//Q: Is it safe to convert to a string and split on ".", or might that be locale dependent?  Use Math for now.
		var fract = value - Math.floor(value);
		fract = (flags.round ? Math.round : Math.floor)(fract * Math.pow(10, flags.places));
		output = output + flags.decimal + fract;
	}

//TODO: exp

	return output;
};

/**
* Method to convert a properly formatted int string to a primative numeric value.
*
* @param String value
*	The int string to be convertted
* @param string locale
*	The locale used to convert the number string
* @param Object flags
*   flags.validate true to check the string for strict adherence to the locale settings for separator, sign, etc.
*     Default is true
* @return Number
* 	Returns a value of type Number, Number.NaN if not a number, or null if locale is not supported.
**/
dojo.i18n.number.parse = function(value, locale /*optional*/, flags /*optional*/){
	flags = (typeof flags == "object") ? flags : {};

	var formatData = dojo.i18n.number._mapToLocalizedFormatData(dojo.i18n.number.FORMAT_TABLE, locale);
	if (typeof flags.separator == "undefined") {flags.separator = formatData[1];}
	if (typeof flags.decimal == "undefined") {flags.decimal = formatData[2];}
	if (typeof flags.groupSize == "undefined") {flags.groupSize = formatData[3];}
	if (typeof flags.groupSize2 == "undefined") {flags.groupSize2 = formatData[4];}
	if (typeof flags.validate == "undefined") {flags.validate = true;}

	if (flags.validate && !dojo.i18n.number.isReal(value, locale, flags)) {
		return Number.NaN;
	}

	var numbers = value.split(flags.decimal);
	if (numbers.length > 2){return Number.NaN; }
	var whole = Number(numbers[0].replace(new RegExp("\\" + flags.separator, "g"), ""));
	var fract = (numbers.length == 1) ? 0 : Number(numbers[1]) / Math.pow(10, String(numbers[1]).length); // could also do Number(whole + "." + numbers[1]) if whole != NaN

//TODO: exp

	return whole + fract;
};

/**
  Validates whether a string is in an integer format. 

  @param value  A string.
  @param locale the locale to determine formatting used.  By default, the locale defined by the
    host environment: dojo.locale
  @param flags  An object.
    flags.signed  The leading plus-or-minus sign.  Can be true, false, or [true, false].
      Default is [true, false], (i.e. sign is optional).
    flags.separator  The character used as the thousands separator.  Default is specified by the locale.
      For more than one symbol use an array, e.g. [",", ""], makes ',' optional.
      The empty array [] makes the default separator optional.   
  @return  true or false.
*/
dojo.i18n.number.isInteger = function(value, locale /*optional*/, flags /*optional*/) {
	flags = (typeof flags == "object") ? flags : {};

	var formatData = dojo.i18n.number._mapToLocalizedFormatData(dojo.i18n.number.FORMAT_TABLE, locale);
	if (typeof flags.separator == "undefined") {flags.separator = formatData[1];}
	else if (dojo.lang.isArray(flags.separator) && flags.separator.length ===0){
		flags.separator = [formatData[1],""];
	}
	if (typeof flags.groupSize == "undefined") {flags.groupSize = formatData[3];}
	if (typeof flags.groupSize2 == "undefined") {flags.groupSize2 = formatData[4];}

	var re = new RegExp("^" + dojo.regexp.integer(flags) + "$");
	return re.test(value);
};

/**
  Validates whether a string is a real valued number. 
  Format is the usual exponential notation.

  @param value  A string.
  @param locale the locale to determine formatting used.  By default, the locale defined by the
    host environment: dojo.locale
  @param flags  An object.
    flags.places  The integer number of decimal places.
      If not given, the decimal part is optional and the number of places is unlimited.
    flags.decimal  The character used for the decimal point.  The default is specified by the locale.
    flags.exponent  Express in exponential notation.  Can be true, false, or [true, false].
      Default is [true, false], (i.e. the exponential part is optional).
    flags.eSigned  The leading plus-or-minus sign on the exponent.  Can be true, false, 
      or [true, false].  Default is [true, false], (i.e. sign is optional).
    flags in regexp.integer can be applied.
  @return  true or false.
*/
dojo.i18n.number.isReal = function(value, locale /*optional*/, flags /*optional*/) {
	flags = (typeof flags == "object") ? flags : {};

	var formatData = dojo.i18n.number._mapToLocalizedFormatData(dojo.i18n.number.FORMAT_TABLE, locale);
	if (typeof flags.separator == "undefined") {flags.separator = formatData[1];}
	else if (dojo.lang.isArray(flags.separator) && flags.separator.length ===0){
		flags.separator = [formatData[1],""];
	}
	if (typeof flags.decimal == "undefined") {flags.decimal = formatData[2];}
	if (typeof flags.groupSize == "undefined") {flags.groupSize = formatData[3];}
	if (typeof flags.groupSize2 == "undefined") {flags.groupSize2 = formatData[4];}

	var re = new RegExp("^" + dojo.regexp.realNumber(flags) + "$");
	return re.test(value);
};

//TODO: hide in a closure?
//TODO: change to use hashes and mixins, rather than arrays
//Q: fallback algorithm/how to structure table:
// does it make sense to look by country code most of the time (wildcard match on
// language, except where it's relevant) and provide default country when only
// a language is given?
(function() {

dojo.i18n.number.FORMAT_TABLE = {
	//0: thousand seperator for monetary, 1: thousand seperator for number, 2: decimal seperator, 3: group size, 4: second group size because of india
	'ar-ae': ["","", ",", 1],
	'ar-bh': ["","",",", 1],
	'ar-dz': ["","",",", 1],
	'ar-eg': ["","", ",", 1],
	'ar-jo': ["","",",", 1],
	'ar-kw': ["","", ",", 1],
	'ar-lb': ["","", ",", 1],
	'ar-ma': ["","", ",", 1],
	'ar-om': ["","", ",", 1],
	'ar-qa': ["","", ",", 1],
	'ar-sa': ["","", ",", 1],
	'ar-sy': ["","", ",", 1],
	'ar-tn': ["","", ",", 1],
	'ar-ye': ["","", ",", 1],
	'cs-cz': [".",".", ",", 3],
	'da-dk': [".",".", ",", 3],
	'de-at': [".",".", ",", 3],
	'de-de': [".",".", ",", 3],
	'de-lu': [".",".", ",", 3],
	//IBM JSL defect 51278. right now we have problem with single quote. //IBM: explain?
	'de-ch': ["'","'", ".", 3], //Q: comma as decimal separator for currency??
	//'de-ch': [".",".", ",", 3],
	'el-gr': [".",".", ",", 3],
	'en-au': [",",",", ".", 3],
	'en-ca': [",",",", ".", 3],
	'en-gb': [",",",", ".", 3],
	'en-hk': [",",",", ".", 3],
	'en-ie': [",",",", ".", 3],
	'en-in': [",",",", ".", 3,2],//india-english, 1,23,456.78
	'en-nz': [",",",", ".", 3],
	'en-us': [",",",", ".", 3],
	'en-za': [",",",", ".", 3],
	
	'es-ar': [".",".", ",", 3],
	'es-bo': [".",".", ",", 3],
	'es-cl': [".",".", ",", 3],
	'es-co': [".",".", ",", 3],
	'es-cr': [".",".", ",", 3],
	'es-do': [".",".", ",", 3],
	'es-ec': [".",".", ",", 3],
	'es-es': [".",".", ",", 3],
	'es-gt': [",",",", ".", 3],
	'es-hn': [",",",", ".", 3],
	'es-mx': [",",",", ".", 3],
	'es-ni': [",",",", ".", 3],
	'es-pa': [",",",", ".", 3],
	'es-pe': [",",",", ".", 3],
	'es-pr': [",",",", ".", 3],
	'es-py': [".",".",",", 3],
	'es-sv': [",", ",",".", 3],
	'es-uy': [".",".",",", 3],
	'es-ve': [".",".", ",", 3],
	
	'fi-fi': [" "," ", ",", 3],
	
	'fr-be': [".",".",",", 3],
	'fr-ca': [" ", " ", ",", 3],
	
	'fr-ch': [" ", " ",".", 3],
	
	'fr-fr': [" "," ", ",", 3],
	'fr-lu': [".",".", ",", 3],
	
	'he-il': [",",",", ".", 3],
	
	'hu-hu': [" ", " ",",", 3],
	
	'it-ch': [" "," ", ".", 3],
	
	'it-it': [".",".", ",", 3],
	'ja-jp': [",",",", ".", 3],
	'ko-kr': [",", ",",".", 3],
	
	'no-no': [".",".", ",", 3],
	
	'nl-be': [" "," ", ",", 3],
	'nl-nl': [".",".", ",", 3],
	'pl-pl': [".", ".",",", 3],
	
	'pt-br': [".",".", ",", 3],
	'pt-pt': [".",".", "$", 3],
	'ru-ru': [" ", " ",",", 3],
	
	'sv-se': ["."," ", ",", 3],
	
	'tr-tr': [".",".", ",", 3],
	
	'zh-cn': [",",",", ".", 3],
	'zh-hk': [",",",",".", 3],
	'zh-tw': [",", ",",".", 3],
	'*': [",",",", ".", 3]
};
})();

dojo.i18n.number._mapToLocalizedFormatData = function(table, locale){
	locale = dojo.hostenv.normalizeLocale(locale);
//TODO: most- to least-specific search? search by country code?
//TODO: implement aliases to simplify and shorten tables
	var data = table[locale];
	if (typeof data == 'undefined'){data = table['*'];}
	return data;
}

__CPAN_DIR__ src/i18n/calendar
__CPAN_DIR__ src/i18n/calendar/nls
__CPAN_FILE__ src/i18n/calendar/nls/gregorianExtras.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

// Dojo-specific extensions to the CLDR
({
	'dateFormat-yearOnly': "yyyy"
})
__CPAN_FILE__ src/i18n/calendar/nls/README
All files within this directory and subdirectories were manually derived from http://unicode.org/cldr

See terms of use: http://www.unicode.org/copyright.html#Exhibit1

Eventually, this data should be generated directly from the XML in the CLDR repository to provide
accurate and full support for the full set of locales.

__CPAN_FILE__ src/i18n/calendar/nls/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
	'months-format-abbr': ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
	'months-standAlone-narrow': ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
	'days-format-wide': ["1", "2", "3", "4", "5", "6", "7"],
	'days-format-abbr': ["1", "2", "3", "4", "5", "6", "7"],
	'days-standAlone-narrow': ["1", "2", "3", "4", "5", "6", "7"],


	'dateFormat-full': "EEEE, yyyy MMMM dd",
	'dateFormat-long': "yyyy MMMM d",
	'dateFormat-medium': "yyyy MMM d",
	'dateFormat-short': "yy/MM/dd",

	'timeFormat-full': "HH:mm:ss z",
	'timeFormat-long': "HH:mm:ss z",
	'timeFormat-medium': "HH:mm:ss",
	'timeFormat-short': "HH:mm",

	am: 'AM',
	pm: 'PM',
	eras: ['BCE','CE'],

	'field-era': "Era",
	'field-year': "Year",
	'field-month': "Month",
	'field-week': "Week",
	'field-day': "Day",
	'field-weekday': "Day of the Week",
	'field-dayperiod': "Dayperiod",
	'field-hour': "Hour",
	'field-minute': "Minute",
	'field-second': "Second",
	'field-zone': "Zone"	
})
__CPAN_DIR__ src/i18n/calendar/nls/es
__CPAN_FILE__ src/i18n/calendar/nls/es/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
	'months-format-abbr': ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
	'months-standAlone-narrow': ["E", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["domingo", "lunes", "martes", "miÃ©rcoles", "jueves", "viernes", "sÃ¡bado"],
	'days-format-abbr': ["dom", "lun", "mar", "miÃ©", "jue", "vie", "sÃ¡b"],
	'days-standAlone-narrow': ["D", "L", "M", "M", "J", "V", "S"],

	'dateFormat-full': "EEEE d' de 'MMMM' de 'yyyy",
	'dateFormat-long': "d' de 'MMMM' de 'yyyy",
	'dateFormat-medium': "dd-MMM-yy",
	'dateFormat-short': "d/MM/yy",

	'timeFormat-full': "HH'H'mm''ss\" z",

	am: "a.m.",
	pm: "p.m.",
	eras: ['a.C.','d.C.']
})
__CPAN_DIR__ src/i18n/calendar/nls/de
__CPAN_FILE__ src/i18n/calendar/nls/de/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["Januar", "Februar", "MÃ¤rz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
	'months-format-abbr': ["Jan", "Feb", "MÃ¤r", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
	'months-standAlone-narrow': ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
	'days-format-abbr': ["So", "Mo", "Di", "Mi", "Do", "Fri", "Sat"],
	'days-standAlone-narrow': ["S", "M", "D", "M", "D", "F", "S"],

	'dateFormat-full': "EEEE, d. MMMM yyyy",
	'dateFormat-long': "d. MMMM yyyy",
	'dateFormat-medium': "dd.MM.yyyy",
	'dateFormat-short': "dd.MM.yy",

	'timeFormat-full': "H:mm' Uhr 'z",

	am: "vorm.",
	pm: "nachm.",
	eras: ['v. Chr.','n. Chr.']
})
__CPAN_DIR__ src/i18n/calendar/nls/zh
__CPAN_FILE__ src/i18n/calendar/nls/zh/gregorianExtras.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'dateFormat-yearOnly': "yyyy'å¹´'"
})
__CPAN_FILE__ src/i18n/calendar/nls/zh/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'months-format-wide': ["ä¸€æœˆ", "äºŒæœˆ", "ä¸‰æœˆ", "å››æœˆ", "äº”æœˆ", "å…­æœˆ", "ä¸ƒæœˆ", "å…«æœˆ", "ä¹�æœˆ", "å��æœˆ", "å��ä¸€æœˆ", "å��äºŒæœˆ"],
	'months-format-abbr': ["ä¸€æœˆ", "äºŒæœˆ", "ä¸‰æœˆ", "å››æœˆ", "äº”æœˆ", "å…­æœˆ", "ä¸ƒæœˆ", "å…«æœˆ", "ä¹�æœˆ", "å��æœˆ", "å��ä¸€æœˆ", "å��äºŒæœˆ"],
	'months-standAlone-narrow': ["1æœˆ", "2æœˆ", "3æœˆ", "4æœˆ", "5æœˆ", "6æœˆ", "7æœˆ", "8æœˆ", "9æœˆ", "10æœˆ", "11æœˆ", "12æœˆ"],
	'days-format-wide': ["æ˜ŸæœŸæ—¥", "æ˜ŸæœŸä¸€", "æ˜ŸæœŸäºŒ", "æ˜ŸæœŸä¸‰", "æ˜ŸæœŸå››", "æ˜ŸæœŸäº”", "æ˜ŸæœŸå…­"],
	'days-format-abbr': ["å‘¨æ—¥", "å‘¨ä¸€", "å‘¨äºŒ", "å‘¨ä¸‰", "å‘¨å››", "å‘¨äº”", "å‘¨å…­"],
	'days-standAlone-narrow': ["æ—¥", "ä¸€", "äºŒ", "ä¸‰", "å››", "äº”", "å…­"],

	am: "ä¸Šå�ˆ",
	pm: "ä¸‹å�ˆ",
	eras: ['å…¬å…ƒå‰�','å…¬å…ƒ']
})
__CPAN_DIR__ src/i18n/calendar/nls/ja
__CPAN_FILE__ src/i18n/calendar/nls/ja/gregorianExtras.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'dateFormat-yearOnly': "yyyyå¹´"
})
__CPAN_FILE__ src/i18n/calendar/nls/ja/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'months-format-wide': ["1 æœˆ", "2 æœˆ", "3 æœˆ", "4 æœˆ", "5 æœˆ", "6 æœˆ", "7 æœˆ", "8 æœˆ", "9 æœˆ", "10 æœˆ", "11 æœˆ", "12 æœˆ"],
	'months-format-abbr': ["1 æœˆ", "2 æœˆ", "3 æœˆ", "4 æœˆ", "5 æœˆ", "6 æœˆ", "7 æœˆ", "8 æœˆ", "9 æœˆ", "10 æœˆ", "11 æœˆ", "12 æœˆ"],
	'days-format-wide': ["æ—¥æ›œæ—¥", "æœˆæ›œæ—¥", "ç�«æ›œæ—¥", "æ°´æ›œæ—¥", "æœ¨æ›œæ—¥", "é‡‘æ›œæ—¥", "åœŸæ›œæ—¥"],
	'days-format-abbr': ["æ—¥", "æœˆ", "ç�«", "æ°´", "æœ¨", "é‡‘", "åœŸ"],
	'days-standAlone-narrow': ["æ—¥", "æœˆ", "ç�«", "æ°´", "æœ¨", "é‡‘", "åœŸ"],


	'dateFormat-full': "yyyy'å¹´'M'æœˆ'd'æ—¥'EEEE",
	'dateFormat-long': "yyyy'å¹´'M'æœˆ'd'æ—¥'",
	'dateFormat-medium': "yyyy/MM/dd",

	'timeFormat-full': "H'æ™‚'mm'åˆ†'ss'ç§’'z",
	'timeFormat-long': "H:mm:ss:z",
	'timeFormat-medium': "H:mm:ss",
	'timeFormat-short': "H:mm",

	am: "å�ˆå‰�",
	pm: "å�ˆå¾Œ",
	eras: ['ç´€å…ƒå‰�','è¥¿æš¦']
})
__CPAN_DIR__ src/i18n/calendar/nls/fi
__CPAN_FILE__ src/i18n/calendar/nls/fi/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesÃ¤kuu", "heinÃ¤kuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
	'months-format-abbr': ["tammi", "helmi", "maalis", "huhti", "touko", "kesÃ¤", "heinÃ¤", "elo", "syys", "loka", "marras", "joulu"],
	'months-standAlone-narrow': ["T", "H", "M", "H", "T", "K", "H", "E", "S", "L", "M", "J"],
	'days-format-wide': ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"],
	'days-format-abbr': ["su", "ma", "ti", "ke", "to", "pe", "la"],
	'days-standAlone-narrow': ["S", "M", "T", "K", "T", "P", "L"],

	'dateFormat-full': "EEEE'na 'd. MMMM'ta 'yyyy",
	'dateFormat-long': "d. MMMM'ta 'yyyy",
	'dateFormat-medium': "d.M.yyyy",
	'dateFormat-short': "d.M.yyyy",

	'timeFormat-full': "H.mm.ss v",
	'timeFormat-long': "'klo 'H.mm.ss",
	'timeFormat-medium': "H.mm.ss",
	'timeFormat-short': "H.mm",

	am: "ap.",
	pm: "ip.",
	eras: ['eKr.','jKr.']
})

__CPAN_DIR__ src/i18n/calendar/nls/zh-cn
__CPAN_FILE__ src/i18n/calendar/nls/zh-cn/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'dateFormat-full': "yyyy'å¹´'M'æœˆ'd'æ—¥'EEEE",
	'dateFormat-long': "yyyy'å¹´'M'æœˆ'd'æ—¥'",
	'dateFormat-medium': "yyyy-M-d",
	'dateFormat-short': "yy-M-d",

	'timeFormat-full': "ahh'æ—¶'mm'åˆ†'ss'ç§’' z",
	'timeFormat-long': "ahh'æ—¶'mm'åˆ†'ss'ç§’'",
	'timeFormat-medium': "ahh:mm:ss",
	'timeFormat-short': "ah:mm"
})
__CPAN_DIR__ src/i18n/calendar/nls/ko
__CPAN_FILE__ src/i18n/calendar/nls/ko/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["1ì›”", "2ì›”", "3ì›”", "4ì›”", "5ì›”", "6ì›”", "7ì›”", "8ì›”", "9ì›”", "10ì›”", "11ì›”", "12ì›”"],
	'months-format-abbr': ["1ì›”", "2ì›”", "3ì›”", "4ì›”", "5ì›”", "6ì›”", "7ì›”", "8ì›”", "9ì›”", "10ì›”", "11ì›”", "12ì›”"],
	'months-standAlone-narrow': ["1ì›”", "2ì›”", "3ì›”", "4ì›”", "5ì›”", "6ì›”", "7ì›”", "8ì›”", "9ì›”", "10ì›”", "11ì›”", "12ì›”"],
	'days-format-wide': ["ì�¼ìš”ì�¼", "ì›”ìš”ì�¼", "í™”ìš”ì�¼", "ìˆ˜ìš”ì�¼", "ëª©ìš”ì�¼", "ê¸ˆìš”ì�¼", "í† ìš”ì�¼"],
	'days-format-abbr': ["ì�¼", "ì›”", "í™”", "ìˆ˜", "ëª©", "ê¸ˆ", "í† "],
	'days-standAlone-narrow': ["ì�¼", "ì›”", "í™”", "ìˆ˜", "ëª©", "ê¸ˆ", "í† "],

	'dateFormat-full': "yyyy'ë…„' M'ì›”' d'ì�¼' EEEE",
	'dateFormat-long': "yyyy'ë…„' M'ì›”' d'ì�¼'",
	'dateFormat-medium': "yyyy. MM. dd",
	'dateFormat-short': "yy. MM. dd",

	'timeFormat-full': "a hh'ì‹œ' mm'ë¶„' ss'ì´ˆ' z",
	'timeFormat-long': "a hh'ì‹œ' mm'ë¶„' ss'ì´ˆ'",
	'timeFormat-medium': "a hh'ì‹œ' mm'ë¶„'",
	'timeFormat-short': "a hh'ì‹œ' mm'ë¶„'",

	am: 'ì˜¤ì „',
	pm: 'ì˜¤í›„',
	eras: ['ê¸°ì›�ì „','ì„œê¸°']
})
__CPAN_DIR__ src/i18n/calendar/nls/sv
__CPAN_FILE__ src/i18n/calendar/nls/sv/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"],
	'months-format-abbr': ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
	'months-standAlone-narrow': ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["sÃ¶ndag", "mÃ¥ndag", "tisdag", "onsdag", "torsdag", "fredag", "lÃ¶rdag"],
	'days-format-abbr': ["sÃ¶n", "mÃ¥n", "tis", "ons", "tor", "fre", "lÃ¶r"],
	'days-standAlone-narrow': ["S", "M", "T", "O", "T", "F", "L"],

	'dateFormat-full': "EEEE'en den' d MMMM yyyy",
	'dateFormat-long': "EEEE d MMM yyyy",
	'dateFormat-medium': "d MMM yyyy",
	'dateFormat-short': "yyyy-MM-dd",

	'timeFormat-full': "'kl. 'HH.mm.ss z",
	'timeFormat-long': "HH.mm.ss z",
	'timeFormat-medium': "HH.mm.ss",
	'timeFormat-short': "HH.mm",

	am: "fm",
	pm: "em",
	eras: ['f.Kr.','e.Kr.']
})

__CPAN_DIR__ src/i18n/calendar/nls/en
__CPAN_FILE__ src/i18n/calendar/nls/en/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
	'months-format-abbr': ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
	'months-standAlone-narrow': ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
	'days-format-abbr': ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
	'days-standAlone-narrow': ["S", "M", "T", "W", "T", "F", "S"],

	'dateFormat-full': "EEEE, MMMM d, yyyy",
	'dateFormat-long': "MMMM d, yyyy",
	'dateFormat-medium': "MMM d, yyyy",
	'dateFormat-short': "M/d/yy",

	'timeFormat-full': "h:mm:ss a v",
	'timeFormat-long': "h:mm:ss a z",
	'timeFormat-medium': "h:mm:ss a",
	'timeFormat-short': "h:mm a",

	eras: ['BC','AD']
})
__CPAN_DIR__ src/i18n/calendar/nls/zh-hk
__CPAN_FILE__ src/i18n/calendar/nls/zh-hk/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'days-format-abbr': ["é€±æ—¥", "é€±ä¸€", "é€±äºŒ", "é€±ä¸‰", "é€±å››", "é€±äº”", "é€±å…­"],

	'dateFormat-full': "yyyy'å¹´'M'æœˆ'd'æ—¥'EEEE",
	'dateFormat-long': "yyyy'å¹´'M'æœˆ'd'æ—¥'",
	'dateFormat-medium': "yyyy/M/d",
	'dateFormat-short': "yyyy/M/d",

	'timeFormat-full': "ahh'æ™‚'mm'åˆ†'ss'ç§’' z",
	'timeFormat-long': "ahh'æ™‚'mm'åˆ†'ss'ç§’'",
	'timeFormat-medium': "a h:mm:ss",
	'timeFormat-short': "a h:mm",

	eras: ['è¥¿å…ƒå‰�','è¥¿å…ƒ']
})
__CPAN_DIR__ src/i18n/calendar/nls/zh-tw
__CPAN_FILE__ src/i18n/calendar/nls/zh-tw/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*<?xml version="1.0" encoding="UTF-8" ?>*/
({
	'months-format-abbr': ["1æœˆ", "2æœˆ", "3æœˆ", "4æœˆ", "5æœˆ", "6æœˆ", "7æœˆ", "8æœˆ", "9æœˆ", "10æœˆ", "11æœˆ", "12æœˆ"],

	'dateFormat-full': "yyyy'å¹´'M'æœˆ'd'æ—¥'EEEE",
	'dateFormat-long': "yyyy'å¹´'M'æœˆ'd'æ—¥'",
	'dateFormat-medium': "yyyy'å¹´'M'æœˆ'd'æ—¥'",
	'dateFormat-short': "yy'å¹´'M'æœˆ'd'æ—¥'",

	'timeFormat-full': "ahh'æ™‚'mm'åˆ†'ss'ç§’' z",
	'timeFormat-long': "ahh'æ™‚'mm'åˆ†'ss'ç§’'",
	'timeFormat-medium': "ahh:mm:ss",
	'timeFormat-short': "ah:mm",

	eras: ['è¥¿å…ƒå‰�','è¥¿å…ƒ']
})
__CPAN_DIR__ src/i18n/calendar/nls/pt
__CPAN_FILE__ src/i18n/calendar/nls/pt/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["janeiro", "fevereiro", "marÃ§o", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"],
	'months-format-abbr': ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"],
	'months-standAlone-narrow': ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["domingo", "segunda-feira", "terÃ§a-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sÃ¡bado"],
	'days-format-abbr': ["dom", "seg", "ter", "qua", "qui", "sex", "sÃ¡b"],
	'days-standAlone-narrow': ["D", "S", "T", "Q", "Q", "S", "S"],

	'dateFormat-full': "EEEE, d' de 'MMMM' de 'yyyy",
	'dateFormat-long': "d' de 'MMMM' de 'yyyy",
	'dateFormat-medium': "d/MMM/yyyy",
	'dateFormat-short': "dd-MM-yyyy",

	'timeFormat-full': "HH'H'mm'm'ss's' z",

	eras: ['a.C.','d.C.']
})
__CPAN_DIR__ src/i18n/calendar/nls/it
__CPAN_FILE__ src/i18n/calendar/nls/it/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"],
	'months-format-abbr': ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic"],
	'months-standAlone-narrow': ["G", "F", "M", "A", "M", "G", "L", "A", "S", "O", "N", "D"],
	'days-format-wide': ["domenica", "lunedÃ¬", "martedÃ¬", "mercoledÃ¬", "giovedÃ¬", "venerdÃ¬", "sabato"],
	'days-format-abbr': ["dom", "lun", "mar", "mer", "gio", "ven", "sab"],
	'days-standAlone-narrow': ["D", "L", "M", "M", "G", "V", "S"],

	'dateFormat-full': "EEEE d MMMM yyyy",
	'dateFormat-long': "dd MMMM yyyy",
	'dateFormat-medium': "dd/MMM/yy",
	'dateFormat-short': "dd/MM/yy",

	eras: ['aC','dC']
})
__CPAN_DIR__ src/i18n/calendar/nls/hu
__CPAN_FILE__ src/i18n/calendar/nls/hu/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["JanuÃ¡r", "FebruÃ¡r", "MÃ¡rcius", "Ã�prilis", "MÃ¡jus", "JÃºnius", "JÃºlius", "Augusztus", "Szeptember", "OktÃ³ber", "November", "December"],
	'months-format-abbr': ["Jan", "Feb", "MÃ¡r", "Ã�pr", "MÃ¡j", "JÃºn", "JÃºl", "Aug", "Sze", "Okt", "Nov", "Dec"],
	'months-standAlone-narrow': ["J", "F", "M", "Ã�", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["VasÃ¡rnap", "HÃ©tfÅ‘", "Kedd", "Szerda", "CsÃ¼tÃ¶rtÃ¶k", "PÃ©ntek", "Szombat"],
	'days-format-abbr': ["Va", "HÃ©", "Ke", "Sze", "CsÃ¼", "PÃ©", "Szo"],
	'days-standAlone-narrow': ["V", "H", "K", "Sz", "Cs", "P", "Sz"],

	'dateFormat-full': "yyyy MMMM d, EEEE",
	'dateFormat-long': "yyyy MMMM d",
	'dateFormat-medium': "yyyy MMM d",
	'dateFormat-short': "yyyy-M-d",

	'timeFormat-full': "h:mm:ss a v",
	'timeFormat-long': "h:mm:ss a z",
	'timeFormat-medium': "h:mm:ss a",
	'timeFormat-short': "h:mm a",

	am: "d.e.",
	pm: "d.u.",
	eras: ['k.e.','k.u.']
})

__CPAN_DIR__ src/i18n/calendar/nls/pt-br
__CPAN_FILE__ src/i18n/calendar/nls/pt-br/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'dateFormat-medium': "dd/MM/yyyy",
	'dateFormat-short': "dd/MM/yy",

	'timeFormat-full': "HH'h'mm'min'ss's' z",
	'timeFormat-long': "H'h'm'min's's' z"
})
__CPAN_DIR__ src/i18n/calendar/nls/fr
__CPAN_FILE__ src/i18n/calendar/nls/fr/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
    'months-format-wide': ["janvier", "fÃ©vrier", "mars", "avril", "mai", "juin", "juillet", "aoÃ»t", "septembre", "octobre", "novembre", "dÃ©cembre"],
    'months-format-abbr': ["janv.", "fÃ©vr.", "mars", "avr.", "mai", "juin", "juil.", "aoÃ»t", "sep.", "oct.", "nov.", "dÃ©c."],
    'months-standAlone-narrow': ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
    'days-format-wide': ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
    'days-format-abbr': ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
    'days-standAlone-narrow': ["D", "L", "M", "M", "J", "V", "S"],

	'dateFormat-full': "EEEE d MMMM yyyy",
	'dateFormat-long': "d MMMM yyyy",
	'dateFormat-medium': "d MMM yy",
	'dateFormat-short': "dd/MM/yy",

	'timeFormat-full': "HH' h 'mm z",

	eras: ['av. J.-C.','apr. J.-C.']
})

__CPAN_DIR__ src/i18n/calendar/nls/nl
__CPAN_FILE__ src/i18n/calendar/nls/nl/gregorian.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	'months-format-wide': ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
	'months-format-abbr': ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
	'months-standAlone-narrow': ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
	'days-format-wide': ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
	'days-format-abbr': ["zo", "ma", "di", "wo", "do", "vr", "za"],
	'days-standAlone-narrow': ["Z", "M", "D", "W", "D", "V", "Z"],

	'dateFormat-full': "EEEE d MMMM yyyy",
	'dateFormat-long': "d MMMM yyyy",
	'dateFormat-medium': "d MMM yyyy",
	'dateFormat-short': "dd-MM-yy",

	'timeFormat-full': "HH:mm:ss v",

	eras: ['v. Chr.','n. Chr.']
})

__CPAN_DIR__ src/i18n/currency
__CPAN_FILE__ src/i18n/currency/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.i18n.currency.common");

dojo.require("dojo.experimental");
dojo.experimental("dojo.i18n.currency");

dojo.require("dojo.regexp");
dojo.require("dojo.i18n.common");
dojo.require("dojo.i18n.number");
dojo.require("dojo.lang.common");

/**
* Method to Format and validate a given number a monetary value
*
* @param Number value
*	The number to be formatted and validated.
* @param String iso the ISO 4217 currency code
* @param Object flags
*   flags.places The number of decimal places to be included in the formatted number
* @param String locale the locale to determine formatting used.  By default, the locale defined by the
*   host environment: dojo.locale
* @return String
* 	the formatted currency of type String if successful; Nan if an
* 	invalid currency is provided or null if an unsupported locale value was provided.
**/
dojo.i18n.currency.format = function(value, iso, flags /*optional*/, locale /*optional*/){
	flags = (typeof flags == "object") ? flags : {};

	var formatData = dojo.i18n.currency._mapToLocalizedFormatData(dojo.i18n.currency.FORMAT_TABLE, iso, locale);
	if (typeof flags.places == "undefined") {flags.places = formatData.places;}
	if (typeof flags.places == "undefined") {flags.places = 2;}
	flags.signed = false;

	var result = dojo.i18n.number.format(value, flags, locale);

	var sym = formatData.symbol;
	if (formatData.adjSpace == "symbol"){ 
		if (formatData.placement == "after"){
			sym = " " + sym;// TODO: nbsp?
		}else{
			sym = sym + " ";// TODO: nbsp?
		}
	}

	if (value < 0){
		if (formatData.signPlacement == "before"){
			sym = "-" + sym;
		}else if (formatData.signPlacement == "after"){
			sym = sym + "-";
		}
	}

	var spc = (formatData.adjSpace == "number") ? " " : ""; // TODO: nbsp?
	if (formatData.placement == "after"){
		result = result + spc + sym;
	}else{
		result = sym + spc + result;
	}

	if (value < 0){
		if (formatData.signPlacement == "around"){
			result = "(" + result + ")";
		}else if (formatData.signPlacement == "end"){
			result = result + "-";
		}else if (!formatData.signPlacement || formatData.signPlacement == "begin"){
			result = "-" + result;
		}
	}

	return result;
};

/**
* Method to convert a properly formatted monetary value to a primative numeric value.
*
* @param String value
*	The int string to be convertted
  @param String iso the ISO 4217 currency code
* @param String locale the locale to determine formatting used.  By default, the locale defined by the
*   host environment: dojo.locale
* @param Object flags
*   flags.validate true to check the string for strict adherence to the locale settings for separator, sign, etc.
*     Default is true
* @return Number
* 	Returns a primative numeric value, Number.NaN if unable to convert to a number, or null if an unsupported locale is provided.
**/
dojo.i18n.currency.parse = function(value, iso, locale, flags /*optional*/){
	if (typeof flags.validate == "undefined") {flags.validate = true;}

	if (flags.validate && !dojo.i18n.number.isCurrency(value, iso, locale, flags)) {
		return Number.NaN;
	}

	var sign = (value.indexOf('-') != -1);
	var abs = abs.replace(/\-/, "");

	var formatData = dojo.i18n.currency._mapToLocalizedFormatData(dojo.i18n.currency.FORMAT_TABLE, iso, locale);
	abs = abs.replace(new RegExp("\\" + formatData.symbol), "");
	//TODO: trim?

	var number = dojo.i18n.number.parse(abs, locale, flags);
	if (sign){number = number * -1;}
	return number;
};

/**
  Validates whether a string denotes a monetary value. 

  @param value  A string
  @param iso the ISO 4217 currency code
  @param locale the locale to determine formatting used.  By default, the locale defined by the
    host environment: dojo.locale
  @param flags  An object
    flags.symbol  A currency symbol such as Yen "ï¿½", Pound "ï¿½", or the Euro sign "ï¿½".  
        The default is specified by the iso code.  For more than one symbol use an array, e.g. ["$", ""], makes $ optional.
        The empty array [] makes the default currency symbol optional.
    flags.placement  The symbol can come "before" or "after".  The default is specified by the iso code.
    flags.signed  The leading plus-or-minus sign.  Can be true, false, or [true, false].
      Default is [true, false], (i.e. sign is optional).
    flags.signPlacement  The sign can come "before" or "after" the symbol or "around" the whole expression
    	with parenthesis, such as CAD: (123$).  The default is specified by the iso code.
    flags.separator  The character used as the thousands separator. The default is specified by the locale.
        The empty array [] makes the default separator optional.
    flags.fractional  The appropriate number of decimal places for fractional currency (e.g. cents)
      Can be true, false, or [true, false].  Default is [true, false], (i.e. cents are optional).
    flags.places  The integer number of decimal places.
      If not given, an amount appropriate to the iso code is used.
    flags.fractional  The appropriate number of decimal places for fractional currency (e.g. cents)
      Can be true, false, or [true, false].  Default is [true, false], (i.e. cents are optional).
    flags.decimal  The character used for the decimal point.  The default is specified by the locale.
  @return  true or false.
*/
dojo.i18n.currency.isCurrency = function(value, iso, locale /*optional*/, flags){
	flags = (typeof flags == "object") ? flags : {};

	var numberFormatData = dojo.i18n.number._mapToLocalizedFormatData(dojo.i18n.number.FORMAT_TABLE, locale);
	if (typeof flags.separator == "undefined") {flags.separator = numberFormatData[0];}
	else if (dojo.lang.isArray(flags.separator) && flags.separator.length == 0){flags.separator = [numberFormatData[0],""];}
	if (typeof flags.decimal == "undefined") {flags.decimal = numberFormatData[2];}
	if (typeof flags.groupSize == "undefined") {flags.groupSize = numberFormatData[3];}
	if (typeof flags.groupSize2 == "undefined") {flags.groupSize2 = numberFormatData[4];}

	var formatData = dojo.i18n.currency._mapToLocalizedFormatData(dojo.i18n.currency.FORMAT_TABLE, iso, locale);
	if (typeof flags.places == "undefined") {flags.places = formatData.places;}
	if (typeof flags.places == "undefined") {flags.places = 2;}
	if (typeof flags.symbol == "undefined") {flags.symbol = formatData.symbol;}
	else if (dojo.lang.isArray(flags.symbol) && flags.symbol.length == 0){flags.symbol = [formatData.symbol,""];}
	if (typeof flags.placement == "undefined") {flags.placement = formatData.placement;}
	//TODO more... or mixin?

	var re = new RegExp("^" + dojo.regexp.currency(flags) + "$");
//dojo.debug(value+":"+dojo.regexp.currency(flags)+"="+re.test(value));
	return re.test(value);
};

dojo.i18n.currency._mapToLocalizedFormatData = function(table, iso, locale /*optional*/){
	var formatData = dojo.i18n.currency.FORMAT_TABLE[iso];
	if (!dojo.lang.isArray(formatData)){
		return formatData;
	}

	return dojo.i18n.number._mapToLocalizedFormatData(formatData[0], locale);
};

(function() {
	var arabic = {symbol: "\u062C", placement: "after", htmlSymbol: "?"};
	var euro = {symbol: "\u20AC", placement: "before", adjSpace: "symbol", htmlSymbol: "&euro;"};
	var euroAfter = {symbol: "\u20AC", placement: "after", htmlSymbol: "&euro;"};

//Q: Do European countries still use their old ISO symbols instead of just EUR?
//Q: are signPlacement and currency symbol placement ISO-dependent or are they really locale-dependent?
//TODO: htmlSymbol is for html entities, need images? (IBM: why? why can't we just use unicode everywhere?)
//TODO: hide visibility of this table?
//for html entities, need a image for arabic symbol "BHD" as "DZD", "EGP", "JOD", "KWD" "LBP", "MAD", "OMR", "QAR", "SAR", "SYP", "TND", "AED", "YER"
//Note: html entities not used at the moment
//placement: placement of currency symbol, before or after number
//signPlacement: placement of negative sign, before or after symbol, or begin or end of expression, or around with parentheses
// This table assumes defaults of
//	places: 2, placement: "before", signPlacement: "begin", adjSpace: undefined, htmlSymbol: undefined]
dojo.i18n.currency.FORMAT_TABLE = {
	AED: {symbol: "\u062c", placement: "after"},
	ARS: {symbol: "$", signPlacement: "after"},
	//Old ATS: {symbol: "S", adjSpace: "symbol"},
	ATS: {symbol: "\u20AC", adjSpace: "number", signPlacement: "after", htmlSymbol: "&euro;"}, 	//Austria using "EUR" // neg should read euro + sign + space + number
	AUD: {symbol: "$"},
	BOB: {symbol: "$b"},
	BRL: {symbol: "R$", adjSpace: "symbol"},
	//Old BEF: {symbol: "BF", placement: "after", adjSpace: "symbol"},
	BEF: euroAfter,	//Belgium using "EUR"
	//Old BHD: {symbol: "\u062C", signPlacement: "end", places: 3, htmlSymbol: "?"},
	BHD: arabic,
	//TODO: I'm suspicious that all the other entries have locale-specific data in them, too?
	//Q: which attributes are iso-specific and which are locale specific?
	CAD: [{
			'*' : {symbol: "$"},
			'fr-ca' : {symbol: "$", placement: "after", signPlacement: "around"}
		}],
	CHF: {symbol: "CHF", adjSpace: "symbol", signPlacement: "after"},
	CLP: {symbol: "$"},
	COP: {symbol: "$", signPlacement: "around"},
	CNY: {symbol: "\u00A5", htmlSymbol: "&yen;"},
	//// Costa Rica  - Spanish slashed C. need to find out the html entity image
	CRC: {symbol: "\u20A1", signPlacement: "after", htmlSymbol: "?"},
	// Czech Republic  - Czech //need image for html entities
	CZK: {symbol: "Kc", adjSpace: "symbol", signPlacement: "after"},
	DEM: euroAfter,
	DKK: {symbol: "kr.", adjSpace: "symbol", signPlacement: "after"},
	DOP: {symbol: "$"},
	//for html entities, need a image, bidi, using "rtl", so from the link, symbol is suffix
	//Old DZD: {symbol: "\u062C", signPlacement: "end", places: 3, htmlSymbol: "?"},
	DZD: arabic,
	//Ecuador using "USD"
	ECS: {symbol: "$", signPlacement: "after"},
	EGP: arabic,
	//Old ESP: {symbol: "Pts", placement: "after", adjSpace: "symbol", places: 0},
	ESP: euroAfter,	//spain using "EUR"
	EUR: euro,
	//Old FIM: {symbol: "mk", placement: "after", adjSpace: "symbol"},
	FIM: euroAfter,	//Finland using "EUR"
	//Old FRF: {symbol: "F", placement: "after", adjSpace: "symbol"},
	FRF: euroAfter,	//France using "EUR"
	GBP: {symbol: "\u00A3", htmlSymbol: "&pound;"},
	GRD: {symbol: "\u20AC", signPlacement: "end", htmlSymbol: "&euro;"},
	GTQ: {symbol: "Q", signPlacement: "after"},
	//Hong Kong need "HK$" and "$". Now only support "HK$"
	HKD: {symbol: "HK$"},
	HNL: {symbol: "L.", signPlacement: "end"},
	HUF: {symbol: "Ft", placement: "after", adjSpace: "symbol"},
	//IEP: {symbol: "\u00A3", htmlSymbol: "&pound;"},
	IEP: {symbol: "\u20AC", htmlSymbol: "&euro;"},	//ireland using "EUR" at the front.
	//couldn't know what Israel - Hebrew symbol, some sites use "NIS", bidi, using "rtl", so from the link, symbol is suffix (IBM: huh?)
	//ILS: {symbol: "\u05E9\u0022\u05D7", signPlacement: "end", htmlSymbol: "?"},
	ILS: {symbol: "\u05E9\u0022\u05D7", placement: "after", htmlSymbol: "?"},
	INR: {symbol: "Rs."},
	//ITL: {symbol: "L", adjSpace: "symbol", signPlacement: "after", places: 0},
	ITL: {symbol: "\u20AC", signPlacement: "after", htmlSymbol: "&euro;"},	//Italy using "EUR"
	JOD: arabic,
	JPY: {symbol: "\u00a5", places: 0, htmlSymbol: "&yen;"},
	KRW: {symbol: "\u20A9", places: 0, htmlSymbol: "?"},
	KWD: arabic,
	LBP: arabic,
	//Old LUF: {symbol: "LUF", placement: "after", adjSpace: "symbol"},
	//for Luxembourg,using "EUR"
	LUF: euroAfter,
	MAD: arabic,
	MXN: {symbol: "$", signPlacement: "around"},
	NIO: {symbol: "C$", adjSpace: "symbol", signPlacement: "after"},
	//Old NLG: {symbol: "f", adjSpace: "symbol", signPlacement: "end"},
	//Netherlands, using "EUR"
	NLG: {symbol: "\u20AC", signPlacement: "end", htmlSymbol: "&euro;"},
	NOK: {symbol: "kr", adjSpace: "symbol", signPlacement: "after"},
	NZD: {symbol: "$"},
	OMR: arabic,
	PAB: {symbol: "B/", adjSpace: "symbol", signPlacement: "after"},
	PEN: {symbol: "S/", signPlacement: "after"},
	//couldn't know what the symbol is from ibm link. (IBM: what does this mean?  Is the symbol 'z' wrong?)
	PLN: {symbol: "z", placement: "after"},
	//Old PTE: {symbol: "Esc.", placement: "after", adjSpace: "symbol", places: 0},
	PTE: euroAfter,
	PYG: {symbol: "Gs.", signPlacement: "after"},
	QAR: arabic,
	RUR: {symbol: "rub.", placement: "after"},
	SAR: arabic,
	SEK: {symbol: "kr", placement: "after", adjSpace: "symbol"},
	SGD: {symbol: "$"},
	//// El Salvador - Spanish slashed C. need to find out. (IBM: need to find out what?)
	SVC: {symbol: "\u20A1", signPlacement: "after", adjSpace: "symbol"},
	//for html entities, need a image
	SYP: arabic,
	TND: arabic,
	TRL: {symbol: "TL", placement: "after"},
	TWD: {symbol: "NT$"},
	USD: {symbol: "$"},
	UYU: {symbol: "$U", signplacement: "after", adjSpace: "symbol"},
	VEB: {symbol: "Bs", signplacement: "after", adjSpace: "symbol"},
	YER: arabic,
	ZAR: {symbol: "R", signPlacement: "around"}
};

})();

__CPAN_DIR__ src/i18n/currency/nls
__CPAN_FILE__ src/i18n/currency/nls/JPY.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "JPY",
	symbol: "\u00a5"
})
__CPAN_FILE__ src/i18n/currency/nls/GBP.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "GBP",
	symbol: "\u00A3"
})
__CPAN_FILE__ src/i18n/currency/nls/README
All files within this directory and subdirectories were manually derived from http://unicode.org/cldr

See terms of use: http://www.unicode.org/copyright.html#Exhibit1

Eventually, this data should be generated directly from the XML in the CLDR repository to provide
accurate and full support for the full set of locales.

__CPAN_FILE__ src/i18n/currency/nls/ITL.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "ITL",
	symbol: "\u20A4"
})
__CPAN_FILE__ src/i18n/currency/nls/USD.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "USD",
	symbol: "$"
})
__CPAN_FILE__ src/i18n/currency/nls/INR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "INR",
	symbol: function(value){return (value == 1) ? "Re." : "Rs.";}
})
__CPAN_FILE__ src/i18n/currency/nls/EUR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "EUR",
	symbol: "\u20AC"
})
__CPAN_DIR__ src/i18n/currency/nls/ja
__CPAN_FILE__ src/i18n/currency/nls/ja/JPY.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "æ—¥æœ¬å††",
	symbol: "ï¿¥"
})
__CPAN_FILE__ src/i18n/currency/nls/ja/GBP.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "è‹±å›½ãƒ�ãƒ³ãƒ‰"
})
__CPAN_FILE__ src/i18n/currency/nls/ja/ITL.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "ã‚¤ã‚¿ãƒªã‚¢ ãƒªãƒ©"
})
__CPAN_FILE__ src/i18n/currency/nls/ja/USD.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "ç±³ãƒ‰ãƒ«"
})
__CPAN_FILE__ src/i18n/currency/nls/ja/INR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "ã‚¤ãƒ³ãƒ‰ ãƒ«ãƒ”ãƒ¼",
	symbol: "INR"
})
__CPAN_FILE__ src/i18n/currency/nls/ja/EUR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "ãƒ¦ãƒ¼ãƒ­"
})
__CPAN_DIR__ src/i18n/currency/nls/en-us
__CPAN_FILE__ src/i18n/currency/nls/en-us/USD.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	symbol: "$"
})
__CPAN_DIR__ src/i18n/currency/nls/en
__CPAN_FILE__ src/i18n/currency/nls/en/JPY.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "Japanese Yen"
})
__CPAN_FILE__ src/i18n/currency/nls/en/GBP.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "British Pound Sterling"
})
__CPAN_FILE__ src/i18n/currency/nls/en/ITL.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "Italian Lira"
})
__CPAN_FILE__ src/i18n/currency/nls/en/USD.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "US Dollar",
	symbol: "US$"
})
__CPAN_FILE__ src/i18n/currency/nls/en/INR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "Indian Rupee"
})
__CPAN_FILE__ src/i18n/currency/nls/en/EUR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "Euro"
})
__CPAN_DIR__ src/i18n/currency/nls/hi
__CPAN_FILE__ src/i18n/currency/nls/hi/JPY.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "à¤œà¤¾à¤ªà¤¾à¤¨à¥€ à¤¯à¥‡à¤¨"
})
__CPAN_FILE__ src/i18n/currency/nls/hi/GBP.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "à¤¬à¥�à¤°à¤¿à¤¤à¤¨ à¤•à¤¾ à¤ªà¥Œà¤¨à¥�à¤¡ à¤¸à¥�à¤Ÿà¤°à¥�à¤²à¤¿à¤—"
})
__CPAN_FILE__ src/i18n/currency/nls/hi/ITL.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "à¤‡à¤¤à¤²à¥€ à¤•à¤¾ à¤²à¥€à¤°à¤¾"
})
__CPAN_FILE__ src/i18n/currency/nls/hi/USD.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "à¤…à¤®à¤°à¥€à¤•à¥€ à¤¡à¤¾à¤²à¤°"
})
__CPAN_FILE__ src/i18n/currency/nls/hi/INR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "à¤­à¤¾à¤°à¤¤à¥€à¤¯  à¤°à¥‚à¤ªà¤¯à¤¾",
	symbol: "à¤°à¥�."
})
__CPAN_FILE__ src/i18n/currency/nls/hi/EUR.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

({
	displayName: "à¤¯à¥�à¤°à¥‹"
})
__CPAN_DIR__ src/namespaces
__CPAN_FILE__ src/namespaces/dojo.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.namespaces.dojo");
dojo.require("dojo.ns");

(function(){
	//mapping of all widget short names to their full package names
	// This is used for widget autoloading - no dojo.require() is necessary.
	// If you use a widget in markup or create one dynamically, then this
	// mapping is used to find and load any dependencies not already loaded.
	// You should use your own namespace for any custom widgets.
	// For extra widgets you use, dojo.declare() may be used to explicitly load them.
	var map = {
		html: {
			"accordioncontainer": "dojo.widget.AccordionContainer",
			"button": "dojo.widget.Button",
			"chart": "dojo.widget.Chart",
			"checkbox": "dojo.widget.Checkbox",
			"colorpalette": "dojo.widget.ColorPalette",
			"combobox": "dojo.widget.ComboBox",
			"combobutton": "dojo.widget.Button",
			"contentpane": "dojo.widget.ContentPane",
			"contextmenu": "dojo.widget.ContextMenu",
			"currencytextbox": "dojo.widget.CurrencyTextbox",
			"datepicker": "dojo.widget.DatePicker",
			"datetextbox": "dojo.widget.DateTextbox",
			"debugconsole": "dojo.widget.DebugConsole",
			"dialog": "dojo.widget.Dialog",
			"docpane": "dojo.widget.DocPane",
			"dropdownbutton": "dojo.widget.Button",
			"dropdowndatepicker": "dojo.widget.DropdownDatePicker",
			"dropdowntimepicker": "dojo.widget.DropdownTimePicker",
			"emaillisttextbox": "dojo.widget.InternetTextbox",
			"emailtextbox": "dojo.widget.InternetTextbox",
			"editor2": "dojo.widget.Editor2",
			"editor2toolbar": "dojo.widget.Editor2Toolbar",
			"editor": "dojo.widget.Editor",
			"editortree": "dojo.widget.EditorTree",
			"editortreecontextmenu": "dojo.widget.EditorTreeContextMenu",
			"editortreenode": "dojo.widget.EditorTreeNode",
			"filteringtable": "dojo.widget.FilteringTable",
			"fisheyelist": "dojo.widget.FisheyeList",
			"editortreecontroller": "dojo.widget.EditorTreeController",
			"googlemap": "dojo.widget.GoogleMap",
			"editortreeselector": "dojo.widget.EditorTreeSelector",
			"floatingpane": "dojo.widget.FloatingPane",
			"form": "dojo.widget.Form",
			"hslcolorpicker": "dojo.widget.HslColorPicker",
			"inlineeditbox": "dojo.widget.InlineEditBox",
			"integerspinner": "dojo.widget.IntegerSpinner",
			"integertextbox": "dojo.widget.IntegerTextbox",
			"ipaddresstextbox": "dojo.widget.InternetTextbox",
			"layoutcontainer": "dojo.widget.LayoutContainer",
			"linkpane": "dojo.widget.LinkPane",
			"pagecontainer": "dojo.widget.PageContainer",
			"pagecontroller": "dojo.widget.PageContainer",
			"popupcontainer": "dojo.widget.Menu2",
			"popupmenu2": "dojo.widget.Menu2",
			"menuitem2": "dojo.widget.Menu2",
			"menuseparator2": "dojo.widget.Menu2",
			"menubar2": "dojo.widget.Menu2",
			"menubaritem2": "dojo.widget.Menu2",
			"monthlyCalendar": "dojo.widget.MonthlyCalendar",
			"radiogroup": "dojo.widget.RadioGroup",
			"realnumbertextbox": "dojo.widget.RealNumberTextbox",
			"regexptextbox": "dojo.widget.RegexpTextbox",
			"repeater": "dojo.widget.Repeater", 
			"richtext": "dojo.widget.RichText",
			"remotetabcontroller": "dojo.widget.RemoteTabController",
			"resizehandle": "dojo.widget.ResizeHandle",
			"resizabletextarea": "dojo.widget.ResizableTextarea",
			"select": "dojo.widget.Select",
			"slideshow": "dojo.widget.SlideShow",
			"sortabletable": "dojo.widget.SortableTable",
			"splitcontainer": "dojo.widget.SplitContainer",
			"svgbutton": "dojo.widget.SvgButton",
			"tabcontainer": "dojo.widget.TabContainer",
			"tabcontroller": "dojo.widget.TabContainer",
			"taskbar": "dojo.widget.TaskBar",
			"textbox": "dojo.widget.Textbox",
			"timepicker": "dojo.widget.TimePicker",
			"timetextbox": "dojo.widget.DateTextbox",
			"titlepane": "dojo.widget.TitlePane",
			"toaster": "dojo.widget.Toaster",
			"toggler": "dojo.widget.Toggler",
			"toolbar": "dojo.widget.Toolbar",
			"tooltip": "dojo.widget.Tooltip",
			"tree": "dojo.widget.Tree",
			"treebasiccontroller": "dojo.widget.TreeBasicController",
			"treecontextmenu": "dojo.widget.TreeContextMenu",
			"treeselector": "dojo.widget.TreeSelector",
			"treecontrollerextension": "dojo.widget.TreeControllerExtension",
			"treenode": "dojo.widget.TreeNode",
			"treerpccontroller": "dojo.widget.TreeRPCController",
			"treebasiccontrollerv3": "dojo.widget.TreeBasicControllerV3",
			"treecontextmenuv3": "dojo.widget.TreeContextMenuV3",
			"treedeselectondblselect": "dojo.widget.TreeDeselectOnDblselect",
			"treedisablewrapextension": "dojo.widget.TreeDisableWrapExtension",
			"treedndcontrollerv3": "dojo.widget.TreeDndControllerV3",
			"treedociconextension": "dojo.widget.TreeDocIconExtension",
			"treeeditor": "dojo.widget.TreeEditor",
			"treeemphaseonselect": "dojo.widget.TreeEmphaseOnSelect",
			"treelinkextension": "dojo.widget.TreeLinkExtension",
			"treeloadingcontrollerv3": "dojo.widget.TreeLoadingControllerV3",
			"treemenuitemv3": "dojo.widget.TreeContextMenuV3",
			"treerpccontrollerv3": "dojo.widget.TreeRpcControllerV3",
			"treeselectorv3": "dojo.widget.TreeSelectorV3",
			"treev3": "dojo.widget.TreeV3",
			"urltextbox": "dojo.widget.InternetTextbox",
			"usphonenumbertextbox": "dojo.widget.UsTextbox",
			"ussocialsecuritynumbertextbox": "dojo.widget.UsTextbox",
			"usstatetextbox": "dojo.widget.UsTextbox",
			"usziptextbox": "dojo.widget.UsTextbox",
			"validationtextbox": "dojo.widget.ValidationTextbox",
			"treeloadingcontroller": "dojo.widget.TreeLoadingController",
			"widget": "dojo.widget.Widget",
			"wizard": "dojo.widget.Wizard",
			"yahoomap": "dojo.widget.YahooMap"
		},
		svg: {
			"chart": "dojo.widget.svg.Chart",
			"hslcolorpicker": "dojo.widget.svg.HslColorPicker"
		},
		vml: {
			"chart": "dojo.widget.vml.Chart"
		}
	};

	dojo.addDojoNamespaceMapping = function(/*String*/shortName, /*String*/packageName){
	// summary:
	//	Add an entry to the mapping table for the dojo: namespace
	//
	// shortName: the name to be used as the widget's tag name in the dojo: namespace
	// packageName: the path to the Javascript module in dotted package notation
		map[shortName]=packageName;    
	};
	
	function dojoNamespaceResolver(name, domain){
		if(!domain){ domain="html"; }
		if(!map[domain]){ return null; }
		return map[domain][name];    
	}

	dojo.registerNamespaceResolver("dojo", dojoNamespaceResolver);
})();

__CPAN_DIR__ src/crypto
__CPAN_FILE__ src/crypto/LICENSE
License Disclaimer:

All contents of this directory are Copyright (c) the Dojo Foundation, with the
following exceptions:
-------------------------------------------------------------------------------

MD5.js, SHA1.js:
	* Copyright 1998-2005, Paul Johnstone
	  Distributed under the terms of the BSD License



__CPAN_FILE__ src/crypto/SHA256.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.crypto.SHA256");
dojo.require("dojo.crypto");
dojo.require("dojo.experimental");

dojo.experimental("dojo.crypto.SHA256");

dojo.crypto.SHA256 = new function(){
	this.compute=function(s){
	};
}();

__CPAN_FILE__ src/crypto/Rijndael.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.crypto.Rijndael");
dojo.require("dojo.crypto");
dojo.require("dojo.experimental");

dojo.experimental("dojo.crypto.Rijndael");

dojo.crypto.Rijndael = new function(){
	this.encrypt=function(plaintext, key){
	};
	this.decrypt=function(ciphertext, key){
	};
}();

__CPAN_FILE__ src/crypto/MD5.js
dojo.require("dojo.crypto");
dojo.provide("dojo.crypto.MD5");

/*	Return to a port of Paul Johnstone's MD5 implementation
 *	http://pajhome.org.uk/crypt/md5/index.html
 *
 *	Copyright (C) Paul Johnston 1999 - 2002.
 *	Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * 	Distributed under the BSD License
 *
 *	Dojo port by Tom Trenka
 *
 *	2005-12-7
 *	All conversions are internalized (no dependencies)
 *	implemented getHMAC for message digest auth.
 */
dojo.crypto.MD5 = new function(){
	//	summary
	//	object for creating digests using the MD5 algorithm
	var chrsz=8;
	var mask=(1<<chrsz)-1;
	function toWord(s) {
	  var wa=[];
	  for(var i=0; i<s.length*chrsz; i+=chrsz)
		wa[i>>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32);
	  return wa;
	}
	function toString(wa){
		var s=[];
		for(var i=0; i<wa.length*32; i+=chrsz)
			s.push(String.fromCharCode((wa[i>>5]>>>(i%32))&mask));
		return s.join("");
	}
	function toHex(wa) {
		var h="0123456789abcdef";
		var s=[];
		for(var i=0; i<wa.length*4; i++){
			s.push(h.charAt((wa[i>>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF));
		}
		return s.join("");
	}
	function toBase64(wa){
		var p="=";
		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var s=[];
		for(var i=0; i<wa.length*4; i+=3){
			var t=(((wa[i>>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF);
			for(var j=0; j<4; j++){
				if(i*8+j*6>wa.length*32) s.push(p);
				else s.push(tab.charAt((t>>6*(3-j))&0x3F));
			}
		}
		return s.join("");
	}
	function add(x,y) {
		var l=(x&0xFFFF)+(y&0xFFFF);
		var m=(x>>16)+(y>>16)+(l>>16);
		return (m<<16)|(l&0xFFFF);
	}
	function R(n,c){ return (n<<c)|(n>>>(32-c)); }
	function C(q,a,b,x,s,t){ return add(R(add(add(a,q),add(x,t)),s),b); }
	function FF(a,b,c,d,x,s,t){ return C((b&c)|((~b)&d),a,b,x,s,t); }
	function GG(a,b,c,d,x,s,t){ return C((b&d)|(c&(~d)),a,b,x,s,t); }
	function HH(a,b,c,d,x,s,t){ return C(b^c^d,a,b,x,s,t); }
	function II(a,b,c,d,x,s,t){ return C(c^(b|(~d)),a,b,x,s,t); }
	function core(x,len){
		x[len>>5]|=0x80<<((len)%32);
		x[(((len+64)>>>9)<<4)+14]=len;
		var a= 1732584193;
		var b=-271733879;
		var c=-1732584194;
		var d= 271733878;
		for(var i=0; i<x.length; i+=16){
			var olda=a;
			var oldb=b;
			var oldc=c;
			var oldd=d;

			a=FF(a,b,c,d,x[i+ 0],7 ,-680876936);
			d=FF(d,a,b,c,x[i+ 1],12,-389564586);
			c=FF(c,d,a,b,x[i+ 2],17, 606105819);
			b=FF(b,c,d,a,x[i+ 3],22,-1044525330);
			a=FF(a,b,c,d,x[i+ 4],7 ,-176418897);
			d=FF(d,a,b,c,x[i+ 5],12, 1200080426);
			c=FF(c,d,a,b,x[i+ 6],17,-1473231341);
			b=FF(b,c,d,a,x[i+ 7],22,-45705983);
			a=FF(a,b,c,d,x[i+ 8],7 , 1770035416);
			d=FF(d,a,b,c,x[i+ 9],12,-1958414417);
			c=FF(c,d,a,b,x[i+10],17,-42063);
			b=FF(b,c,d,a,x[i+11],22,-1990404162);
			a=FF(a,b,c,d,x[i+12],7 , 1804603682);
			d=FF(d,a,b,c,x[i+13],12,-40341101);
			c=FF(c,d,a,b,x[i+14],17,-1502002290);
			b=FF(b,c,d,a,x[i+15],22, 1236535329);

			a=GG(a,b,c,d,x[i+ 1],5 ,-165796510);
			d=GG(d,a,b,c,x[i+ 6],9 ,-1069501632);
			c=GG(c,d,a,b,x[i+11],14, 643717713);
			b=GG(b,c,d,a,x[i+ 0],20,-373897302);
			a=GG(a,b,c,d,x[i+ 5],5 ,-701558691);
			d=GG(d,a,b,c,x[i+10],9 , 38016083);
			c=GG(c,d,a,b,x[i+15],14,-660478335);
			b=GG(b,c,d,a,x[i+ 4],20,-405537848);
			a=GG(a,b,c,d,x[i+ 9],5 , 568446438);
			d=GG(d,a,b,c,x[i+14],9 ,-1019803690);
			c=GG(c,d,a,b,x[i+ 3],14,-187363961);
			b=GG(b,c,d,a,x[i+ 8],20, 1163531501);
			a=GG(a,b,c,d,x[i+13],5 ,-1444681467);
			d=GG(d,a,b,c,x[i+ 2],9 ,-51403784);
			c=GG(c,d,a,b,x[i+ 7],14, 1735328473);
			b=GG(b,c,d,a,x[i+12],20,-1926607734);

			a=HH(a,b,c,d,x[i+ 5],4 ,-378558);
			d=HH(d,a,b,c,x[i+ 8],11,-2022574463);
			c=HH(c,d,a,b,x[i+11],16, 1839030562);
			b=HH(b,c,d,a,x[i+14],23,-35309556);
			a=HH(a,b,c,d,x[i+ 1],4 ,-1530992060);
			d=HH(d,a,b,c,x[i+ 4],11, 1272893353);
			c=HH(c,d,a,b,x[i+ 7],16,-155497632);
			b=HH(b,c,d,a,x[i+10],23,-1094730640);
			a=HH(a,b,c,d,x[i+13],4 , 681279174);
			d=HH(d,a,b,c,x[i+ 0],11,-358537222);
			c=HH(c,d,a,b,x[i+ 3],16,-722521979);
			b=HH(b,c,d,a,x[i+ 6],23, 76029189);
			a=HH(a,b,c,d,x[i+ 9],4 ,-640364487);
			d=HH(d,a,b,c,x[i+12],11,-421815835);
			c=HH(c,d,a,b,x[i+15],16, 530742520);
			b=HH(b,c,d,a,x[i+ 2],23,-995338651);

			a=II(a,b,c,d,x[i+ 0],6 ,-198630844);
			d=II(d,a,b,c,x[i+ 7],10, 1126891415);
			c=II(c,d,a,b,x[i+14],15,-1416354905);
			b=II(b,c,d,a,x[i+ 5],21,-57434055);
			a=II(a,b,c,d,x[i+12],6 , 1700485571);
			d=II(d,a,b,c,x[i+ 3],10,-1894986606);
			c=II(c,d,a,b,x[i+10],15,-1051523);
			b=II(b,c,d,a,x[i+ 1],21,-2054922799);
			a=II(a,b,c,d,x[i+ 8],6 , 1873313359);
			d=II(d,a,b,c,x[i+15],10,-30611744);
			c=II(c,d,a,b,x[i+ 6],15,-1560198380);
			b=II(b,c,d,a,x[i+13],21, 1309151649);
			a=II(a,b,c,d,x[i+ 4],6 ,-145523070);
			d=II(d,a,b,c,x[i+11],10,-1120210379);
			c=II(c,d,a,b,x[i+ 2],15, 718787259);
			b=II(b,c,d,a,x[i+ 9],21,-343485551);

			a = add(a,olda);
			b = add(b,oldb);
			c = add(c,oldc);
			d = add(d,oldd);
		}
		return [a,b,c,d];
	}
	function hmac(data,key){
		var wa=toWord(key);
		if(wa.length>16) wa=core(wa,key.length*chrsz);
		var l=[], r=[];
		for(var i=0; i<16; i++){
			l[i]=wa[i]^0x36363636;
			r[i]=wa[i]^0x5c5c5c5c;
		}
		var h=core(l.concat(toWord(data)),512+data.length*chrsz);
		return core(r.concat(h),640);
	}

	//	Public functions
	this.compute=function(/* string */data, /* dojo.crypto.outputTypes */outputType){
		//	summary
		//	computes the digest of data, and returns the result as a string of type outputType
		var out=outputType||dojo.crypto.outputTypes.Base64;
		switch(out){
			case dojo.crypto.outputTypes.Hex:{
				return toHex(core(toWord(data),data.length*chrsz));	//	string
			}
			case dojo.crypto.outputTypes.String:{
				return toString(core(toWord(data),data.length*chrsz));	//	string
			}
			default:{
				return toBase64(core(toWord(data),data.length*chrsz));	//	string
			}
		}
	};
	this.getHMAC=function(/* string */data, /* string */key, /* dojo.crypto.outputTypes */outputType){
		//	summary
		//	computes a digest of data using key, and returns the result as a string of outputType
		var out=outputType||dojo.crypto.outputTypes.Base64;
		switch(out){
			case dojo.crypto.outputTypes.Hex:{
				return toHex(hmac(data,key));	//	string
			}
			case dojo.crypto.outputTypes.String:{
				return toString(hmac(data,key));	//	string
			}
			default:{
				return toBase64(hmac(data,key));	//	string
			}
		}
	};
}();

__CPAN_FILE__ src/crypto/Blowfish.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.crypto");
dojo.provide("dojo.crypto.Blowfish");

/*	Blowfish
 *	Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/)
 *	Unsigned math functions derived from Joe Gregorio's SecureSyndication GM script
 *	http://bitworking.org/projects/securesyndication/
 *	(Note that this is *not* an adaption of the above script)
 *
 *	version 1.0 
 *	TRT 
 *	2005-12-08
 */
dojo.crypto.Blowfish = new function(){
	//	summary
	//	Object for doing Blowfish encryption/decryption.
	var POW2=Math.pow(2,2);
	var POW3=Math.pow(2,3);
	var POW4=Math.pow(2,4);
	var POW8=Math.pow(2,8);
	var POW16=Math.pow(2,16);
	var POW24=Math.pow(2,24);
	var iv=null;	//	CBC mode initialization vector
	var boxes={
		p:[
			0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 
			0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 
			0x9216d5d9, 0x8979fb1b
		],
		s0:[
			0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
			0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
			0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
			0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
			0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
			0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
			0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
			0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
			0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
			0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
			0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 
			0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 
			0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 
			0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
			0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
			0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
			0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 
			0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 
			0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 
			0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 
			0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
			0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 
			0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
			0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 
			0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
			0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
			0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
			0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
			0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
			0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
			0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
			0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
		],
		s1:[
			0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
			0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
			0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
			0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
			0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
			0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
			0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
			0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 
			0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 
			0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
			0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 
			0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
			0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 
			0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 
			0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
			0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 
			0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
			0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 
			0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
			0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 
			0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 
			0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 
			0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
			0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
			0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 
			0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
			0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
			0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
			0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
			0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
			0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
			0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
		],
		s2:[
			0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
			0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
			0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
			0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
			0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
			0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
			0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
			0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
			0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
			0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
			0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
			0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
			0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
			0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
			0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
			0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
			0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
			0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
			0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
			0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
			0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 
			0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
			0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
			0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 
			0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 
			0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 
			0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 
			0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
			0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
			0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 
			0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
			0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
		],
		s3:[
			0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
			0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
			0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 
			0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
			0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 
			0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 
			0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
			0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 
			0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 
			0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 
			0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
			0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 
			0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 
			0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 
			0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
			0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
			0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 
			0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
			0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 
			0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 
			0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 
			0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 
			0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
			0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 
			0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
			0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 
			0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 
			0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 
			0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 
			0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
			0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
			0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
		]
	}
////////////////////////////////////////////////////////////////////////////
	function add(x,y){
		var sum=(x+y)&0xffffffff;
		if (sum<0){
			sum=-sum;
			return (0x10000*((sum>>16)^0xffff))+(((sum&0xffff)^0xffff)+1);
		}
		return sum;
	}
	function split(x){
		var r=x&0xffffffff;
		if(r<0) {
			r=-r;
			return [((r&0xffff)^0xffff)+1,(r>>16)^0xffff];
		}
		return [r&0xffff,(r>>16)];
	}
	function xor(x,y){
		var xs=split(x);
		var ys=split(y);
		return (0x10000*(xs[1]^ys[1]))+(xs[0]^ys[0]);
	}
	function $(v, box){
		var d=v&0xff; v>>=8;
		var c=v&0xff; v>>=8;
		var b=v&0xff; v>>=8;
		var a=v&0xff;
		var r=add(box.s0[a],box.s1[b]);
		r=xor(r,box.s2[c]);
		return add(r,box.s3[d]);
	}
////////////////////////////////////////////////////////////////////////////
	function eb(o, box){
		var l=o.left;
		var r=o.right;
		l=xor(l,box.p[0]);
		r=xor(r,xor($(l,box),box.p[1]));
		l=xor(l,xor($(r,box),box.p[2]));
		r=xor(r,xor($(l,box),box.p[3]));
		l=xor(l,xor($(r,box),box.p[4]));
		r=xor(r,xor($(l,box),box.p[5]));
		l=xor(l,xor($(r,box),box.p[6]));
		r=xor(r,xor($(l,box),box.p[7]));
		l=xor(l,xor($(r,box),box.p[8]));
		r=xor(r,xor($(l,box),box.p[9]));
		l=xor(l,xor($(r,box),box.p[10]));
		r=xor(r,xor($(l,box),box.p[11]));
		l=xor(l,xor($(r,box),box.p[12]));
		r=xor(r,xor($(l,box),box.p[13]));
		l=xor(l,xor($(r,box),box.p[14]));
		r=xor(r,xor($(l,box),box.p[15]));
		l=xor(l,xor($(r,box),box.p[16]));
		o.right=l;
		o.left=xor(r,box.p[17]);
	}

	function db(o, box){
		var l=o.left;
		var r=o.right;
		l=xor(l,box.p[17]);
		r=xor(r,xor($(l,box),box.p[16]));
		l=xor(l,xor($(r,box),box.p[15]));
		r=xor(r,xor($(l,box),box.p[14]));
		l=xor(l,xor($(r,box),box.p[13]));
		r=xor(r,xor($(l,box),box.p[12]));
		l=xor(l,xor($(r,box),box.p[11]));
		r=xor(r,xor($(l,box),box.p[10]));
		l=xor(l,xor($(r,box),box.p[9]));
		r=xor(r,xor($(l,box),box.p[8]));
		l=xor(l,xor($(r,box),box.p[7]));
		r=xor(r,xor($(l,box),box.p[6]));
		l=xor(l,xor($(r,box),box.p[5]));
		r=xor(r,xor($(l,box),box.p[4]));
		l=xor(l,xor($(r,box),box.p[3]));
		r=xor(r,xor($(l,box),box.p[2]));
		l=xor(l,xor($(r,box),box.p[1]));
		o.right=l;
		o.left=xor(r,box.p[0]);
	}

	//	Note that we aren't caching contexts here; it might take a little longer
	//	but we should be more secure this way.
	function init(key){
		var k=key;
		if (typeof(k)=="string"){
			var a=[];
			for(var i=0; i<k.length; i++) 
				a.push(k.charCodeAt(i)&0xff);
			k=a;
		}
		//	init the boxes
		var box = { p:[], s0:[], s1:[], s2:[], s3:[] };
		for(var i=0; i<boxes.p.length; i++) box.p.push(boxes.p[i]);
		for(var i=0; i<boxes.s0.length; i++) box.s0.push(boxes.s0[i]);
		for(var i=0; i<boxes.s1.length; i++) box.s1.push(boxes.s1[i]);
		for(var i=0; i<boxes.s2.length; i++) box.s2.push(boxes.s2[i]);
		for(var i=0; i<boxes.s3.length; i++) box.s3.push(boxes.s3[i]);

		//	init p with the key
		var pos=0;
		var data=0;
		for(var i=0; i < box.p.length; i++){
			for (var j=0; j<4; j++){
				data = (data*POW8) | k[pos];
				if(++pos==k.length) pos=0;
			}
			box.p[i] = xor(box.p[i], data);
		}

		//	encrypt p and the s boxes
		var res={ left:0, right:0 };
		for(var i=0; i<box.p.length;){
			eb(res, box);
			box.p[i++]=res.left;
			box.p[i++]=res.right;
		}
		for (var i=0; i<4; i++){
			for(var j=0; j<box["s"+i].length;){
				eb(res, box);
				box["s"+i][j++]=res.left;
				box["s"+i][j++]=res.right;
			}
		}
		return box;
	}

////////////////////////////////////////////////////////////////////////////
//	CONVERSION FUNCTIONS
////////////////////////////////////////////////////////////////////////////
	//	these operate on byte arrays, NOT word arrays.
	function toBase64(ba){ 
		var p="=";
		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var s=[];
		var l=ba.length;
		var rm=l%3;
		var x=l-rm;
		for (var i=0; i<x;){
			var t=ba[i++]<<16|ba[i++]<<8|ba[i++];
			s.push(tab.charAt((t>>>18)&0x3f)); 
			s.push(tab.charAt((t>>>12)&0x3f));
			s.push(tab.charAt((t>>>6)&0x3f));
			s.push(tab.charAt(t&0x3f));
		}
		//	deal with trailers, based on patch from Peter Wood.
		switch(rm){
			case 2:{
				var t=ba[i++]<<16|ba[i++]<<8;
				s.push(tab.charAt((t>>>18)&0x3f));
				s.push(tab.charAt((t>>>12)&0x3f));
				s.push(tab.charAt((t>>>6)&0x3f));
				s.push(p);
				break;
			}
			case 1:{
				var t=ba[i++]<<16;
				s.push(tab.charAt((t>>>18)&0x3f));
				s.push(tab.charAt((t>>>12)&0x3f));
				s.push(p);
				s.push(p);
				break;
			}
		}
		return s.join("");
	}
	function fromBase64(str){
		var s=str.split("");
		var p="=";
		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var out=[];
		var l=s.length;
		while(s[--l]==p){ }
		for (var i=0; i<l;){
			var t=tab.indexOf(s[i++])<<18|tab.indexOf(s[i++])<<12|tab.indexOf(s[i++])<<6|tab.indexOf(s[i++]);
			out.push((t>>>16)&0xff);
			out.push((t>>>8)&0xff);
			out.push(t&0xff);
		}
		return out;
	}
////////////////////////////////////////////////////////////////////////////
//	PUBLIC FUNCTIONS
//	0.2: Only supporting ECB mode for now.
////////////////////////////////////////////////////////////////////////////
	this.getIV=function(/* dojo.crypto.outputTypes? */ outputType){
		//	summary
		//	returns the initialization vector in the output format specified by outputType
		var out=outputType||dojo.crypto.outputTypes.Base64;
		switch(out){
			case dojo.crypto.outputTypes.Hex:{
				var s=[];
				for(var i=0; i<iv.length; i++)
					s.push((iv[i]).toString(16));
				return s.join("");		//	string
			}
			case dojo.crypto.outputTypes.String:{
				return iv.join("");		//	string
			}
			case dojo.crypto.outputTypes.Raw:{
				return iv;				//	array
			}
			default:{
				return toBase64(iv); 	//	 string
			}
		}
	};
	this.setIV=function(/* string */data, /* dojo.crypto.outputTypes? */inputType){
		//	summary
		//	sets the initialization vector to data (as interpreted as inputType)
		var ip=inputType||dojo.crypto.outputTypes.Base64;
		var ba=null;
		switch(ip){
			case dojo.crypto.outputTypes.String:{
				ba=[];
				for (var i=0; i<data.length; i++){
					ba.push(data.charCodeAt(i));
				}
				break;
			}
			case dojo.crypto.outputTypes.Hex:{
				ba=[];
				var i=0;
				while (i+1<data.length){
					ba.push(parseInt(data.substr(i,2),16));
					i+=2;
				}
				break;
			}
			case dojo.crypto.outputTypes.Raw:{
				ba=data;
				break;
			}
			default:{
				ba=fromBase64(data);
				break;
			}
		}
		//	make it a pair of words now
		iv={};
		iv.left=ba[0]*POW24|ba[1]*POW16|ba[2]*POW8|ba[3];
		iv.right=ba[4]*POW24|ba[5]*POW16|ba[6]*POW8|ba[7];
	}
	this.encrypt = function(/* string */plaintext, /* string */key, /* object? */ao){
		//	summary
		//	encrypts plaintext using key; allows user to specify output type and cipher mode via keyword object "ao"
		var out=dojo.crypto.outputTypes.Base64;
		var mode=dojo.crypto.cipherModes.EBC;
		if (ao){
			if (ao.outputType) out=ao.outputType;
			if (ao.cipherMode) mode=ao.cipherMode;
		}

		var bx = init(key);
		var padding = 8-(plaintext.length&7);
		for (var i=0; i<padding; i++) plaintext+=String.fromCharCode(padding);
		var cipher=[];
		var count=plaintext.length >> 3;
		var pos=0;
		var o={};
		var isCBC=(mode==dojo.crypto.cipherModes.CBC);
		var vector={left:iv.left||null, right:iv.right||null};
		for(var i=0; i<count; i++){
			o.left=plaintext.charCodeAt(pos)*POW24
				|plaintext.charCodeAt(pos+1)*POW16
				|plaintext.charCodeAt(pos+2)*POW8
				|plaintext.charCodeAt(pos+3);
			o.right=plaintext.charCodeAt(pos+4)*POW24
				|plaintext.charCodeAt(pos+5)*POW16
				|plaintext.charCodeAt(pos+6)*POW8
				|plaintext.charCodeAt(pos+7);

			if(isCBC){
				o.left=xor(o.left, vector.left);
				o.right=xor(o.right, vector.right);
			}

			eb(o, bx);	//	encrypt the block

			if(isCBC){
				vector.left=o.left;
				vector.right=o.right;dojo.crypto.outputTypes.Hex
			}

			cipher.push((o.left>>24)&0xff); 
			cipher.push((o.left>>16)&0xff); 
			cipher.push((o.left>>8)&0xff);
			cipher.push(o.left&0xff);
			cipher.push((o.right>>24)&0xff); 
			cipher.push((o.right>>16)&0xff); 
			cipher.push((o.right>>8)&0xff);
			cipher.push(o.right&0xff);
			pos+=8;
		}
		switch(out){
			case dojo.crypto.outputTypes.Hex:{
				var s=[];
				for(var i=0; i<cipher.length; i++)
					s.push((cipher[i]).toString(16));
				return s.join("");	//	string
			}
			case dojo.crypto.outputTypes.String:{
				return cipher.join("");	//	string
			}
			case dojo.crypto.outputTypes.Raw:{
				return cipher;	//	array
			}
			default:{
				return toBase64(cipher);	//	string
			}
		}
	};

	this.decrypt = function(/* string */ciphertext, /* string */key, /* object? */ao){
		//	summary
		//	decrypts ciphertext using key; allows specification of how ciphertext is encoded via ao.
		var ip=dojo.crypto.outputTypes.Base64;
		var mode=dojo.crypto.cipherModes.EBC;
		if (ao){
			if (ao.outputType) ip=ao.outputType;
			if (ao.cipherMode) mode=ao.cipherMode;
		}
		var bx = init(key);
		var pt=[];
	
		var c=null;
		switch(ip){
			case dojo.crypto.outputTypes.Hex:{
				c=[];
				var i=0;
				while (i+1<ciphertext.length){
					c.push(parseInt(ciphertext.substr(i,2),16));
					i+=2;
				}
				break;
			}
			case dojo.crypto.outputTypes.String:{
				c=[];
				for (var i=0; i<ciphertext.length; i++){
					c.push(ciphertext.charCodeAt(i));
				}
				break;
			}
			case dojo.crypto.outputTypes.Raw:{
				c=ciphertext;	//	should be a byte array
				break;
			}
			default:{
				c=fromBase64(ciphertext);
				break;
			}
		}

		var count=c.length >> 3;
		var pos=0;
		var o={};
		var isCBC=(mode==dojo.crypto.cipherModes.CBC);
		var vector={left:iv.left||null, right:iv.right||null};
		for(var i=0; i<count; i++){
			o.left=c[pos]*POW24|c[pos+1]*POW16|c[pos+2]*POW8|c[pos+3];
			o.right=c[pos+4]*POW24|c[pos+5]*POW16|c[pos+6]*POW8|c[pos+7];

			if(isCBC){
				var left=o.left;
				var right=o.right;
			}

			db(o, bx);	//	decrypt the block

			if(isCBC){
				o.left=xor(o.left, vector.left);
				o.right=xor(o.right, vector.right);
				vector.left=left;
				vector.right=right;
			}

			pt.push((o.left>>24)&0xff);
			pt.push((o.left>>16)&0xff);
			pt.push((o.left>>8)&0xff);
			pt.push(o.left&0xff);
			pt.push((o.right>>24)&0xff);
			pt.push((o.right>>16)&0xff);
			pt.push((o.right>>8)&0xff);
			pt.push(o.right&0xff);
			pos+=8;
		}

		//	check for padding, and remove.
		if(pt[pt.length-1]==pt[pt.length-2]||pt[pt.length-1]==0x01){
			var n=pt[pt.length-1];
			pt.splice(pt.length-n, n);
		}

		//	convert to string
		for(var i=0; i<pt.length; i++)
			pt[i]=String.fromCharCode(pt[i]);
		return pt.join("");		//	string
	};

	this.setIV("0000000000000000", dojo.crypto.outputTypes.Hex);
}();

__CPAN_FILE__ src/crypto/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.crypto",
		"dojo.crypto.MD5"
	]
});
dojo.provide("dojo.crypto.*");

__CPAN_FILE__ src/crypto/SHA1.js
dojo.require("dojo.crypto");
dojo.provide("dojo.crypto.SHA1");
dojo.require("dojo.experimental");

/*
 *	A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 *	in FIPS PUB 180-1
 *
 * 	Version 2.1a Copyright Paul Johnston 2000 - 2002.
 * 	Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * 	Distributed under the BSD License
 * 	See http://pajhome.org.uk/crypt/md5 for details.
 *
 *	Dojo port by Tom Trenka
 */
dojo.experimental("dojo.crypto.SHA1");

dojo.crypto.SHA1 = new function(){
	var chrsz=8;
	var mask=(1<<chrsz)-1;
	function toWord(s) {
	  var wa=[];
	  for(var i=0; i<s.length*chrsz; i+=chrsz)
		wa[i>>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32);
	  return wa;
	}
	function toString(wa){
		var s=[];
		for(var i=0; i<wa.length*32; i+=chrsz)
			s.push(String.fromCharCode((wa[i>>5]>>>(i%32))&mask));
		return s.join("");
	}
	function toHex(wa) {
		var h="0123456789abcdef";
		var s=[];
		for(var i=0; i<wa.length*4; i++){
			s.push(h.charAt((wa[i>>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF));
		}
		return s.join("");
	}
	function toBase64(wa){
		var p="=";
		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var s=[];
		for(var i=0; i<wa.length*4; i+=3){
			var t=(((wa[i>>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF);
			for(var j=0; j<4; j++){
				if(i*8+j*6>wa.length*32) s.push(p);
				else s.push(tab.charAt((t>>6*(3-j))&0x3F));
			}
		}
		return s.join("");
	}

	//	math
	function add(x,y){
		var l=(x&0xffff)+(y&0xffff);
		var m=(x>>16)+(y>>16)+(l>>16);
		return (m<<16)|(l&0xffff);
	}
	function r(x,n){  return (x<<n)|(x>>>(32-n)); }
	
	//	SHA rounds
	function f(u,v,w){ return ((u&v)|(~u&w)); }
	function g(u,v,w){ return ((u&v)|(u&w)|(v&w)); }
	function h(u,v,w){ return (u^v^w); }
	
	function fn(i,u,v,w){
		if(i<20) return f(u,v,w);
		if(i<40) return h(u,v,w);
		if(i<60) return g(u,v,w);
		return h(u,v,w);
	}
	function cnst(i){
		if(i<20) return 1518500249;
		if(i<40) return 1859775393;
		if(i<60) return -1894007588;
		return -899497514;
	}

	function core(x,len){
		x[len>>5]|=0x80<<(24-len%32);
		x[((len+64>>9)<<4)+15]=len;

		var w=[];
		var a= 1732584193;		//	0x67452301
		var b=-271733879;		//	0xefcdab89
		var c=-1732584194;		//	0x98badcfe
		var d= 271733878;		//	0x10325476
		var e=-1009589776;		//	0xc3d2e1f0
		
		for(var i=0; i<x.length; i+=16){
			var olda=a;
			var oldb=b;
			var oldc=c;
			var oldd=d;
			var olde=e;

			for(var j=0; j<80; j++){
				if(j<16) w[j]=x[i+j];
				else w[j]=r(w[j-3]^w[j-8]^w[j-14]^w[j-16],1);
				var t=add(add(r(a,5),fn(j,b,c,d)),add(add(e,w[j]),cnst(j)));
				e=d; d=c; c=r(b,30); b=a; a=t;
			}

			a=add(a,olda);
			b=add(b,oldb);
			c=add(c,oldc);
			d=add(d,oldd);
			e=add(e,olde);
		}
		return [a,b,c,d,e];
	}
	function hmac(data,key){
		var wa=toWord(key);
		if(wa.length>16) wa=core(wa,key.length*chrsz);
		var l=[], r=[];
		for(var i=0; i<16; i++){
			l[i]=wa[i]^0x36363636;
			r[i]=wa[i]^0x5c5c5c5c;
		}
		var h=core(l.concat(toWord(data)),512+data.length*chrsz);
		return core(r.concat(h),640);
	}

	this.compute=function(data,outputType){
		var out=outputType||dojo.crypto.outputTypes.Base64;
		switch(out){
			case dojo.crypto.outputTypes.Hex:{
				return toHex(core(toWord(data),data.length*chrsz));
			}
			case dojo.crypto.outputTypes.String:{
				return toString(core(toWord(data),data.length*chrsz));
			}
			default:{
				return toBase64(core(toWord(data),data.length*chrsz));
			}
		}
	};
	this.getHMAC=function(data,key,outputType){
		var out=outputType||dojo.crypto.outputTypes.Base64;
		switch(out){
			case dojo.crypto.outputTypes.Hex:{
				return toHex(hmac(data,key));
			}
			case dojo.crypto.outputTypes.String:{
				return toString(hmac(data,key));
			}
			default:{
				return toBase64(hmac(data,key));
			}
		}
	};
}();

__CPAN_DIR__ src/cal
__CPAN_FILE__ src/cal/textDirectory.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.cal.textDirectory");
dojo.require("dojo.string");

/*
 * This class parses a single line from a text/directory file
 * and returns an object with four named values; name, group, params
 * and value. name, group and value are strings containing the original
 * tokens unaltered and values is an array containing name/value pairs
 * or a single name token packed into arrays.
 */
dojo.cal.textDirectory.Property = function (line) {
	// split into name/value pair
	var left = dojo.string.trim(line.substring(0, line.indexOf(':')));
	var right = dojo.string.trim(line.substr(line.indexOf(':') + 1));

	// seperate name and paramters	
	var parameters = dojo.string.splitEscaped(left,';');
	this.name = parameters[0]
	parameters.splice(0, 1);

	// parse paramters
	this.params = [];
	for (var i = 0; i < parameters.length; i++) {
		var arr = parameters[i].split("=");
		var key = dojo.string.trim(arr[0].toUpperCase());
		
		if (arr.length == 1) { this.params.push([key]); continue; }
		
		var values = dojo.string.splitEscaped(arr[1],',');
		for (var j = 0; j < values.length; j++) {
			if (dojo.string.trim(values[j]) != '') {
				this.params.push([key, dojo.string.trim(values[j])]);
			}
		}
	}

	// seperate group
	if (this.name.indexOf('.') > 0) {
		var arr = this.name.split('.');
		this.group = arr[0];
		this.name = arr[1];
	}
	
	// don't do any parsing, leave to implementation
	this.value = right;
}


// tokeniser, parses into an array of properties.
dojo.cal.textDirectory.tokenise = function (text) {
	// normlize to one propterty per line and parse
	var nText = dojo.string.normalizeNewlines(text,"\n");
	nText = nText.replace(/\n[ \t]/g, '');
	nText = nText.replace(/\x00/g, '');
		
	var lines = nText.split("\n");
	var properties = []

	for (var i = 0; i < lines.length; i++) {
		if (dojo.string.trim(lines[i]) == '') { continue; }
		var prop = new dojo.cal.textDirectory.Property(lines[i]);
		properties.push(prop);
	}
	return properties;
}

__CPAN_FILE__ src/cal/iCalendar.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.cal.iCalendar");
dojo.require("dojo.lang.common");
dojo.require("dojo.cal.textDirectory");
dojo.require("dojo.date.common");
dojo.require("dojo.date.serialize");


dojo.cal.iCalendar.fromText =  function (/* string */text) {
	// summary
	// Parse text of an iCalendar and return an array of iCalendar objects

	var properties = dojo.cal.textDirectory.tokenise(text);
	var calendars = [];

	//dojo.debug("Parsing iCal String");
	for (var i = 0, begun = false; i < properties.length; i++) {
		var prop = properties[i];
		if (!begun) {
			if (prop.name == 'BEGIN' && prop.value == 'VCALENDAR') {
				begun = true;
				var calbody = [];
			}
		} else if (prop.name == 'END' && prop.value == 'VCALENDAR') {
			calendars.push(new dojo.cal.iCalendar.VCalendar(calbody));
			begun = false;
		} else {
			calbody.push(prop);
		}
	}
	return /* array */calendars;
}


dojo.cal.iCalendar.Component = function (/* string */ body ) {
	// summary
	// A component is the basic container of all this stuff. 

	if (!this.name) {
		this.name = "COMPONENT"
	}

	this.properties = [];
	this.components = [];

	if (body) {
		for (var i = 0, context = ''; i < body.length; i++) {
			if (context == '') {
				if (body[i].name == 'BEGIN') {
					context = body[i].value;
					var childprops = [];
				} else {
					this.addProperty(new dojo.cal.iCalendar.Property(body[i]));
				}
			} else if (body[i].name == 'END' && body[i].value == context) {
				if (context=="VEVENT") {
					this.addComponent(new dojo.cal.iCalendar.VEvent(childprops));
				} else if (context=="VTIMEZONE") {
					this.addComponent(new dojo.cal.iCalendar.VTimeZone(childprops));
				} else if (context=="VTODO") {
					this.addComponent(new dojo.cal.iCalendar.VTodo(childprops));
				} else if (context=="VJOURNAL") {
					this.addComponent(new dojo.cal.iCalendar.VJournal(childprops));
				} else if (context=="VFREEBUSY") {
					this.addComponent(new dojo.cal.iCalendar.VFreeBusy(childprops));
				} else if (context=="STANDARD") {
					this.addComponent(new dojo.cal.iCalendar.Standard(childprops));
				} else if (context=="DAYLIGHT") {
					this.addComponent(new dojo.cal.iCalendar.Daylight(childprops));
				} else if (context=="VALARM") {
					this.addComponent(new dojo.cal.iCalendar.VAlarm(childprops));
				}else {
					dojo.unimplemented("dojo.cal.iCalendar." + context);
				}
				context = '';
			} else {
				childprops.push(body[i]);
			}
		}

		if (this._ValidProperties) {
			this.postCreate();
		}
	}
}

dojo.extend(dojo.cal.iCalendar.Component, {

	addProperty: function (prop) {
		// summary
		// push a new property onto a component.
		this.properties.push(prop);
		this[prop.name.toLowerCase()] = prop;
	},

	addComponent: function (prop) {
		// summary
		// add a component to this components list of children.
		this.components.push(prop);
	},

	postCreate: function() {
		for (var x=0; x<this._ValidProperties.length; x++) {
			var evtProperty = this._ValidProperties[x];
			var found = false;
	
			for (var y=0; y<this.properties.length; y++) {	
				var prop = this.properties[y];
				var propName = prop.name.toLowerCase();
				if (dojo.lang.isArray(evtProperty)) {

					var alreadySet = false;
					for (var z=0; z<evtProperty.length; z++) {
						var evtPropertyName = evtProperty[z].name.toLowerCase();
						if((this[evtPropertyName])  && (evtPropertyName != propName )) {
							alreadySet=true;
						} 
					}
					if (!alreadySet) {
						this[propName] = prop;
					}
				} else {
					if (propName == evtProperty.name.toLowerCase()) {
						found = true;
						if (evtProperty.occurance == 1){
							this[propName] = prop;
						} else {
							found = true;
							if (!dojo.lang.isArray(this[propName])) {
							 	this[propName] = [];
							}
							this[propName].push(prop);
						}
					}
				}
			}

			if (evtProperty.required && !found) {	
				dojo.debug("iCalendar - " + this.name + ": Required Property not found: " + evtProperty.name);
			}
		}

		// parse any rrules		
		if (dojo.lang.isArray(this.rrule)) {
			for(var x=0; x<this.rrule.length; x++) {
				var rule = this.rrule[x].value;

				//add a place to cache dates we have checked for recurrance
				this.rrule[x].cache = function() {};
				
				var temp = rule.split(";");
				for (var y=0; y<temp.length; y++) {
					var pair = temp[y].split("=");
					var key = pair[0].toLowerCase();
					var val = pair[1];

					if ((key == "freq") || (key=="interval") || (key=="until")) {
						this.rrule[x][key]= val;
					} else {
						var valArray = val.split(",");
						this.rrule[x][key] = valArray; 
					}
				}	
			}
			this.recurring = true;
		}

	}, 

	toString: function () {
		// summary
		// output a string representation of this component.
		return "[iCalendar.Component; " + this.name + ", " + this.properties.length +
			" properties, " + this.components.length + " components]";
	}
});

dojo.cal.iCalendar.Property = function (prop) {
	// summary
	// A single property of a component.

	// unpack the values
	this.name = prop.name;
	this.group = prop.group;
	this.params = prop.params;
	this.value = prop.value;

}

dojo.extend(dojo.cal.iCalendar.Property, {
	toString: function () {	
		// summary
		// output a string reprensentation of this component.
		return "[iCalenday.Property; " + this.name + ": " + this.value + "]";
	}
});

// This is just a little helper function for the Component Properties
var _P = function (n, oc, req) {
	return {name: n, required: (req) ? true : false,
		occurance: (oc == '*' || !oc) ? -1 : oc}
}

/*
 * VCALENDAR
 */

dojo.cal.iCalendar.VCalendar = function (/* string */ calbody) {
	// summary
	// VCALENDAR Component

	this.name = "VCALENDAR";
	this.recurring = [];
	this.nonRecurringEvents = function(){};
	dojo.cal.iCalendar.Component.call(this, calbody);
}

dojo.inherits(dojo.cal.iCalendar.VCalendar, dojo.cal.iCalendar.Component);

dojo.extend(dojo.cal.iCalendar.VCalendar, {

	addComponent: function (prop) {
		// summary
		// add component to the calenadar that makes it easy to pull them out again later.
		this.components.push(prop);
		if (prop.name.toLowerCase() == "vevent") {
			if (prop.rrule) {
				this.recurring.push(prop);
			} else {
				var startDate = prop.getDate();
				var month = startDate.getMonth() + 1;
				var dateString= month + "-" + startDate.getDate() + "-" + startDate.getFullYear();
				if (!dojo.lang.isArray(this[dateString])) {
					this.nonRecurringEvents[dateString] = [];
				}
				this.nonRecurringEvents[dateString].push(prop);
			}
		}
	},

	preComputeRecurringEvents: function(until) {
		var calculatedEvents = function(){};

		for(var x=0; x<this.recurring.length; x++) {
			var dates = this.recurring[x].getDates(until);
			for (var y=0; y<dates.length;y++) {
				var month = dates[y].getMonth() + 1;
				var dateStr = month + "-" + dates[y].getDate() + "-" + dates[y].getFullYear();
				if (!dojo.lang.isArray(calculatedEvents[dateStr])) {
					calculatedEvents[dateStr] = [];
				}

				if (!dojo.lang.inArray(calculatedEvents[dateStr], this.recurring[x])) { 
					calculatedEvents[dateStr].push(this.recurring[x]);
				} 
			}
		}
		this.recurringEvents = calculatedEvents;
	
	},

	getEvents: function(/* Date */ date) {
		// summary
		// Gets all events occuring on a particular date
		var events = [];
		var recur = [];
		var nonRecur = [];
		var month = date.getMonth() + 1;
		var dateStr= month + "-" + date.getDate() + "-" + date.getFullYear();
		if (dojo.lang.isArray(this.nonRecurringEvents[dateStr])) {
			nonRecur= this.nonRecurringEvents[dateStr];
			dojo.debug("Number of nonRecurring Events: " + nonRecur.length);
		} 
		

		if (dojo.lang.isArray(this.recurringEvents[dateStr])) {
			recur= this.recurringEvents[dateStr];
		} 

		events = recur.concat(nonRecur);

		if (events.length > 0) {
			return events;
		} 

		return null;			
	}
});

/*
 * STANDARD
 */

var StandardProperties = [
	_P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true),
	_P("comment"), _P("rdate"), _P("rrule"), _P("tzname")
];


dojo.cal.iCalendar.Standard = function (/* string */ body) {
	// summary
	// STANDARD Component

	this.name = "STANDARD";
	this._ValidProperties = StandardProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.Standard, dojo.cal.iCalendar.Component);

/*
 * DAYLIGHT
 */

var DaylightProperties = [
	_P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true),
	_P("comment"), _P("rdate"), _P("rrule"), _P("tzname")
];

dojo.cal.iCalendar.Daylight = function (/* string */ body) {
	// summary
	// Daylight Component
	this.name = "DAYLIGHT";
	this._ValidProperties = DaylightProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.Daylight, dojo.cal.iCalendar.Component);

/*
 * VEVENT
 */

var VEventProperties = [
	// these can occur once only
	_P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1),
	_P("geo", 1), _P("last-mod", 1), _P("location", 1), _P("organizer", 1),
	_P("priority", 1), _P("dtstamp", 1), _P("seq", 1), _P("status", 1),
	_P("summary", 1), _P("transp", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1),
	// these two are exclusive
	[_P("dtend", 1), _P("duration", 1)],
	// these can occur many times over
	_P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"),
	_P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"),
	_P("rdate"), _P("rrule")
];

dojo.cal.iCalendar.VEvent = function (/* string */ body) {
	// summary 
	// VEVENT Component
	this._ValidProperties = VEventProperties;
	this.name = "VEVENT";
	dojo.cal.iCalendar.Component.call(this, body);
	this.recurring = false;
	this.startDate = dojo.date.fromIso8601(this.dtstart.value);
}

dojo.inherits(dojo.cal.iCalendar.VEvent, dojo.cal.iCalendar.Component);

dojo.extend(dojo.cal.iCalendar.VEvent, {
		getDates: function(until) {
			var dtstart = this.getDate();

			var recurranceSet = [];
			var weekdays=["su","mo","tu","we","th","fr","sa"];
			var order = { 
				"daily": 1, "weekly": 2, "monthly": 3, "yearly": 4,
				"byday": 1, "bymonthday": 1, "byweekno": 2, "bymonth": 3, "byyearday": 4};

			// expand rrules into the recurrance 
			for (var x=0; x<this.rrule.length; x++) {
				var rrule = this.rrule[x];
				var freq = rrule.freq.toLowerCase();
				var interval = 1;

				if (rrule.interval > interval) {
					interval = rrule.interval;
				}

				var set = [];
				var freqInt = order[freq];

				if (rrule.until) {
					var tmpUntil = dojo.date.fromIso8601(rrule.until);
				} else {
					var tmpUntil = until
				}

				if (tmpUntil > until) {
					tmpUntil = until
				}


				if (dtstart<tmpUntil) {

					var expandingRules = function(){};
					var cullingRules = function(){};
					expandingRules.length=0;
					cullingRules.length =0;

					switch(freq) {
						case "yearly":
							var nextDate = new Date(dtstart);
							set.push(nextDate);
							while(nextDate < tmpUntil) {
								nextDate.setYear(nextDate.getFullYear()+interval);
								tmpDate = new Date(nextDate);
								if(tmpDate < tmpUntil) {
									set.push(tmpDate);
								}
							}
							break;
						case "monthly":
							nextDate = new Date(dtstart);
							set.push(nextDate);
							while(nextDate < tmpUntil) {
								nextDate.setMonth(nextDate.getMonth()+interval);
								var tmpDate = new Date(nextDate);
								if (tmpDate < tmpUntil) {
									set.push(tmpDate);
								}
							}
							break;
						case "weekly":
							nextDate = new Date(dtstart);
							set.push(nextDate);
							while(nextDate < tmpUntil) {
								nextDate.setDate(nextDate.getDate()+(7*interval));
								var tmpDate = new Date(nextDate);
								if (tmpDate < tmpUntil) {
									set.push(tmpDate);
								}
							}
							break;	
						case "daily":
							nextDate = new Date(dtstart);
							set.push(nextDate);
							while(nextDate < tmpUntil) {
								nextDate.setDate(nextDate.getDate()+interval);
								var tmpDate = new Date(nextDate);
								if (tmpDate < tmpUntil) {
									set.push(tmpDate);
								}
							}
							break;
	
					}

					if ((rrule["bymonth"]) && (order["bymonth"]<freqInt))	{
						for (var z=0; z<rrule["bymonth"].length; z++) {
							if (z==0) {
								for (var zz=0; zz < set.length; zz++) {
									set[zz].setMonth(rrule["bymonth"][z]-1);
								}
							} else {
								var subset=[];
								for (var zz=0; zz < set.length; zz++) {
									var newDate = new Date(set[zz]);
									newDate.setMonth(rrule[z]);
									subset.push(newDate);
								}
								tmp = set.concat(subset);
								set = tmp;
							}
						}
					}

					
					// while the spec doesn't prohibit it, it makes no sense to have a bymonth and a byweekno at the same time
					// and if i'm wrong then i don't know how to apply that rule.  This is also documented elsewhere on the web
					if (rrule["byweekno"] && !rrule["bymonth"]) {	
						dojo.debug("TODO: no support for byweekno yet");
					}


					// while the spec doesn't prohibit it, it makes no sense to have a bymonth and a byweekno at the same time
					// and if i'm wrong then i don't know how to apply that rule.  This is also documented elsewhere on the web
					if (rrule["byyearday"] && !rrule["bymonth"] && !rrule["byweekno"] ) {	
						if (rrule["byyearday"].length > 1) {
							var regex = "([+-]?)([0-9]{1,3})";
							for (var z=1; x<rrule["byyearday"].length; z++) {
								var regexResult = rrule["byyearday"][z].match(regex);
								if (z==1) {
									for (var zz=0; zz < set.length; zz++) {
										if (regexResult[1] == "-") {
											dojo.date.setDayOfYear(set[zz],366-regexResult[2]);
										} else {
											dojo.date.setDayOfYear(set[zz],regexResult[2]);
										}
									}
								}	else {
									var subset=[];
									for (var zz=0; zz < set.length; zz++) {
										var newDate = new Date(set[zz]);
										if (regexResult[1] == "-") {
											dojo.date.setDayOfYear(newDate,366-regexResult[2]);
										} else {
											dojo.date.setDayOfYear(newDate,regexResult[2]);
										}
										subset.push(newDate);
									}
									tmp = set.concat(subset);
									set = tmp;
								}
							}
						}
					}

					if (rrule["bymonthday"]  && (order["bymonthday"]<freqInt)) {	
						if (rrule["bymonthday"].length > 0) {
							var regex = "([+-]?)([0-9]{1,3})";
							for (var z=0; z<rrule["bymonthday"].length; z++) {
								var regexResult = rrule["bymonthday"][z].match(regex);
								if (z==0) {
									for (var zz=0; zz < set.length; zz++) {
										if (regexResult[1] == "-") {
											if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
												set[zz].setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);
											}
										} else {
											if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
												set[zz].setDate(regexResult[2]);
											}
										}
									}
								}	else {
									var subset=[];
									for (var zz=0; zz < set.length; zz++) {
										var newDate = new Date(set[zz]);
										if (regexResult[1] == "-") {
											if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
												newDate.setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);
											}
										} else {
											if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
												newDate.setDate(regexResult[2]);
											}
										}
										subset.push(newDate);
									}
									tmp = set.concat(subset);
									set = tmp;
								}
							}
						}
					}

					if (rrule["byday"]  && (order["byday"]<freqInt)) {	
						if (rrule["bymonth"]) {
							if (rrule["byday"].length > 0) {
								var regex = "([+-]?)([0-9]{0,1}?)([A-Za-z]{1,2})";
								for (var z=0; z<rrule["byday"].length; z++) {
									var regexResult = rrule["byday"][z].match(regex);
									var occurance = regexResult[2];
									var day = regexResult[3].toLowerCase();


									if (z==0) {
										for (var zz=0; zz < set.length; zz++) {
											if (regexResult[1] == "-") {
												//find the nth to last occurance of date 
												var numDaysFound = 0;
												var lastDayOfMonth = dojo.date.getDaysInMonth(set[zz]);
												var daysToSubtract = 1;
												set[zz].setDate(lastDayOfMonth); 
												if (weekdays[set[zz].getDay()] == day) {
													numDaysFound++;
													daysToSubtract=7;
												}
												daysToSubtract = 1;
												while (numDaysFound < occurance) {
													set[zz].setDate(set[zz].getDate()-daysToSubtract);	
													if (weekdays[set[zz].getDay()] == day) {
														numDaysFound++;
														daysToSubtract=7;	
													}
												}
											} else {
												if (occurance) {
													var numDaysFound=0;
													set[zz].setDate(1);
													var daysToAdd=1;

													if(weekdays[set[zz].getDay()] == day) {
														numDaysFound++;
														daysToAdd=7;
													}

													while(numDaysFound < occurance) {
														set[zz].setDate(set[zz].getDate()+daysToAdd);
														if(weekdays[set[zz].getDay()] == day) {
															numDaysFound++;
															daysToAdd=7;
														}
													}
												} else {
													//we're gonna expand here to add a date for each of the specified days for each month
													var numDaysFound=0;
													var subset = [];

													lastDayOfMonth = new Date(set[zz]);
													var daysInMonth = dojo.date.getDaysInMonth(set[zz]);
													lastDayOfMonth.setDate(daysInMonth);

													set[zz].setDate(1);
												
													if (weekdays[set[zz].getDay()] == day) {
														numDaysFound++;
													}
													var tmpDate = new Date(set[zz]);
													daysToAdd = 1;
													while(tmpDate.getDate() < lastDayOfMonth) {
														if (weekdays[tmpDate.getDay()] == day) {
															numDaysFound++;
															if (numDaysFound==1) {
																set[zz] = tmpDate;
															} else {
																subset.push(tmpDate);
																tmpDate = new Date(tmpDate);
																daysToAdd=7;	
																tmpDate.setDate(tmpDate.getDate() + daysToAdd);
															}
														} else {
															tmpDate.setDate(tmpDate.getDate() + daysToAdd);
														}
													}
													var t = set.concat(subset);
													set = t; 
												}
											}
										}
									}	else {
										var subset=[];
										for (var zz=0; zz < set.length; zz++) {
											var newDate = new Date(set[zz]);
											if (regexResult[1] == "-") {
												if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
													newDate.setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);
												}
											} else {
												if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
													newDate.setDate(regexResult[2]);
												}
											}
											subset.push(newDate);
										}
										tmp = set.concat(subset);
										set = tmp;
									}
								}
							}
						} else {
							dojo.debug("TODO: byday within a yearly rule without a bymonth");
						}
					}

					dojo.debug("TODO: Process BYrules for units larger than frequency");
			
					//add this set of events to the complete recurranceSet	
					var tmp = recurranceSet.concat(set);
					recurranceSet = tmp;
				}
			}

			// TODO: add rdates to the recurrance set here

			// TODO: subtract exdates from the recurrance set here

			//TODO:  subtract dates generated by exrules from recurranceSet here

			recurranceSet.push(dtstart);
			return recurranceSet;
		},

		getDate: function() {
			return dojo.date.fromIso8601(this.dtstart.value);
		}
});

/*
 * VTIMEZONE
 */

var VTimeZoneProperties = [
	_P("tzid", 1, true), _P("last-mod", 1), _P("tzurl", 1)

	// one of 'standardc' or 'daylightc' must occur
	// and each may occur more than once.
];

dojo.cal.iCalendar.VTimeZone = function (/* string */ body) {
	// summary
	// VTIMEZONE Component
	this.name = "VTIMEZONE";
	this._ValidProperties = VTimeZoneProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.VTimeZone, dojo.cal.iCalendar.Component);

/*
 * VTODO
 */

var VTodoProperties = [
	// these can occur once only
	_P("class", 1), _P("completed", 1), _P("created", 1), _P("description", 1),
	_P("dtstart", 1), _P("geo", 1), _P("last-mod", 1), _P("location", 1),
	_P("organizer", 1), _P("percent", 1), _P("priority", 1), _P("dtstamp", 1),
	_P("seq", 1), _P("status", 1), _P("summary", 1), _P("uid", 1), _P("url", 1),
	_P("recurid", 1),
	// these two are exclusive
	[_P("due", 1), _P("duration", 1)],
	// these can occur many times over
	_P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"),
	_P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"),
	_P("rdate"), _P("rrule")
];

dojo.cal.iCalendar.VTodo= function (/* string */ body) {
	// summary
	// VTODO Componenet
	this.name = "VTODO";
	this._ValidProperties = VTodoProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.VTodo, dojo.cal.iCalendar.Component);

/*
 * VJOURNAL
 */

var VJournalProperties = [
	// these can occur once only
	_P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1),
	_P("last-mod", 1), _P("organizer", 1), _P("dtstamp", 1), _P("seq", 1),
	_P("status", 1), _P("summary", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1),
	// these can occur many times over
	_P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"),
	_P("exdate"), _P("exrule"), _P("related"), _P("rstatus"), _P("rdate"), _P("rrule")
];

dojo.cal.iCalendar.VJournal= function (/* string */ body) {
	// summary
	// VJOURNAL Component
	this.name = "VJOURNAL";
	this._ValidProperties = VJournalProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.VJournal, dojo.cal.iCalendar.Component);

/*
 * VFREEBUSY
 */

var VFreeBusyProperties = [
	// these can occur once only
	_P("contact"), _P("dtstart", 1), _P("dtend"), _P("duration"),
	_P("organizer", 1), _P("dtstamp", 1), _P("uid", 1), _P("url", 1),
	// these can occur many times over
	_P("attendee"), _P("comment"), _P("freebusy"), _P("rstatus")
];

dojo.cal.iCalendar.VFreeBusy= function (/* string */ body) {
	// summary
	// VFREEBUSY Component
	this.name = "VFREEBUSY";
	this._ValidProperties = VFreeBusyProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.VFreeBusy, dojo.cal.iCalendar.Component);

/*
 * VALARM
 */

var VAlarmProperties = [
	[_P("action", 1, true), _P("trigger", 1, true), [_P("duration", 1), _P("repeat", 1)],
	_P("attach", 1)],

	[_P("action", 1, true), _P("description", 1, true), _P("trigger", 1, true),
	[_P("duration", 1), _P("repeat", 1)]],

	[_P("action", 1, true), _P("description", 1, true), _P("trigger", 1, true),
	_P("summary", 1, true), _P("attendee", "*", true),
	[_P("duration", 1), _P("repeat", 1)],
	_P("attach", 1)],

	[_P("action", 1, true), _P("attach", 1, true), _P("trigger", 1, true),
	[_P("duration", 1), _P("repeat", 1)],
	_P("description", 1)],
];

dojo.cal.iCalendar.VAlarm= function (/* string */ body) {
	// summary
	// VALARM Component
	this.name = "VALARM";
	this._ValidProperties = VAlarmProperties;
	dojo.cal.iCalendar.Component.call(this, body);
}

dojo.inherits(dojo.cal.iCalendar.VAlarm, dojo.cal.iCalendar.Component);


__CPAN_DIR__ src/date
__CPAN_FILE__ src/date/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.date.common");


/* Supplementary Date Functions
 *******************************/

dojo.date.setDayOfYear = function(/*Date*/dateObject, /*Number*/dayOfYear){
	// summary: sets dateObject according to day of the year (1..366)
	dateObject.setMonth(0);
	dateObject.setDate(dayOfYear);
	return dateObject; // Date
}

dojo.date.getDayOfYear = function(/*Date*/dateObject){
	// summary: gets the day of the year as represented by dateObject
	var fullYear = dateObject.getFullYear();
	var lastDayOfPrevYear = new Date(fullYear-1, 11, 31);
	return Math.floor((dateObject.getTime() -
		lastDayOfPrevYear.getTime()) / 86400000); // Number
}


dojo.date.setWeekOfYear = function(/*Date*/dateObject, /*Number*/week, /*Number*/firstDay){
	if(arguments.length == 1){ firstDay = 0; } // Sunday
	dojo.unimplemented("dojo.date.setWeekOfYear");
}

dojo.date.getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay){
	if(arguments.length == 1){ firstDay = 0; } // Sunday

	// work out the first day of the year corresponding to the week
	var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1);
	var day = firstDayOfYear.getDay();
	firstDayOfYear.setDate(firstDayOfYear.getDate() -
			day + firstDay - (day > firstDay ? 7 : 0));

	return Math.floor((dateObject.getTime() -
		firstDayOfYear.getTime()) / 604800000);
}

dojo.date.setIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/week, /*Number*/firstDay){
	// summary: unimplemented
	if (arguments.length == 1) { firstDay = 1; } // Monday
	dojo.unimplemented("dojo.date.setIsoWeekOfYear");
}

dojo.date.getIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay) {
	// summary: unimplemented
	if (arguments.length == 1) { firstDay = 1; } // Monday
	dojo.unimplemented("dojo.date.getIsoWeekOfYear");
}


/* Informational Functions
 **************************/

//DEPRECATED: These timezone arrays will be deprecated in 0.5
dojo.date.shortTimezones = ["IDLW", "BET", "HST", "MART", "AKST", "PST", "MST",
	"CST", "EST", "AST", "NFT", "BST", "FST", "AT", "GMT", "CET", "EET", "MSK",
	"IRT", "GST", "AFT", "AGTT", "IST", "NPT", "ALMT", "MMT", "JT", "AWST",
	"JST", "ACST", "AEST", "LHST", "VUT", "NFT", "NZT", "CHAST", "PHOT",
	"LINT"];
dojo.date.timezoneOffsets = [-720, -660, -600, -570, -540, -480, -420, -360,
	-300, -240, -210, -180, -120, -60, 0, 60, 120, 180, 210, 240, 270, 300,
	330, 345, 360, 390, 420, 480, 540, 570, 600, 630, 660, 690, 720, 765, 780,
	840];
/*
dojo.date.timezones = ["International Date Line West", "Bering Standard Time",
	"Hawaiian Standard Time", "Marquesas Time", "Alaska Standard Time",
	"Pacific Standard Time (USA)", "Mountain Standard Time",
	"Central Standard Time (USA)", "Eastern Standard Time (USA)",
	"Atlantic Standard Time", "Newfoundland Time", "Brazil Standard Time",
	"Fernando de Noronha Standard Time (Brazil)", "Azores Time",
	"Greenwich Mean Time", "Central Europe Time", "Eastern Europe Time",
	"Moscow Time", "Iran Standard Time", "Gulf Standard Time",
	"Afghanistan Time", "Aqtobe Time", "Indian Standard Time", "Nepal Time",
	"Almaty Time", "Myanmar Time", "Java Time",
	"Australian Western Standard Time", "Japan Standard Time",
	"Australian Central Standard Time", "Lord Hove Standard Time (Australia)",
	"Vanuata Time", "Norfolk Time (Australia)", "New Zealand Standard Time",
	"Chatham Standard Time (New Zealand)", "Phoenix Islands Time (Kribati)",
	"Line Islands Time (Kribati)"];
*/

dojo.date.getDaysInMonth = function(/*Date*/dateObject){
	// summary: returns the number of days in the month used by dateObject
	var month = dateObject.getMonth();
	var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	if (month == 1 && dojo.date.isLeapYear(dateObject)) { return 29; } // Number
	else { return days[month]; } // Number
}

dojo.date.isLeapYear = function(/*Date*/dateObject){
// summary:
//	Determines if the year of the dateObject is a leap year
//
// description:
//	Leap years are years with an additional day YYYY-02-29, where the year
//	number is a multiple of four with the following exception: If a year
//	is a multiple of 100, then it is only a leap year if it is also a
//	multiple of 400. For example, 1900 was not a leap year, but 2000 is one.

	var year = dateObject.getFullYear();
	return (year%400 == 0) ? true : (year%100 == 0) ? false : (year%4 == 0) ? true : false; // Boolean
}

// FIXME: This is not localized
dojo.date.getTimezoneName = function(/*Date*/dateObject){
// summary:
//	Get the user's time zone as provided by the browser
//
// dateObject: needed because the timezone may vary with time (daylight savings)
//
// description:
//	Try to get time zone info from toString or toLocaleString
//	method of the Date object -- UTC offset is not a time zone.
//	See http://www.twinsun.com/tz/tz-link.htm
//	Note: results may be inconsistent across browsers.

	var str = dateObject.toString(); // Start looking in toString
	var tz = ''; // The result -- return empty string if nothing found
	var match;

	// First look for something in parentheses -- fast lookup, no regex
	var pos = str.indexOf('(');
	if (pos > -1) {
		pos++;
		tz = str.substring(pos, str.indexOf(')'));
	}
	// If at first you don't succeed ...
	else{
		// If IE knows about the TZ, it appears before the year
		// Capital letters or slash before a 4-digit year 
		// at the end of string
		var pat = /([A-Z\/]+) \d{4}$/;
		if((match = str.match(pat))) {
			tz = match[1];
		}
		// Some browsers (e.g. Safari) glue the TZ on the end
		// of toLocaleString instead of putting it in toString
		else{
			str = dateObject.toLocaleString();
			// Capital letters or slash -- end of string, 
			// after space
			pat = / ([A-Z\/]+)$/;
			if((match = str.match(pat))) {
				tz = match[1];
			}
		}
	}

	// Make sure it doesn't somehow end up return AM or PM
	return tz == 'AM' || tz == 'PM' ? '' : tz; //String
}


//FIXME: not localized
dojo.date.getOrdinal = function(dateObject){
	// summary: returns the appropriate suffix (English only) for the day of the month, e.g. 'st' for 1, 'nd' for 2, etc.)
	var date = dateObject.getDate();

	if(date%100 != 11 && date%10 == 1){ return "st"; } // String
	else if(date%100 != 12 && date%10 == 2){ return "nd"; } // String
	else if(date%100 != 13 && date%10 == 3){ return "rd"; } // String
	else{ return "th"; } // String
}


/* compare and add
 ******************/
dojo.date.compareTypes={
	// 	summary
	//	bitmask for comparison operations.
	DATE:1, TIME:2 
};
dojo.date.compare=function(/* Date */ dateA, /* Date */ dateB, /* dojo.date.compareTypes */ options){
	//	summary
	//	Compare two date objects by date, time, or both.  Returns 0 if equal, positive if a > b, else negative.
	var dA=dateA;
	var dB=dateB||new Date();
	var now=new Date();
	//FIXME: shorten this code
	with(dojo.date.compareTypes){
		var opt=options||(DATE|TIME);
		var d1=new Date(
			(opt&DATE)?dA.getFullYear():now.getFullYear(), 
			(opt&DATE)?dA.getMonth():now.getMonth(),
			(opt&DATE)?dA.getDate():now.getDate(),
			(opt&TIME)?dA.getHours():0,
			(opt&TIME)?dA.getMinutes():0,
			(opt&TIME)?dA.getSeconds():0
		);
		var d2=new Date(
			(opt&DATE)?dB.getFullYear():now.getFullYear(),
			(opt&DATE)?dB.getMonth():now.getMonth(),
			(opt&DATE)?dB.getDate():now.getDate(),
			(opt&TIME)?dB.getHours():0,
			(opt&TIME)?dB.getMinutes():0,
			(opt&TIME)?dB.getSeconds():0
		);
	}
	if(d1.valueOf()>d2.valueOf()){
		return 1;	//	int
	}
	if(d1.valueOf()<d2.valueOf()){
		return -1;	//	int
	}
	return 0;	//	int
}

dojo.date.dateParts={ 
	//	summary
	//	constants for use in dojo.date.add
	YEAR:0, MONTH:1, DAY:2, HOUR:3, MINUTE:4, SECOND:5, MILLISECOND:6, QUARTER:7, WEEK:8, WEEKDAY:9
};

dojo.date.add = function(/* Date */ dt, /* dojo.date.dateParts */ interv, /* int */ incr){
//	summary:
//		Add to a Date in intervals of different size, from milliseconds to years
//
//	dt:
//		A Javascript Date object to start with
//
//	interv:
//		A constant representing the interval, e.g. YEAR, MONTH, DAY.  See dojo.date.dateParts.
//
//	incr:
//		How much to add to the date

	if(typeof dt == 'number'){dt = new Date(dt);} // Allow timestamps
//FIXME: what's the reason behind this?	incr = incr || 1;

	function fixOvershoot(){
		if (sum.getDate() < dt.getDate()){
			sum.setDate(0);
		}
	}
	
	var sum = new Date(dt);

	with(dojo.date.dateParts){
		switch(interv){
			case YEAR:
				sum.setFullYear(dt.getFullYear()+incr);
				// Keep increment/decrement from 2/29 out of March
				fixOvershoot();
				break;
			case QUARTER:
				// Naive quarter is just three months
				incr*=3;
				// fallthrough...
			case MONTH:
				sum.setMonth(dt.getMonth()+incr);
				// Reset to last day of month if you overshoot
				fixOvershoot();
				break;
			case WEEK:
				incr*=7;
				// fallthrough...
			case DAY:
				sum.setDate(dt.getDate() + incr);
				break;
			case WEEKDAY:
				//FIXME: assumes Saturday/Sunday weekend, but even this is not fixed.  There are CLDR entries to localize this.
				var dat = dt.getDate();
				var weeks = 0;
				var days = 0;
				var strt = 0;
				var trgt = 0;
				var adj = 0;
				// Divide the increment time span into weekspans plus leftover days
				// e.g., 8 days is one 5-day weekspan / and two leftover days
				// Can't have zero leftover days, so numbers divisible by 5 get
				// a days value of 5, and the remaining days make up the number of weeks
				var mod = incr % 5;
				if (mod == 0) {
					days = (incr > 0) ? 5 : -5;
					weeks = (incr > 0) ? ((incr-5)/5) : ((incr+5)/5);
				}
				else {
					days = mod;
					weeks = parseInt(incr/5);
				}
				// Get weekday value for orig date param
				strt = dt.getDay();
				// Orig date is Sat / positive incrementer
				// Jump over Sun
				if (strt == 6 && incr > 0) {
					adj = 1;
				}
				// Orig date is Sun / negative incrementer
				// Jump back over Sat
				else if (strt == 0 && incr < 0) {
					adj = -1;
				}
				// Get weekday val for the new date
				trgt = (strt + days);
				// New date is on Sat or Sun
				if (trgt == 0 || trgt == 6) {
					adj = (incr > 0) ? 2 : -2;
				}
				// Increment by number of weeks plus leftover days plus
				// weekend adjustments
				sum.setDate(dat + (7*weeks) + days + adj);
				break;
			case HOUR:
				sum.setHours(sum.getHours()+incr);
				break;
			case MINUTE:
				sum.setMinutes(sum.getMinutes()+incr);
				break;
			case SECOND:
				sum.setSeconds(sum.getSeconds()+incr);
				break;
			case MILLISECOND:
				sum.setMilliseconds(sum.getMilliseconds()+incr);
				break;
			default:
				// Do nothing
				break;
		}
	}

	return sum; // Date
};

dojo.date.diff = function(/* Date */ dtA, /* Date */ dtB, /* dojo.date.dateParts */ interv){
//	summary:
//		Get the difference in a specific unit of time (e.g., number of months, weeks,
//		days, etc.) between two dates.
//
//	dtA:
//		A Javascript Date object
//
//	dtB:
//		A Javascript Date object
//
//	interv:
//		A constant representing the interval, e.g. YEAR, MONTH, DAY.  See dojo.date.dateParts.

	// Accept timestamp input
	if(typeof dtA == 'number'){dtA = new Date(dtA);}
	if(typeof dtB == 'number'){dtB = new Date(dtB);}
	var yeaDiff = dtB.getFullYear() - dtA.getFullYear();
	var monDiff = (dtB.getMonth() - dtA.getMonth()) + (yeaDiff * 12);
	var msDiff = dtB.getTime() - dtA.getTime(); // Millisecs
	var secDiff = msDiff/1000;
	var minDiff = secDiff/60;
	var houDiff = minDiff/60;
	var dayDiff = houDiff/24;
	var weeDiff = dayDiff/7;
	var delta = 0; // Integer return value

	with(dojo.date.dateParts){
		switch(interv){
			case YEAR:
				delta = yeaDiff;
				break;
			case QUARTER:
				var mA = dtA.getMonth();
				var mB = dtB.getMonth();
				// Figure out which quarter the months are in
				var qA = Math.floor(mA/3) + 1;
				var qB = Math.floor(mB/3) + 1;
				// Add quarters for any year difference between the dates
				qB += (yeaDiff * 4);
				delta = qB - qA;
				break;
			case MONTH:
				delta = monDiff;
				break;
			case WEEK:
				// Truncate instead of rounding
				// Don't use Math.floor -- value may be negative
				delta = parseInt(weeDiff);
				break;
			case DAY:
				delta = dayDiff;
				break;
			case WEEKDAY:
				var days = Math.round(dayDiff);
				var weeks = parseInt(days/7);
				var mod = days % 7;

				// Even number of weeks
				if (mod == 0) {
					days = weeks*5;
				}
				// Weeks plus spare change (< 7 days)
				else {
					var adj = 0;
					var aDay = dtA.getDay();
					var bDay = dtB.getDay();
	
					weeks = parseInt(days/7);
					mod = days % 7;
					// Mark the date advanced by the number of
					// round weeks (may be zero)
					var dtMark = new Date(dtA);
					dtMark.setDate(dtMark.getDate()+(weeks*7));
					var dayMark = dtMark.getDay();
					// Spare change days -- 6 or less
					// ----------
					// Positive diff
					if (dayDiff > 0) {
						switch (true) {
							// Range starts on Sat
							case aDay == 6:
								adj = -1;
								break;
							// Range starts on Sun
							case aDay == 0:
								adj = 0;
								break;
							// Range ends on Sat
							case bDay == 6:
								adj = -1;
								break;
							// Range ends on Sun
							case bDay == 0:
								adj = -2;
								break;
							// Range contains weekend
							case (dayMark + mod) > 5:
								adj = -2;
								break;
							default:
								// Do nothing
								break;
						}
					}
					// Negative diff
					else if (dayDiff < 0) {
						switch (true) {
							// Range starts on Sat
							case aDay == 6:
								adj = 0;
								break;
							// Range starts on Sun
							case aDay == 0:
								adj = 1;
								break;
							// Range ends on Sat
							case bDay == 6:
								adj = 2;
								break;
							// Range ends on Sun
							case bDay == 0:
								adj = 1;
								break;
							// Range contains weekend
							case (dayMark + mod) < 0:
								adj = 2;
								break;
							default:
								// Do nothing
								break;
						}
					}
					days += adj;
					days -= (weeks*2);
				}
				delta = days;

				break;
			case HOUR:
				delta = houDiff;
				break;
			case MINUTE:
				delta = minDiff;
				break;
			case SECOND:
				delta = secDiff;
				break;
			case MILLISECOND:
				delta = msDiff;
				break;
			default:
				// Do nothing
				break;
		}
	}

	// Round for fractional values and DST leaps
	return Math.round(delta); // Number (integer)
};

__CPAN_FILE__ src/date/serialize.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.date.serialize");

dojo.require("dojo.string.common");

/* ISO 8601 Functions
 *********************/

dojo.date.setIso8601 = function(/*Date*/dateObject, /*String*/formattedString){
	// summary: sets a Date object based on an ISO 8601 formatted string (uses date and time)
	var comps = (formattedString.indexOf("T") == -1) ? formattedString.split(" ") : formattedString.split("T");
	dateObject = dojo.date.setIso8601Date(dateObject, comps[0]);
	if(comps.length == 2){ dateObject = dojo.date.setIso8601Time(dateObject, comps[1]); }
	return dateObject; /* Date or null */
};

dojo.date.fromIso8601 = function(/*String*/formattedString){
	// summary: returns a Date object based on an ISO 8601 formatted string (uses date and time)
	return dojo.date.setIso8601(new Date(0, 0), formattedString);
};

dojo.date.setIso8601Date = function(/*String*/dateObject, /*String*/formattedString){
	// summary: sets a Date object based on an ISO 8601 formatted string (date only)
	var regexp = "^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|" +
			"(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$";
	var d = formattedString.match(new RegExp(regexp));
	if(!d){
		dojo.debug("invalid date string: " + formattedString);
		return null; // null
	}
	var year = d[1];
	var month = d[4];
	var date = d[6];
	var dayofyear = d[8];
	var week = d[10];
	var dayofweek = d[12] ? d[12] : 1;

	dateObject.setFullYear(year);

	if(dayofyear){
		dateObject.setMonth(0);
		dateObject.setDate(Number(dayofyear));
	}
	else if(week){
		dateObject.setMonth(0);
		dateObject.setDate(1);
		var gd = dateObject.getDay();
		var day =  gd ? gd : 7;
		var offset = Number(dayofweek) + (7 * Number(week));
		
		if(day <= 4){ dateObject.setDate(offset + 1 - day); }
		else{ dateObject.setDate(offset + 8 - day); }
	} else{
		if(month){
			dateObject.setDate(1);
			dateObject.setMonth(month - 1); 
		}
		if(date){ dateObject.setDate(date); }
	}
	
	return dateObject; // Date
};

dojo.date.fromIso8601Date = function(/*String*/formattedString){
	// summary: returns a Date object based on an ISO 8601 formatted string (date only)
	return dojo.date.setIso8601Date(new Date(0, 0), formattedString);
};

dojo.date.setIso8601Time = function(/*Date*/dateObject, /*String*/formattedString){
	// summary: sets a Date object based on an ISO 8601 formatted string (time only)

	// first strip timezone info from the end
	var timezone = "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$";
	var d = formattedString.match(new RegExp(timezone));

	var offset = 0; // local time if no tz info
	if(d){
		if(d[0] != 'Z'){
			offset = (Number(d[3]) * 60) + Number(d[5]);
			offset *= ((d[2] == '-') ? 1 : -1);
		}
		offset -= dateObject.getTimezoneOffset();
		formattedString = formattedString.substr(0, formattedString.length - d[0].length);
	}

	// then work out the time
	var regexp = "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$";
	d = formattedString.match(new RegExp(regexp));
	if(!d){
		dojo.debug("invalid time string: " + formattedString);
		return null; // null
	}
	var hours = d[1];
	var mins = Number((d[3]) ? d[3] : 0);
	var secs = (d[5]) ? d[5] : 0;
	var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;

	dateObject.setHours(hours);
	dateObject.setMinutes(mins);
	dateObject.setSeconds(secs);
	dateObject.setMilliseconds(ms);

	if(offset !== 0){
		dateObject.setTime(dateObject.getTime() + offset * 60000);
	}	
	return dateObject; // Date
};

dojo.date.fromIso8601Time = function(/*String*/formattedString){
	// summary: returns a Date object based on an ISO 8601 formatted string (date only)
	return dojo.date.setIso8601Time(new Date(0, 0), formattedString);
};


/* RFC-3339 Date Functions
 *************************/

dojo.date.toRfc3339 = function(/*Date?*/dateObject, /*String?*/selector){
//	summary:
//		Format a JavaScript Date object as a string according to RFC 3339
//
//	dateObject:
//		A JavaScript date, or the current date and time, by default
//
//	selector:
//		"dateOnly" or "timeOnly" to format selected portions of the Date object.
//		Date and time will be formatted by default.

//FIXME: tolerate Number, string input?
	if(!dateObject){
		dateObject = new Date();
	}

	var _ = dojo.string.pad;
	var formattedDate = [];
	if(selector != "timeOnly"){
		var date = [_(dateObject.getFullYear(),4), _(dateObject.getMonth()+1,2), _(dateObject.getDate(),2)].join('-');
		formattedDate.push(date);
	}
	if(selector != "dateOnly"){
		var time = [_(dateObject.getHours(),2), _(dateObject.getMinutes(),2), _(dateObject.getSeconds(),2)].join(':');
		var timezoneOffset = dateObject.getTimezoneOffset();
		time += (timezoneOffset > 0 ? "-" : "+") + 
					_(Math.floor(Math.abs(timezoneOffset)/60),2) + ":" +
					_(Math.abs(timezoneOffset)%60,2);
		formattedDate.push(time);
	}
	return formattedDate.join('T'); // String
};

dojo.date.fromRfc3339 = function(/*String*/rfcDate){
//	summary:
//		Create a JavaScript Date object from a string formatted according to RFC 3339
//
//	rfcDate:
//		A string such as 2005-06-30T08:05:00-07:00
//		"any" is also supported in place of a time.

	// backwards compatible support for use of "any" instead of just not 
	// including the time
	if(rfcDate.indexOf("Tany")!=-1){
		rfcDate = rfcDate.replace("Tany","");
	}
	var dateObject = new Date();
	return dojo.date.setIso8601(dateObject, rfcDate); // Date or null
};

__CPAN_FILE__ src/date/supplemental.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.date.supplemental");

dojo.date.getFirstDayOfWeek = function(/*String?*/locale){
// summary: Returns a zero-based index for first day of the week
// description:
//		Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
//		e.g. Sunday (returns 0), or Monday (returns 1)

	// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
	var firstDay = {/*default is 1=Monday*/
		mv:5,
		ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,lb:6,ly:6,ma:6,om:6,qa:6,sa:6,
		sd:6,so:6,tn:6,ye:6,
		as:0,au:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,il:0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,
		mh:0,mo:0,mp:0,mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,za:0,zw:0,
		et:0,mw:0,ng:0,tj:0,
		gb:0,
		sy:4
	};

	locale = dojo.hostenv.normalizeLocale(locale);
	var country = locale.split("-")[1];
	var dow = firstDay[country];
	return (typeof dow == 'undefined') ? 1 : dow; /*Number*/
};

dojo.date.getWeekend = function(/*String?*/locale){
// summary: Returns a hash containing the start and end days of the weekend
// description:
//		Returns a hash containing the start and end days of the weekend according to local custom using locale,
//		or by default in the user's locale.
//		e.g. {start:6, end:0}

	// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
	var weekendStart = {/*default is 6=Saturday*/
		eg:5,il:5,sy:5,
		'in':0,
		ae:4,bh:4,dz:4,iq:4,jo:4,kw:4,lb:4,ly:4,ma:4,om:4,qa:4,sa:4,sd:4,tn:4,ye:4		
	};

	var weekendEnd = {/*default is 0=Sunday*/
		ae:5,bh:5,dz:5,iq:5,jo:5,kw:5,lb:5,ly:5,ma:5,om:5,qa:5,sa:5,sd:5,tn:5,ye:5,af:5,ir:5,
		eg:6,il:6,sy:6
	};

	locale = dojo.hostenv.normalizeLocale(locale);
	var country = locale.split("-")[1];
	var start = weekendStart[country];
	var end = weekendEnd[country];
	if(typeof start == 'undefined'){start=6;}
	if(typeof end == 'undefined'){end=0;}
	return {start:start, end:end}; /*Object {start,end}*/
};

dojo.date.isWeekend = function(/*Date?*/dateObj, /*String?*/locale){
// summary:
//	Determines if the date falls on a weekend, according to local custom.

	var weekend = dojo.date.getWeekend(locale);
	var day = (dateObj || new Date()).getDay();
	if(weekend.end<weekend.start){
		weekend.end+=7;
		if(day<weekend.start){ day+=7; }
	}
	return day >= weekend.start && day <= weekend.end; // Boolean
};

__CPAN_FILE__ src/date/format.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.date.format");

dojo.require("dojo.date.common");
dojo.require("dojo.date.supplemental");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");
dojo.require("dojo.string.common");
dojo.require("dojo.i18n.common");

// Load the bundles containing localization information for
// names and formats
dojo.requireLocalization("dojo.i18n.calendar", "gregorian");
dojo.requireLocalization("dojo.i18n.calendar", "gregorianExtras");

//NOTE: Everything in this module assumes Gregorian calendars.
// Other calendars will be implemented in separate modules.

(function(){
dojo.date.format = function(/*Date*/dateObject, /*Object?*/options){
//
// summary:
//		Format a Date object as a String, using locale-specific settings.
//
// description:
//		Create a string from a Date object using a known localized pattern.
//		By default, this method formats both date and time from dateObject.
//		Formatting patterns are chosen appropriate to the locale.  Different
//		formatting lengths may be chosen, with "full" used by default.
//		Custom patterns may be used or registered with translations using
//		the addCustomBundle method.
//		Formatting patterns are implemented using the syntax described at
//		http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns
//
// dateObject:
//		the date and/or time to be formatted.  If a time only is formatted,
//		the values in the year, month, and day fields are irrelevant.  The
//		opposite is true when formatting only dates.
//
// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string}
//		selector- choice of timeOnly,dateOnly (default: date and time)
//		formatLength- choice of long, short, medium or full (plus any custom additions).  Defaults to 'full'
//		datePattern,timePattern- override pattern with this string
//		am,pm- override strings for am/pm in times
//		locale- override the locale used to determine formatting rules
//

	if(typeof options == "string"){
		dojo.deprecated("dojo.date.format", "To format dates with POSIX-style strings, please use dojo.date.strftime instead", "0.5");
		return dojo.date.strftime(dateObject, options);
	}

	// Format a pattern without literals
	function formatPattern(dateObject, pattern){
		return pattern.replace(/[a-zA-Z]+/g, function(match){
			var s;
			var c = match.charAt(0);
			var l = match.length;
			var pad;
			var widthList = ["abbr", "wide", "narrow"];
			switch(c){
				case 'G':
					if(l>3){dojo.unimplemented("Era format not implemented");}
					s = info.eras[dateObject.getFullYear() < 0 ? 1 : 0];
					break;
				case 'y':
					s = dateObject.getFullYear();
					switch(l){
						case 1:
							break;
						case 2:
							s = String(s).substr(-2);
							break;
						default:
							pad = true;
					}
					break;
				case 'Q':
				case 'q':
					s = Math.ceil((dateObject.getMonth()+1)/3);
					switch(l){
						case 1: case 2:
							pad = true;
							break;
						case 3:
						case 4:
							dojo.unimplemented("Quarter format not implemented");
					}
					break;
				case 'M':
				case 'L':
					var m = dateObject.getMonth();
					var width;
					switch(l){
						case 1: case 2:
							s = m+1; pad = true;
							break;
						case 3: case 4: case 5:
							width = widthList[l-3];
							break;
					}
					if(width){
						var type = (c == "L") ? "standalone" : "format";
						var prop = ["months",type,width].join("-");
						s = info[prop][m];
					}
					break;
				case 'w':
					var firstDay = 0;
					s = dojo.date.getWeekOfYear(dateObject, firstDay); pad = true;
					break;
				case 'd':
					s = dateObject.getDate(); pad = true;
					break;
				case 'D':
					s = dojo.date.getDayOfYear(dateObject); pad = true;
					break;
				case 'E':
				case 'e':
				case 'c': // REVIEW: don't see this in the spec?
					var d = dateObject.getDay();
					var width;
					switch(l){
						case 1: case 2:
							if(c == 'e'){
								var first = dojo.date.getFirstDayOfWeek(options.locale);
								d = (d-first+7)%7;
							}
							if(c != 'c'){
								s = d+1; pad = true;
								break;
							}
							// else fallthrough...
						case 3: case 4: case 5:
							width = widthList[l-3];
							break;
					}
					if(width){
						var type = (c == "c") ? "standalone" : "format";
						var prop = ["days",type,width].join("-");
						s = info[prop][d];
					}
					break;
				case 'a':
					var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
					s = info[timePeriod];
					break;
				case 'h':
				case 'H':
				case 'K':
				case 'k':
					var h = dateObject.getHours();
					// strange choices in the date format make it impossible to write this succinctly
					switch (c) {
						case 'h': // 1-12
							s = (h % 12) || 12;
							break;
						case 'H': // 0-23
							s = h;
							break;
						case 'K': // 0-11
							s = (h % 12);
							break;
						case 'k': // 1-24
							s = h || 24;
							break;
					}
					pad = true;
					break;
				case 'm':
					s = dateObject.getMinutes(); pad = true;
					break;
				case 's':
					s = dateObject.getSeconds(); pad = true;
					break;
				case 'S':
					s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3));
					break;
				case 'v': // FIXME: don't know what this is. seems to be same as z?
				case 'z':
					// We only have one timezone to offer; the one from the browser
					s = dojo.date.getTimezoneName(dateObject);
					if(s){break;}
					l=4;
					// fallthrough... use GMT if tz not available
				case 'Z':
					var offset = dateObject.getTimezoneOffset();
					var tz = [
						(offset<=0 ? "+" : "-"),
						dojo.string.pad(Math.floor(Math.abs(offset)/60), 2),
						dojo.string.pad(Math.abs(offset)% 60, 2)
					];
					if(l==4){
						tz.splice(0, 0, "GMT");
						tz.splice(3, 0, ":");
					}
					s = tz.join("");
					break;
				case 'Y':
				case 'u':
				case 'W':
				case 'F':
				case 'g':
				case 'A':
					dojo.debug(match+" modifier not yet implemented");
					s = "?";
					break;
				default:
					dojo.raise("dojo.date.format: invalid pattern char: "+pattern);
			}
			if(pad){ s = dojo.string.pad(s, l); }
			return s;
		});
	}

	options = options || {};

	var locale = dojo.hostenv.normalizeLocale(options.locale);
	var formatLength = options.formatLength || 'full';
	var info = dojo.date._getGregorianBundle(locale);
	var str = [];
	var sauce = dojo.lang.curry(this, formatPattern, dateObject);
	if(options.selector != "timeOnly"){
		var datePattern = options.datePattern || info["dateFormat-"+formatLength];
		if(datePattern){str.push(_processPattern(datePattern, sauce));}
	}
	if(options.selector != "dateOnly"){
		var timePattern = options.timePattern || info["timeFormat-"+formatLength];
		if(timePattern){str.push(_processPattern(timePattern, sauce));}
	}
	var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
	return result; /*String*/
};

dojo.date.parse = function(/*String*/value, /*Object?*/options){
//
// summary:
//		Convert a properly formatted string to a primitive Date object,
//		using locale-specific settings.
//
// description:
//		Create a Date object from a string using a known localized pattern.
//		By default, this method parses looking for both date and time in the string.
//		Formatting patterns are chosen appropriate to the locale.  Different
//		formatting lengths may be chosen, with "full" used by default.
//		Custom patterns may be used or registered with translations using
//		the addCustomBundle method.
//		Formatting patterns are implemented using the syntax described at
//		http://www.unicode.org/reports/tr35/#Date_Format_Patterns
//
// value:
//		A string representation of a date
//
// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string, strict: boolean}
//		selector- choice of timeOnly, dateOnly, dateTime (default: dateOnly)
//		formatLength- choice of long, short, medium or full (plus any custom additions).  Defaults to 'full'
//		datePattern,timePattern- override pattern with this string
//		am,pm- override strings for am/pm in times
//		locale- override the locale used to determine formatting rules
//		strict- strict parsing, off by default
//

	options = options || {};
	var locale = dojo.hostenv.normalizeLocale(options.locale);
	var info = dojo.date._getGregorianBundle(locale);
	var formatLength = options.formatLength || 'full';
	if(!options.selector){ options.selector = 'dateOnly'; }
	var datePattern = options.datePattern || info["dateFormat-" + formatLength];
	var timePattern = options.timePattern || info["timeFormat-" + formatLength];

	var pattern;
	if(options.selector == 'dateOnly'){
		pattern = datePattern;
	}
	else if(options.selector == 'timeOnly'){
		pattern = timePattern;
	}else if(options.selector == 'dateTime'){
		pattern = datePattern + ' ' + timePattern; //TODO: use locale-specific pattern to assemble date + time
	}else{
		var msg = "dojo.date.parse: Unknown selector param passed: '" + options.selector + "'.";
		msg += " Defaulting to date pattern.";
		dojo.debug(msg);
		pattern = datePattern;
	}

	var groups = [];
	var dateREString = _processPattern(pattern, dojo.lang.curry(this, _buildDateTimeRE, groups, info, options));
	var dateRE = new RegExp("^" + dateREString + "$");

	var match = dateRE.exec(value);
	if(!match){
		return null;
	}

	var widthList = ['abbr', 'wide', 'narrow'];
	//1972 is a leap year.  We want to avoid Feb 29 rolling over into Mar 1,
	//in the cases where the year is parsed after the month and day.
	var result = new Date(1972, 0);
	var expected = {};
	for(var i=1; i<match.length; i++){
		var grp=groups[i-1];
		var l=grp.length;
		var v=match[i];
		switch(grp.charAt(0)){
			case 'y':
				if(l != 2){
					//interpret year literally, so '5' would be 5 A.D.
					result.setFullYear(v);
					expected.year = v;
				}else{
					if(v<100){
						v = Number(v);
						//choose century to apply, according to a sliding window
						//of 80 years before and 20 years after present year
						var year = '' + new Date().getFullYear();
						var century = year.substring(0, 2) * 100;
						var yearPart = Number(year.substring(2, 4));
						var cutoff = Math.min(yearPart + 20, 99);
						var num = (v < cutoff) ? century + v : century - 100 + v;
						result.setFullYear(num);
						expected.year = num;
					}else{
						//we expected 2 digits and got more...
						if(options.strict){
							return null;
						}
						//interpret literally, so '150' would be 150 A.D.
						//also tolerate '1950', if 'yyyy' input passed to 'yy' format
						result.setFullYear(v);
						expected.year = v;
					}
				}
				break;
			case 'M':
				if (l>2) {
					if(!options.strict){
						//Tolerate abbreviating period in month part
						v = v.replace(/\./g,'');
						//Case-insensitive
						v = v.toLowerCase();
					}
					var months = info['months-format-' + widthList[l-3]].concat();
					for (var j=0; j<months.length; j++){
						if(!options.strict){
							//Case-insensitive
							months[j] = months[j].toLowerCase();
						}
						if(v == months[j]){
							result.setMonth(j);
							expected.month = j;
							break;
						}
					}
					if(j==months.length){
						dojo.debug("dojo.date.parse: Could not parse month name: '" + v + "'.");
						return null;
					}
				}else{
					result.setMonth(v-1);
					expected.month = v-1;
				}
				break;
			case 'E':
			case 'e':
				if(!options.strict){
					//Case-insensitive
					v = v.toLowerCase();
				}
				var days = info['days-format-' + widthList[l-3]].concat();
				for (var j=0; j<days.length; j++){
					if(!options.strict){
						//Case-insensitive
						days[j] = days[j].toLowerCase();
					}
					if(v == days[j]){
						//TODO: not sure what to actually do with this input,
						//in terms of setting something on the Date obj...?
						//without more context, can't affect the actual date
						break;
					}
				}
				if(j==days.length){
					dojo.debug("dojo.date.parse: Could not parse weekday name: '" + v + "'.");
					return null;
				}
				break;	
			case 'd':
				result.setDate(v);
				expected.date = v;
				break;
			case 'a': //am/pm
				var am = options.am || info.am;
				var pm = options.pm || info.pm;
				if(!options.strict){
					v = v.replace(/\./g,'').toLowerCase();
					am = am.replace(/\./g,'').toLowerCase();
					pm = pm.replace(/\./g,'').toLowerCase();
				}
				if(options.strict && v != am && v != pm){
					dojo.debug("dojo.date.parse: Could not parse am/pm part.");
					return null;
				}
				var hours = result.getHours();
				if(v == pm && hours < 12){
					result.setHours(hours + 12); //e.g., 3pm -> 15
				} else if(v == am && hours == 12){
					result.setHours(0); //12am -> 0
				}
				break;
			case 'K': //hour (1-24)
				if(v==24){v=0;}
				// fallthrough...
			case 'h': //hour (1-12)
			case 'H': //hour (0-23)
			case 'k': //hour (0-11)
				//TODO: strict bounds checking, padding
				if(v>23){
					dojo.debug("dojo.date.parse: Illegal hours value");
					return null;
				}

				//in the 12-hour case, adjusting for am/pm requires the 'a' part
				//which for now we will assume always comes after the 'h' part
				result.setHours(v);
				break;
			case 'm': //minutes
				result.setMinutes(v);
				break;
			case 's': //seconds
				result.setSeconds(v);
				break;
			case 'S': //milliseconds
				result.setMilliseconds(v);
				break;
			default:
				dojo.unimplemented("dojo.date.parse: unsupported pattern char=" + grp.charAt(0));
		}
	}

	//validate parse date fields versus input date fields
	if(expected.year && result.getFullYear() != expected.year){
		dojo.debug("Parsed year: '" + result.getFullYear() + "' did not match input year: '" + expected.year + "'.");
		return null;
	}
	if(expected.month && result.getMonth() != expected.month){
		dojo.debug("Parsed month: '" + result.getMonth() + "' did not match input month: '" + expected.month + "'.");
		return null;
	}
	if(expected.date && result.getDate() != expected.date){
		dojo.debug("Parsed day of month: '" + result.getDate() + "' did not match input day of month: '" + expected.date + "'.");
		return null;
	}

	//TODO: implement a getWeekday() method in order to test 
	//validity of input strings containing 'EEE' or 'EEEE'...

	return result; /*Date*/
};

function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
	// Process a pattern with literals in it
	// Break up on single quotes, treat every other one as a literal, except '' which becomes '
	var identity = function(x){return x;};
	applyPattern = applyPattern || identity;
	applyLiteral = applyLiteral || identity;
	applyAll = applyAll || identity;

	//split on single quotes (which escape literals in date format strings) 
	//but preserve escaped single quotes (e.g., o''clock)
	var chunks = pattern.match(/(''|[^'])+/g); 
	var literal = false;

	for(var i=0; i<chunks.length; i++){
		if(!chunks[i]){
			chunks[i]='';
		} else {
			chunks[i]=(literal ? applyLiteral : applyPattern)(chunks[i]);
			literal = !literal;
		}
	}
	return applyAll(chunks.join(''));
}

function _buildDateTimeRE(groups, info, options, pattern){
	return pattern.replace(/[a-zA-Z]+/g, function(match){
		// Build a simple regexp without parenthesis, which would ruin the match list
		var s;
		var c = match.charAt(0);
		var l = match.length;
		switch(c){
			case 'y':
				s = '\\d' + ((l==2) ? '{2,4}' : '+');
				break;
			case 'M':
				s = (l>2) ? '\\S+' : '\\d{1,2}';
				break;
			case 'd':
				s = '\\d{1,2}';
				break;
		    case 'E':
				s = '\\S+';
				break;
			case 'h': 
			case 'H': 
			case 'K': 
			case 'k':
				s = '\\d{1,2}';
				break;
			case 'm':
			case 's':
				s = '[0-5]\\d';
				break;
			case 'S':
				s = '\\d{1,3}';
				break;
			case 'a':
				var am = options.am || info.am || 'AM';
				var pm = options.pm || info.pm || 'PM';
				if(options.strict){
					s = am + '|' + pm;
				}else{
					s = am;
					s += (am != am.toLowerCase()) ? '|' + am.toLowerCase() : '';
					s += '|';
					s += (pm != pm.toLowerCase()) ? pm + '|' + pm.toLowerCase() : pm;
				}
				break;
			default:
				dojo.unimplemented("parse of date format, pattern=" + pattern);
		}

		if(groups){ groups.push(match); }

//FIXME: replace whitespace within final regexp with more flexible whitespace match instead?
		//tolerate whitespace
		return '\\s*(' + s + ')\\s*';
	});
}
})();

//TODO: try to common strftime and format code somehow?

dojo.date.strftime = function(/*Date*/dateObject, /*String*/format, /*String?*/locale){
//
// summary:
//		Formats the date object using the specifications of the POSIX strftime function
//
// description:
//		see <http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html>

	// zero pad
	var padChar = null;
	function _(s, n){
		return dojo.string.pad(s, n || 2, padChar || "0");
	}

	var info = dojo.date._getGregorianBundle(locale);

	function $(property){
		switch (property){
			case "a": // abbreviated weekday name according to the current locale
				return dojo.date.getDayShortName(dateObject, locale);

			case "A": // full weekday name according to the current locale
				return dojo.date.getDayName(dateObject, locale);

			case "b":
			case "h": // abbreviated month name according to the current locale
				return dojo.date.getMonthShortName(dateObject, locale);
				
			case "B": // full month name according to the current locale
				return dojo.date.getMonthName(dateObject, locale);
				
			case "c": // preferred date and time representation for the current
				      // locale
				return dojo.date.format(dateObject, {locale: locale});

			case "C": // century number (the year divided by 100 and truncated
				      // to an integer, range 00 to 99)
				return _(Math.floor(dateObject.getFullYear()/100));
				
			case "d": // day of the month as a decimal number (range 01 to 31)
				return _(dateObject.getDate());
				
			case "D": // same as %m/%d/%y
				return $("m") + "/" + $("d") + "/" + $("y");
					
			case "e": // day of the month as a decimal number, a single digit is
				      // preceded by a space (range ' 1' to '31')
				if(padChar == null){ padChar = " "; }
				return _(dateObject.getDate());
			
			case "f": // month as a decimal number, a single digit is
							// preceded by a space (range ' 1' to '12')
				if(padChar == null){ padChar = " "; }
				return _(dateObject.getMonth()+1);				
			
			case "g": // like %G, but without the century.
				break;
			
			case "G": // The 4-digit year corresponding to the ISO week number
				      // (see %V).  This has the same format and value as %Y,
				      // except that if the ISO week number belongs to the
				      // previous or next year, that year is used instead.
				dojo.unimplemented("unimplemented modifier 'G'");
				break;
			
			case "F": // same as %Y-%m-%d
				return $("Y") + "-" + $("m") + "-" + $("d");
				
			case "H": // hour as a decimal number using a 24-hour clock (range
				      // 00 to 23)
				return _(dateObject.getHours());
				
			case "I": // hour as a decimal number using a 12-hour clock (range
				      // 01 to 12)
				return _(dateObject.getHours() % 12 || 12);
				
			case "j": // day of the year as a decimal number (range 001 to 366)
				return _(dojo.date.getDayOfYear(dateObject), 3);
				
			case "k": // Hour as a decimal number using a 24-hour clock (range
					  // 0 to 23 (space-padded))
				if (padChar == null) { padChar = " "; }
				return _(dateObject.getHours());

			case "l": // Hour as a decimal number using a 12-hour clock (range
					  // 1 to 12 (space-padded))
				if (padChar == null) { padChar = " "; }
				return _(dateObject.getHours() % 12 || 12);
			
			case "m": // month as a decimal number (range 01 to 12)
				return _(dateObject.getMonth() + 1);
				
			case "M": // minute as a decimal number
				return _(dateObject.getMinutes());
			
			case "n":
				return "\n";

			case "p": // either `am' or `pm' according to the given time value,
				      // or the corresponding strings for the current locale
				return info[dateObject.getHours() < 12 ? "am" : "pm"];
				
			case "r": // time in a.m. and p.m. notation
				return $("I") + ":" + $("M") + ":" + $("S") + " " + $("p");
				
			case "R": // time in 24 hour notation
				return $("H") + ":" + $("M");
				
			case "S": // second as a decimal number
				return _(dateObject.getSeconds());

			case "t":
				return "\t";

			case "T": // current time, equal to %H:%M:%S
				return $("H") + ":" + $("M") + ":" + $("S");
				
			case "u": // weekday as a decimal number [1,7], with 1 representing
				      // Monday
				return String(dateObject.getDay() || 7);
				
			case "U": // week number of the current year as a decimal number,
				      // starting with the first Sunday as the first day of the
				      // first week
				return _(dojo.date.getWeekOfYear(dateObject));

			case "V": // week number of the year (Monday as the first day of the
				      // week) as a decimal number [01,53]. If the week containing
				      // 1 January has four or more days in the new year, then it 
				      // is considered week 1. Otherwise, it is the last week of 
				      // the previous year, and the next week is week 1.
				return _(dojo.date.getIsoWeekOfYear(dateObject));
				
			case "W": // week number of the current year as a decimal number,
				      // starting with the first Monday as the first day of the
				      // first week
				return _(dojo.date.getWeekOfYear(dateObject, 1));
				
			case "w": // day of the week as a decimal, Sunday being 0
				return String(dateObject.getDay());

			case "x": // preferred date representation for the current locale
				      // without the time
				return dojo.date.format(dateObject, {selector:'dateOnly', locale:locale});

			case "X": // preferred time representation for the current locale
				      // without the date
				return dojo.date.format(dateObject, {selector:'timeOnly', locale:locale});

			case "y": // year as a decimal number without a century (range 00 to
				      // 99)
				return _(dateObject.getFullYear()%100);
				
			case "Y": // year as a decimal number including the century
				return String(dateObject.getFullYear());
			
			case "z": // time zone or name or abbreviation
				var timezoneOffset = dateObject.getTimezoneOffset();
				return (timezoneOffset > 0 ? "-" : "+") + 
					_(Math.floor(Math.abs(timezoneOffset)/60)) + ":" +
					_(Math.abs(timezoneOffset)%60);

			case "Z": // time zone or name or abbreviation
				return dojo.date.getTimezoneName(dateObject);
			
			case "%":
				return "%";
		}
	}

	// parse the formatting string and construct the resulting string
	var string = "";
	var i = 0;
	var index = 0;
	var switchCase = null;
	while ((index = format.indexOf("%", i)) != -1){
		string += format.substring(i, index++);
		
		// inspect modifier flag
		switch (format.charAt(index++)) {
			case "_": // Pad a numeric result string with spaces.
				padChar = " "; break;
			case "-": // Do not pad a numeric result string.
				padChar = ""; break;
			case "0": // Pad a numeric result string with zeros.
				padChar = "0"; break;
			case "^": // Convert characters in result string to uppercase.
				switchCase = "upper"; break;
			case "*": // Convert characters in result string to lowercase
				switchCase = "lower"; break;
			case "#": // Swap the case of the result string.
				switchCase = "swap"; break;
			default: // no modifier flag so decrement the index
				padChar = null; index--; break;
		}

		// toggle case if a flag is set
		var property = $(format.charAt(index++));
		switch (switchCase){
			case "upper":
				property = property.toUpperCase();
				break;
			case "lower":
				property = property.toLowerCase();
				break;
			case "swap": // Upper to lower, and versey-vicea
				var compareString = property.toLowerCase();
				var swapString = '';
				var j = 0;
				var ch = '';
				while (j < property.length){
					ch = property.charAt(j);
					swapString += (ch == compareString.charAt(j)) ?
						ch.toUpperCase() : ch.toLowerCase();
					j++;
				}
				property = swapString;
				break;
			default:
				break;
		}
		switchCase = null;
		
		string += property;
		i = index;
	}
	string += format.substring(i);
	
	return string; // String
};

(function(){
var _customFormats = [];
dojo.date.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
//
// summary:
//		Add a reference to a bundle containing localized custom formats to be
//		used by date/time formatting and parsing routines.
//
// description:
//		The user may add custom localized formats where the bundle has properties following the
//		same naming convention used by dojo for the CLDR data: dateFormat-xxxx / timeFormat-xxxx
//		The pattern string should match the format used by the CLDR.
//		See dojo.date.format for details.
//		The resources must be loaded by dojo.requireLocalization() prior to use

	_customFormats.push({pkg:packageName,name:bundleName});
};

dojo.date._getGregorianBundle = function(/*String*/locale){
	var gregorian = {};
	dojo.lang.forEach(_customFormats, function(desc){
		var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
		gregorian = dojo.lang.mixin(gregorian, bundle);
	}, this);
	return gregorian; /*Object*/
};
})();

dojo.date.addCustomFormats("dojo.i18n.calendar","gregorian");
dojo.date.addCustomFormats("dojo.i18n.calendar","gregorianExtras");

dojo.date.getNames = function(/*String*/item, /*String*/type, /*String?*/use, /*String?*/locale){
//
// summary:
//		Used to get localized strings for day or month names.
//
// item: 'months' || 'days'
// type: 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
// use: 'standAlone' || 'format' (default)
// locale: override locale used to find the names

	var label;
	var lookup = dojo.date._getGregorianBundle(locale);
	var props = [item, use, type];
	if(use == 'standAlone'){
		label = lookup[props.join('-')];
	}
	props[1] = 'format';

	// return by copy so changes won't be made accidentally to the in-memory model
	return (label || lookup[props.join('-')]).concat(); /*Array*/
};

// Convenience methods

dojo.date.getDayName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the full localized day of the week corresponding to the date object
	return dojo.date.getNames('days', 'wide', 'format', locale)[dateObject.getDay()]; /*String*/
};

dojo.date.getDayShortName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the abbreviated localized day of the week corresponding to the date object
	return dojo.date.getNames('days', 'abbr', 'format', locale)[dateObject.getDay()]; /*String*/
};

dojo.date.getMonthName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the full localized month name corresponding to the date object
	return dojo.date.getNames('months', 'wide', 'format', locale)[dateObject.getMonth()]; /*String*/
};

dojo.date.getMonthShortName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the abbreviated localized month name corresponding to the date object
	return dojo.date.getNames('months', 'abbr', 'format', locale)[dateObject.getMonth()]; /*String*/
};

//FIXME: not localized
dojo.date.toRelativeString = function(/*Date*/dateObject){
// summary:
//	Returns an description in English of the date relative to the current date.  Note: this is not localized yet.  English only.
//
// description: Example returns:
//	 - "1 minute ago"
//	 - "4 minutes ago"
//	 - "Yesterday"
//	 - "2 days ago"

	var now = new Date();
	var diff = (now - dateObject) / 1000;
	var end = " ago";
	var future = false;
	if(diff < 0){
		future = true;
		end = " from now";
		diff = -diff;
	}

	if(diff < 60){
		diff = Math.round(diff);
		return diff + " second" + (diff == 1 ? "" : "s") + end;
	}
	if(diff < 60*60){
		diff = Math.round(diff/60);
		return diff + " minute" + (diff == 1 ? "" : "s") + end;
	}
	if(diff < 60*60*24){
		diff = Math.round(diff/3600);
		return diff + " hour" + (diff == 1 ? "" : "s") + end;
	}
	if(diff < 60*60*24*7){
		diff = Math.round(diff/(3600*24));
		if(diff == 1){
			return future ? "Tomorrow" : "Yesterday";
		}else{
			return diff + " days" + end;
		}
	}
	return dojo.date.format(dateObject); // String
};

//FIXME: SQL methods can probably be moved to a different module without i18n deps

dojo.date.toSql = function(/*Date*/dateObject, /*Boolean?*/noTime){
// summary:
//	Convert a Date to a SQL string
// noTime: whether to ignore the time portion of the Date.  Defaults to false.

	return dojo.date.strftime(dateObject, "%F" + !noTime ? " %T" : ""); // String
};

dojo.date.fromSql = function(/*String*/sqlDate){
// summary:
//	Convert a SQL date string to a JavaScript Date object

	var parts = sqlDate.split(/[\- :]/g);
	while(parts.length < 6){
		parts.push(0);
	}
	return new Date(parts[0], (parseInt(parts[1],10)-1), parts[2], parts[3], parts[4], parts[5]); // Date
};

__CPAN_DIR__ src/undo
__CPAN_FILE__ src/undo/browser.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.undo.browser");
dojo.require("dojo.io.common");

try{
	if((!djConfig["preventBackButtonFix"])&&(!dojo.hostenv.post_load_)){
		document.write("<iframe style='border: 0px; width: 1px; height: 1px; position: absolute; bottom: 0px; right: 0px; visibility: visible;' name='djhistory' id='djhistory' src='"+(dojo.hostenv.getBaseScriptUri()+'iframe_history.html')+"'></iframe>");
	}
}catch(e){/* squelch */}

if(dojo.render.html.opera){
	dojo.debug("Opera is not supported with dojo.undo.browser, so back/forward detection will not work.");
}

/* NOTES:
 *  Safari 1.2: 
 *	back button "works" fine, however it's not possible to actually
 *	DETECT that you've moved backwards by inspecting window.location.
 *	Unless there is some other means of locating.
 *	FIXME: perhaps we can poll on history.length?
 *  Safari 2.0.3+ (and probably 1.3.2+):
 *	works fine, except when changeUrl is used. When changeUrl is used,
 *	Safari jumps all the way back to whatever page was shown before
 *	the page that uses dojo.undo.browser support.
 *  IE 5.5 SP2:
 *	back button behavior is macro. It does not move back to the
 *	previous hash value, but to the last full page load. This suggests
 *	that the iframe is the correct way to capture the back button in
 *	these cases.
 *	Don't test this page using local disk for MSIE. MSIE will not create 
 *	a history list for iframe_history.html if served from a file: URL. 
 *	The XML served back from the XHR tests will also not be properly 
 *	created if served from local disk. Serve the test pages from a web 
 *	server to test in that browser.
 *  IE 6.0:
 *	same behavior as IE 5.5 SP2
 * Firefox 1.0+:
 *	the back button will return us to the previous hash on the same
 *	page, thereby not requiring an iframe hack, although we do then
 *	need to run a timer to detect inter-page movement.
 */

dojo.undo.browser = {
	initialHref: window.location.href,
	initialHash: window.location.hash,

	moveForward: false,
	historyStack: [],
	forwardStack: [],
	historyIframe: null,
	bookmarkAnchor: null,
	locationTimer: null,

	/**
	 * setInitialState sets the state object and back callback for the very first page that is loaded.
	 * It is recommended that you call this method as part of an event listener that is registered via
	 * dojo.addOnLoad().
	 */
	setInitialState: function(args){
		this.initialState = this._createState(this.initialHref, args, this.initialHash);
	},

	//FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things.
	//FIXME: is there a slight race condition in moz using change URL with the timer check and when
	//       the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent.
	/**
	 * addToHistory takes one argument, and it is an object that defines the following functions:
	 * - To support getting back button notifications, the object argument should implement a
	 *   function called either "back", "backButton", or "handle". The string "back" will be
	 *   passed as the first and only argument to this callback.
	 * - To support getting forward button notifications, the object argument should implement a
	 *   function called either "forward", "forwardButton", or "handle". The string "forward" will be
	 *   passed as the first and only argument to this callback.
	 * - If you want the browser location string to change, define "changeUrl" on the object. If the
	 *   value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment
	 *   identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does
	 *   not evaluate to false, that value will be used as the fragment identifier. For example,
	 *   if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1
	 *   
	 * Full example:
	 * 
	 * dojo.undo.browser.addToHistory({
	 *   back: function() { alert('back pressed'); },
	 *   forward: function() { alert('forward pressed'); },
	 *   changeUrl: true
	 * });
	 */
	addToHistory: function(args){
		//If addToHistory is called, then that means we prune the
		//forward stack -- the user went back, then wanted to
		//start a new forward path.
		this.forwardStack = []; 

		var hash = null;
		var url = null;
		if(!this.historyIframe){
			this.historyIframe = window.frames["djhistory"];
		}
		if(!this.bookmarkAnchor){
			this.bookmarkAnchor = document.createElement("a");
			dojo.body().appendChild(this.bookmarkAnchor);
			this.bookmarkAnchor.style.display = "none";
		}
		if(args["changeUrl"]){
			hash = "#"+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime());
			
			//If the current hash matches the new one, just replace the history object with
			//this new one. It doesn't make sense to track different state objects for the same
			//logical URL. This matches the browser behavior of only putting in one history
			//item no matter how many times you click on the same #hash link, at least in Firefox
			//and Safari, and there is no reliable way in those browsers to know if a #hash link
			//has been clicked on multiple times. So making this the standard behavior in all browsers
			//so that dojo.undo.browser's behavior is the same in all browsers.
			if(this.historyStack.length == 0 && this.initialState.urlHash == hash){
				this.initialState = this._createState(url, args, hash);
				return;
			}else if(this.historyStack.length > 0 && this.historyStack[this.historyStack.length - 1].urlHash == hash){
				this.historyStack[this.historyStack.length - 1] = this._createState(url, args, hash);
				return;
			}

			this.changingUrl = true;
			setTimeout("window.location.href = '"+hash+"'; dojo.undo.browser.changingUrl = false;", 1);
			this.bookmarkAnchor.href = hash;
			
			if(dojo.render.html.ie){
				url = this._loadIframeHistory();

				var oldCB = args["back"]||args["backButton"]||args["handle"];

				//The function takes handleName as a parameter, in case the
				//callback we are overriding was "handle". In that case,
				//we will need to pass the handle name to handle.
				var tcb = function(handleName){
					if(window.location.hash != ""){
						setTimeout("window.location.href = '"+hash+"';", 1);
					}
					//Use apply to set "this" to args, and to try to avoid memory leaks.
					oldCB.apply(this, [handleName]);
				}
		
				//Set interceptor function in the right place.
				if(args["back"]){
					args.back = tcb;
				}else if(args["backButton"]){
					args.backButton = tcb;
				}else if(args["handle"]){
					args.handle = tcb;
				}
		
				var oldFW = args["forward"]||args["forwardButton"]||args["handle"];
		
				//The function takes handleName as a parameter, in case the
				//callback we are overriding was "handle". In that case,
				//we will need to pass the handle name to handle.
				var tfw = function(handleName){
					if(window.location.hash != ""){
						window.location.href = hash;
					}
					if(oldFW){ // we might not actually have one
						//Use apply to set "this" to args, and to try to avoid memory leaks.
						oldFW.apply(this, [handleName]);
					}
				}

				//Set interceptor function in the right place.
				if(args["forward"]){
					args.forward = tfw;
				}else if(args["forwardButton"]){
					args.forwardButton = tfw;
				}else if(args["handle"]){
					args.handle = tfw;
				}

			}else if(dojo.render.html.moz){
				// start the timer
				if(!this.locationTimer){
					this.locationTimer = setInterval("dojo.undo.browser.checkLocation();", 200);
				}
			}
		}else{
			url = this._loadIframeHistory();
		}

		this.historyStack.push(this._createState(url, args, hash));
	},

	checkLocation: function(){
		if (!this.changingUrl){
			var hsl = this.historyStack.length;

			if((window.location.hash == this.initialHash||window.location.href == this.initialHref)&&(hsl == 1)){
				// FIXME: could this ever be a forward button?
				// we can't clear it because we still need to check for forwards. Ugg.
				// clearInterval(this.locationTimer);
				this.handleBackButton();
				return;
			}
			
			// first check to see if we could have gone forward. We always halt on
			// a no-hash item.
			if(this.forwardStack.length > 0){
				if(this.forwardStack[this.forwardStack.length-1].urlHash == window.location.hash){
					this.handleForwardButton();
					return;
				}
			}
	
			// ok, that didn't work, try someplace back in the history stack
			if((hsl >= 2)&&(this.historyStack[hsl-2])){
				if(this.historyStack[hsl-2].urlHash==window.location.hash){
					this.handleBackButton();
					return;
				}
			}
		}
	},

	iframeLoaded: function(evt, ifrLoc){
		if(!dojo.render.html.opera){
			var query = this._getUrlQuery(ifrLoc.href);
			if(query == null){ 
				// alert("iframeLoaded");
				// we hit the end of the history, so we should go back
				if(this.historyStack.length == 1){
					this.handleBackButton();
				}
				return;
			}
			if(this.moveForward){
				// we were expecting it, so it's not either a forward or backward movement
				this.moveForward = false;
				return;
			}
	
			//Check the back stack first, since it is more likely.
			//Note that only one step back or forward is supported.
			if(this.historyStack.length >= 2 && query == this._getUrlQuery(this.historyStack[this.historyStack.length-2].url)){
				this.handleBackButton();
			}
			else if(this.forwardStack.length > 0 && query == this._getUrlQuery(this.forwardStack[this.forwardStack.length-1].url)){
				this.handleForwardButton();
			}
		}
	},

	handleBackButton: function(){
		//The "current" page is always at the top of the history stack.
		var current = this.historyStack.pop();
		if(!current){ return; }
		var last = this.historyStack[this.historyStack.length-1];
		if(!last && this.historyStack.length == 0){
			last = this.initialState;
		}
		if (last){
			if(last.kwArgs["back"]){
				last.kwArgs["back"]();
			}else if(last.kwArgs["backButton"]){
				last.kwArgs["backButton"]();
			}else if(last.kwArgs["handle"]){
				last.kwArgs.handle("back");
			}
		}
		this.forwardStack.push(current);
	},

	handleForwardButton: function(){
		var last = this.forwardStack.pop();
		if(!last){ return; }
		if(last.kwArgs["forward"]){
			last.kwArgs.forward();
		}else if(last.kwArgs["forwardButton"]){
			last.kwArgs.forwardButton();
		}else if(last.kwArgs["handle"]){
			last.kwArgs.handle("forward");
		}
		this.historyStack.push(last);
	},

	_createState: function(url, args, hash){
		return {"url": url, "kwArgs": args, "urlHash": hash};	
	},

	_getUrlQuery: function(url){
		var segments = url.split("?");
		if (segments.length < 2){
			return null;
		}
		else{
			return segments[1];
		}
	},
	
	_loadIframeHistory: function(){
		var url = dojo.hostenv.getBaseScriptUri()+"iframe_history.html?"+(new Date()).getTime();
		this.moveForward = true;
		dojo.io.setIFrameSrc(this.historyIframe, url, false);	
		return url;
	}
}

__CPAN_FILE__ src/undo/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.undo.Manager");
dojo.provide("dojo.undo.*");

__CPAN_FILE__ src/undo/Manager.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.undo.Manager");
dojo.require("dojo.lang.common");

dojo.undo.Manager = function(parent) {
	this.clear();
	this._parent = parent;
};
dojo.extend(dojo.undo.Manager, {
	_parent: null,
	_undoStack: null,
	_redoStack: null,
	_currentManager: null,

	canUndo: false,
	canRedo: false,

	isUndoing: false,
	isRedoing: false,

	// these events allow you to hook in and update your code (UI?) as necessary
	onUndo: function(manager, item) {},
	onRedo: function(manager, item) {},

	// fired when you do *any* undo action, which means you'll have one for every item
	// in a transaction. this is usually only useful for debugging
	onUndoAny: function(manager, item) {},
	onRedoAny: function(manager, item) {},

	_updateStatus: function() {
		this.canUndo = this._undoStack.length > 0;
		this.canRedo = this._redoStack.length > 0;
	},

	clear: function() {
		this._undoStack = [];
		this._redoStack = [];
		this._currentManager = this;

		this.isUndoing = false;
		this.isRedoing = false;

		this._updateStatus();
	},

	undo: function() {
		if(!this.canUndo) { return false; }

		this.endAllTransactions();

		this.isUndoing = true;
		var top = this._undoStack.pop();
		if(top instanceof dojo.undo.Manager){
			top.undoAll();
		}else{
			top.undo();
		}
		if(top.redo){
			this._redoStack.push(top);
		}
		this.isUndoing = false;

		this._updateStatus();
		this.onUndo(this, top);
		if(!(top instanceof dojo.undo.Manager)) {
			this.getTop().onUndoAny(this, top);
		}
		return true;
	},

	redo: function() {
		if(!this.canRedo){ return false; }

		this.isRedoing = true;
		var top = this._redoStack.pop();
		if(top instanceof dojo.undo.Manager) {
			top.redoAll();
		}else{
			top.redo();
		}
		this._undoStack.push(top);
		this.isRedoing = false;

		this._updateStatus();
		this.onRedo(this, top);
		if(!(top instanceof dojo.undo.Manager)){
			this.getTop().onRedoAny(this, top);
		}
		return true;
	},

	undoAll: function() {
		while(this._undoStack.length > 0) {
			this.undo();
		}
	},

	redoAll: function() {
		while(this._redoStack.length > 0) {
			this.redo();
		}
	},

	push: function(undo, redo /* optional */, description /* optional */) {
		if(!undo) { return; }

		if(this._currentManager == this) {
			this._undoStack.push({
				undo: undo,
				redo: redo,
				description: description
			});
		} else {
			this._currentManager.push.apply(this._currentManager, arguments);
		}
		// adding a new undo-able item clears out the redo stack
		this._redoStack = [];
		this._updateStatus();
	},

	concat: function(manager) {
		if ( !manager ) { return; }

		if (this._currentManager == this ) {
			for(var x=0; x < manager._undoStack.length; x++) {
				this._undoStack.push(manager._undoStack[x]);
			}
			// adding a new undo-able item clears out the redo stack
			if (manager._undoStack.length > 0) {
				this._redoStack = [];
			}
			this._updateStatus();
		} else {
			this._currentManager.concat.apply(this._currentManager, arguments);
		}
	},

	beginTransaction: function(description /* optional */) {
		if(this._currentManager == this) {
			var mgr = new dojo.undo.Manager(this);
			mgr.description = description ? description : "";
			this._undoStack.push(mgr);
			this._currentManager = mgr;
			return mgr;
		} else {
			//for nested transactions need to make sure the top level _currentManager is set
			this._currentManager = this._currentManager.beginTransaction.apply(this._currentManager, arguments);
		}
	},

	endTransaction: function(flatten /* optional */) {
		if(this._currentManager == this) {
			if(this._parent) {
				this._parent._currentManager = this._parent;
				// don't leave empty transactions hangin' around
				if(this._undoStack.length == 0 || flatten) {
					var idx = dojo.lang.find(this._parent._undoStack, this);
					if (idx >= 0) {
						this._parent._undoStack.splice(idx, 1);
						//add the current transaction to parents undo stack
						if (flatten) {
							for(var x=0; x < this._undoStack.length; x++){
								this._parent._undoStack.splice(idx++, 0, this._undoStack[x]);
							}
							this._updateStatus();
						}
					}
				}
				return this._parent;
			}
		} else {
			//for nested transactions need to make sure the top level _currentManager is set
			this._currentManager = this._currentManager.endTransaction.apply(this._currentManager, arguments);
		}
	},

	endAllTransactions: function() {
		while(this._currentManager != this) {
			this.endTransaction();
		}
	},

	// find the top parent of an undo manager
	getTop: function() {
		if(this._parent) {
			return this._parent.getTop();
		} else {
			return this;
		}
	}
});

__CPAN_DIR__ src/flash
__CPAN_DIR__ src/flash/flash8
__CPAN_FILE__ src/flash/flash8/ExpressInstall.as
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
 * Based on the expressinstall.as class created by Geoff Stearns as part
 * of the FlashObject library.
 *
 * Use this file to invoke the Macromedia Flash Player Express Install functionality
 * This file is intended for use with the FlashObject embed script. You can download FlashObject 
 * and this file at the following URL: http://blog.deconcept.com/flashobject/
 *
 * Usage: 
 *          var ExpressInstall = new ExpressInstall();
 *          
 *          // test to see if install is needed:
 *          if (ExpressInstall.needsUpdate) { // returns true if update is needed
 *              ExpressInstall.init(); // starts the update
 *          }
 *
 *	NOTE: Your Flash movie must be at least 214px by 137px in order to use ExpressInstall.
 *
 */

class ExpressInstall {
	public var needsUpdate:Boolean;
	private var updater:MovieClip;
	private var hold:MovieClip;
	
	public function ExpressInstall(){
		// does the user need to update?
		this.needsUpdate = (_root.MMplayerType == undefined) ? false : true;	
	}

	public function init():Void{
		this.loadUpdater();
	}

	public function loadUpdater():Void {
		System.security.allowDomain("fpdownload.macromedia.com");

		// hope that nothing is at a depth of 10000000, you can change this depth if needed, but you want
		// it to be on top of your content if you have any stuff on the first frame
		this.updater = _root.createEmptyMovieClip("expressInstallHolder", 10000000);

		// register the callback so we know if they cancel or there is an error
		var _self = this;
		this.updater.installStatus = _self.onInstallStatus;
		this.hold = this.updater.createEmptyMovieClip("hold", 1);

		// can't use movieClipLoader because it has to work in 6.0.65
		this.updater.onEnterFrame = function():Void {
			if(typeof this.hold.startUpdate == 'function'){
				_self.initUpdater();
				this.onEnterFrame = null;
			}
		}

		var cacheBuster:Number = Math.random();

		this.hold.loadMovie("http://fpdownload.macromedia.com/pub/flashplayer/"
												+"update/current/swf/autoUpdater.swf?"+ cacheBuster);
	}

	private function initUpdater():Void{
		this.hold.redirectURL = _root.MMredirectURL;
		this.hold.MMplayerType = _root.MMplayerType;
		this.hold.MMdoctitle = _root.MMdoctitle;
		this.hold.startUpdate();
	}

	public function onInstallStatus(msg):Void{
		getURL("javascript:dojo.flash.install._onInstallStatus('"+msg+"')");
	}
}

__CPAN_FILE__ src/flash/flash8/DojoExternalInterface.as
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/**
	A wrapper around Flash 8's ExternalInterface; DojoExternalInterface is needed so that we
	can do a Flash 6 implementation of ExternalInterface, and be able
	to support having a single codebase that uses DojoExternalInterface
	across Flash versions rather than having two seperate source bases,
	where one uses ExternalInterface and the other uses DojoExternalInterface.
	
	DojoExternalInterface class does a variety of optimizations to bypass ExternalInterface's
	unbelievably bad performance so that we can have good performance
	on Safari; see the blog post
	http://codinginparadise.org/weblog/2006/02/how-to-speed-up-flash-8s.html
	for details.
	
	@author Brad Neuberg, bkn3@columbia.edu
*/
import flash.external.ExternalInterface;

class DojoExternalInterface{
	public static var available:Boolean;
	public static var dojoPath = "";
	
	private static var flashMethods:Array = new Array();
	private static var numArgs:Number;
	private static var argData:Array;
	private static var resultData = null;
	
	public static function initialize(){
		// extract the dojo base path
		DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath();
		
		// see if we need to do an express install
		var install:ExpressInstall = new ExpressInstall();
		if(install.needsUpdate){
			install.init();
		}
		
		// register our callback functions
		ExternalInterface.addCallback("startExec", DojoExternalInterface, startExec);
		ExternalInterface.addCallback("setNumberArguments", DojoExternalInterface,
																	setNumberArguments);
		ExternalInterface.addCallback("chunkArgumentData", DojoExternalInterface,
																	chunkArgumentData);
		ExternalInterface.addCallback("exec", DojoExternalInterface, exec);
		ExternalInterface.addCallback("getReturnLength", DojoExternalInterface,
																	getReturnLength);
		ExternalInterface.addCallback("chunkReturnData", DojoExternalInterface,
																	chunkReturnData);
		ExternalInterface.addCallback("endExec", DojoExternalInterface, endExec);
		
		// set whether communication is available
		DojoExternalInterface.available = ExternalInterface.available;
		DojoExternalInterface.call("loaded");
	}
	
	public static function addCallback(methodName:String, instance:Object, 
										 								 method:Function) : Boolean{
		// register DojoExternalInterface methodName with it's instance
		DojoExternalInterface.flashMethods[methodName] = instance;
		
		// tell JavaScript about DojoExternalInterface new method so we can create a proxy
		ExternalInterface.call("dojo.flash.comm._addExternalInterfaceCallback", 
													 methodName);
													 
		return true;
	}
	
	public static function call(methodName:String,
								resultsCallback:Function) : Void{
		// we might have any number of optional arguments, so we have to 
		// pass them in dynamically; strip out the results callback
		var parameters = new Array();
		for(var i = 0; i < arguments.length; i++){
			if(i != 1){ // skip the callback
				parameters.push(arguments[i]);
			}
		}
		
		var results = ExternalInterface.call.apply(ExternalInterface, parameters);
		
		// immediately give the results back, since ExternalInterface is
		// synchronous
		if(resultsCallback != null && typeof resultsCallback != "undefined"){
			resultsCallback.call(null, results);
		}
	}
	
	/** 
			Called by Flash to indicate to JavaScript that we are ready to have
			our Flash functions called. Calling loaded()
			will fire the dojo.flash.loaded() event, so that JavaScript can know that
			Flash has finished loading and adding its callbacks, and can begin to
			interact with the Flash file.
	*/
	public static function loaded(){
		DojoExternalInterface.call("dojo.flash.loaded");
	}
	
	public static function startExec():Void{
		DojoExternalInterface.numArgs = null;
		DojoExternalInterface.argData = null;
		DojoExternalInterface.resultData = null;
	}
	
	public static function setNumberArguments(numArgs):Void{
		DojoExternalInterface.numArgs = numArgs;
		DojoExternalInterface.argData = new Array(DojoExternalInterface.numArgs);
	}
	
	public static function chunkArgumentData(value, argIndex:Number):Void{
		//getURL("javascript:dojo.debug('FLASH: chunkArgumentData, value="+value+", argIndex="+argIndex+"')");
		var currentValue = DojoExternalInterface.argData[argIndex];
		if(currentValue == null || typeof currentValue == "undefined"){
			DojoExternalInterface.argData[argIndex] = value;
		}else{
			DojoExternalInterface.argData[argIndex] += value;
		}
	}
	
	public static function exec(methodName):Void{
		// decode all of the arguments that were passed in
		for(var i = 0; i < DojoExternalInterface.argData.length; i++){
			DojoExternalInterface.argData[i] = 
				DojoExternalInterface.decodeData(DojoExternalInterface.argData[i]);
		}
		
		var instance = DojoExternalInterface.flashMethods[methodName];
		DojoExternalInterface.resultData = instance[methodName].apply(
																			instance, DojoExternalInterface.argData);
		// encode the result data
		DojoExternalInterface.resultData = 
			DojoExternalInterface.encodeData(DojoExternalInterface.resultData);
			
		//getURL("javascript:dojo.debug('FLASH: encoded result data="+DojoExternalInterface.resultData+"')");
	}
	
	public static function getReturnLength():Number{
	 if(DojoExternalInterface.resultData == null || 
	 					typeof DojoExternalInterface.resultData == "undefined"){
	 	return 0;
	 }
	 var segments = Math.ceil(DojoExternalInterface.resultData.length / 1024);
	 return segments;
	}
	
	public static function chunkReturnData(segment:Number):String{
		var numSegments = DojoExternalInterface.getReturnLength();
		var startCut = segment * 1024;
		var endCut = segment * 1024 + 1024;
		if(segment == (numSegments - 1)){
			endCut = segment * 1024 + DojoExternalInterface.resultData.length;
		}
			
		var piece = DojoExternalInterface.resultData.substring(startCut, endCut);
		
		//getURL("javascript:dojo.debug('FLASH: chunking return piece="+piece+"')");
		
		return piece;
	}
	
	public static function endExec():Void{
	}
	
	private static function decodeData(data):String{
		// we have to use custom encodings for certain characters when passing
		// them over; for example, passing a backslash over as //// from JavaScript
		// to Flash doesn't work
		data = DojoExternalInterface.replaceStr(data, "&custom_backslash;", "\\");
		
		data = DojoExternalInterface.replaceStr(data, "\\\'", "\'");
		data = DojoExternalInterface.replaceStr(data, "\\\"", "\"");
		
		return data;
	}
	
	private static function encodeData(data){
		//getURL("javascript:dojo.debug('inside flash, data before="+data+"')");

		// double encode all entity values, or they will be mis-decoded
		// by Flash when returned
		data = DojoExternalInterface.replaceStr(data, "&", "&amp;");
		
		// certain XMLish characters break Flash's wire serialization for
		// ExternalInterface; encode these into a custom encoding, rather than
		// the standard entity encoding, because otherwise we won't be able to
		// differentiate between our own encoding and any entity characters
		// that are being used in the string itself
		data = DojoExternalInterface.replaceStr(data, '<', '&custom_lt;');
		data = DojoExternalInterface.replaceStr(data, '>', '&custom_gt;');
		
		// encode control characters and JavaScript delimiters
		data = DojoExternalInterface.replaceStr(data, "\n", "\\n");
		data = DojoExternalInterface.replaceStr(data, "\r", "\\r");
		data = DojoExternalInterface.replaceStr(data, "\f", "\\f");
		data = DojoExternalInterface.replaceStr(data, "'", "\\'");
		data = DojoExternalInterface.replaceStr(data, '"', '\"');
		
		//getURL("javascript:dojo.debug('inside flash, data after="+data+"')");
		return data;
	}
	
	/** 
			Flash ActionScript has no String.replace method or support for
			Regular Expressions! We roll our own very simple one.
	*/
	private static function replaceStr(inputStr:String, replaceThis:String, 
																		 withThis:String):String {
		var splitStr = inputStr.split(replaceThis)
		inputStr = splitStr.join(withThis)
		return inputStr;
	}
	
	private static function getDojoPath(){
		var url = _root._url;
		var start = url.indexOf("baseRelativePath=") + "baseRelativePath=".length;
		var path = url.substring(start);
		var end = path.indexOf("&");
		if(end != -1){
			path = path.substring(0, end);
		}
		return path;
	}
}

// vim:ts=4:noet:tw=0:

__CPAN_DIR__ src/flash/flash6
__CPAN_FILE__ src/flash/flash6/DojoExternalInterface.as
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/** 
		An implementation of Flash 8's ExternalInterface that works with Flash 6
		and which is source-compatible with Flash 8. 
		
		@author Brad Neuberg, bkn3@columbia.edu 
*/

class DojoExternalInterface{
	public static var available:Boolean;
	public static var dojoPath = "";
	
	public static var _fscommandReady = false;
	public static var _callbacks = new Array();

	public static function initialize(){ 
		//getURL("javascript:dojo.debug('FLASH:DojoExternalInterface initialize')");
		// FIXME: Set available variable by testing for capabilities
		DojoExternalInterface.available = true;
		
		// extract the dojo base path
		DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath();
		//getURL("javascript:dojo.debug('FLASH:dojoPath="+DojoExternalInterface.dojoPath+"')");
		
		// Sometimes, on IE, the fscommand infrastructure can take a few hundred
		// milliseconds the first time a page loads. Set a timer to keep checking
		// to make sure we can issue fscommands; otherwise, our calls to fscommand
		// for setCallback() and loaded() will just "disappear"
		_root.fscommandReady = false;
		var fsChecker = function(){
			// issue a test fscommand
			fscommand("fscommandReady");
			
			// JavaScript should set _root.fscommandReady if it got the call
			if(_root.fscommandReady == "true"){
				DojoExternalInterface._fscommandReady = true;
				clearInterval(_root.fsTimer);
			}
		};
		_root.fsTimer = setInterval(fsChecker, 100);
	}
	
	public static function addCallback(methodName:String, instance:Object, 
											method:Function) : Boolean{
		// A variable that indicates whether the call below succeeded
		_root._succeeded = null;
		
		// Callbacks are registered with the JavaScript side as follows.
		// On the Flash side, we maintain a lookup table that associates
		// the methodName with the actual instance and method that are
		// associated with this method.
		// Using fscommand, we send over the action "addCallback", with the
		// argument being the methodName to add, such as "foobar".
		// The JavaScript takes these values and registers the existence of
		// this callback point.
		
		// precede the method name with a _ character in case it starts
		// with a number
		_callbacks["_" + methodName] = {_instance: instance, _method: method};
		_callbacks[_callbacks.length] = methodName;
		
		// The API for ExternalInterface says we have to make sure the call
		// succeeded; check to see if there is a value 
		// for _succeeded, which is set by the JavaScript side
		if(_root._succeeded == null){
			return false;
		}else{
			return true;
		}
	}
	
	public static function call(methodName:String, 
								resultsCallback:Function) : Void{
		// FIXME: support full JSON serialization
		
		// First, we pack up all of the arguments to this call and set them
		// as Flash variables, which the JavaScript side will unpack using
		// plugin.GetVariable(). We set the number of arguments as "_numArgs",
		// and add each argument as a variable, such as "_1", "_2", etc., starting
		// from 0.
		// We then execute an fscommand with the action "call" and the
		// argument being the method name. JavaScript takes the method name,
		// retrieves the arguments using GetVariable, executes the method,
		// and then places the return result in a Flash variable
		// named "_returnResult".
		_root._numArgs = arguments.length - 2;
		for(var i = 2; i < arguments.length; i++){
			var argIndex = i - 2;
			_root["_" + argIndex] = arguments[i];
		}
		
		_root._returnResult = undefined;
		fscommand("call", methodName);
		
		// immediately return if the caller is not waiting for return results
		if(resultsCallback == undefined || resultsCallback == null){
			return;
		}
		
		// check at regular intervals for return results	
		var resultsChecker = function(){
			if((typeof _root._returnResult != "undefined")&&
				(_root._returnResult != "undefined")){
				clearInterval(_root._callbackID);
				resultsCallback.call(null, _root._returnResult);
			}
		};	
		_root._callbackID = setInterval(resultsChecker, 100);
	}
	
	/** 
			Called by Flash to indicate to JavaScript that we are ready to have
			our Flash functions called. Calling loaded()
			will fire the dojo.flash.loaded() event, so that JavaScript can know that
			Flash has finished loading and adding its callbacks, and can begin to
			interact with the Flash file.
	*/
	public static function loaded(){
		//getURL("javascript:dojo.debug('FLASH:loaded')");
		
		// one more step: see if fscommands are ready to be executed; if not,
		// set an interval that will keep running until fscommands are ready;
		// make sure the gateway is loaded as well
		var execLoaded = function(){
			if(DojoExternalInterface._fscommandReady == true){
				clearInterval(_root.loadedInterval);
				
				// initialize the small Flash file that helps gateway JS to Flash
				// calls
				DojoExternalInterface._initializeFlashRunner();
			}	
		};
		
		if(_fscommandReady == true){
			execLoaded();
		}else{
			_root.loadedInterval = setInterval(execLoaded, 50);
		}
	}
	
	/** 
			Handles and executes a JavaScript to Flash method call. Used by
			initializeFlashRunner. 
	*/
	public static function _handleJSCall(){
		// get our parameters
		var numArgs = parseInt(_root._numArgs);
		var jsArgs = new Array();
		for(var i = 0; i < numArgs; i++){
			var currentValue = _root["_" + i];
			jsArgs.push(currentValue);
		}
		
		// get our function name
		var functionName = _root._functionName;
		
		// now get the actual instance and method object to execute on,
		// using our lookup table that was constructed by calls to
		// addCallback on initialization
		var instance = _callbacks["_" + functionName]._instance;
		var method = _callbacks["_" + functionName]._method;
		
		// execute it
		var results = method.apply(instance, jsArgs);
		
		// return the results
		_root._returnResult = results;
	}
	
	/** Called by the flash6_gateway.swf to indicate that it is loaded. */
	public static function _gatewayReady(){
		for(var i = 0; i < _callbacks.length; i++){
			fscommand("addCallback", _callbacks[i]);
		}
		call("dojo.flash.loaded");
	}
	
	/** 
			When JavaScript wants to communicate with Flash it simply sets
			the Flash variable "_execute" to true; this method creates the
			internal Movie Clip, called the Flash Runner, that makes this
			magic happen.
	*/
	public static function _initializeFlashRunner(){
		// figure out where our Flash movie is
		var swfLoc = DojoExternalInterface.dojoPath + "flash6_gateway.swf";
		
		// load our gateway helper file
		_root.createEmptyMovieClip("_flashRunner", 5000);
		_root._flashRunner._lockroot = true;
		_root._flashRunner.loadMovie(swfLoc);
	}
	
	private static function getDojoPath(){
		var url = _root._url;
		var start = url.indexOf("baseRelativePath=") + "baseRelativePath=".length;
		var path = url.substring(start);
		var end = path.indexOf("&");
		if(end != -1){
			path = path.substring(0, end);
		}
		return path;
	}
}

// vim:ts=4:noet:tw=0:

__CPAN_FILE__ src/flash/flash6/flash6_gateway.fla
ÐÏà¡±á>þÿ	þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRoot Entryÿÿÿÿÿÿÿÿpª|YªrÏƒRASH€fUajbÆÀContentsÿÿÿÿÿÿÿÿ(¾APage 1ÿÿÿÿÿÿÿÿÿÿÿÿ§ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿ'ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿ)*+,-./0123456789:;<=>?@ABCDEFGMÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRoot Entryÿÿÿÿÿÿÿÿpª|YªrÏƒRASHppÚ«žZÆ	ÀContentsÿÿÿÿÿÿÿÿ¾APage 1ÿÿÿÿÿÿÿÿÿÿÿÿ§ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿ

 !"#$%&HÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIJKLþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ	

þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿCPicPageÿÿ	CPicLayerÿÿ	CPicFrame€€ÿÿÿ?ÿÿÿþÿstart2ÿþÿÿÓ/** 

	Very simple two frame Flash file; frame 1 says we are all loaded, while frame 2

	says to execute a JavaScript call. This small file is necessary because ActionScript

	2.0 has no way to know when a specific frame has been called, which we use for all

	of our code. However, the Flash 6 communication we use kicks off a call by jumping

	to a specific frame and then calling Play() on the Flash player.

*/



DojoExternalIn	

þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿterface._gatewayReady();

stop();

ÿþÿ€€€ÿÿÿ?ÿÿÿþÿexecute}vÿþÿ/DojoExternalInterface._handleJSCall();

stop();ÿþÿ€€ÿþÿLayer 1ÿÿÿÿOÿOÿ€€("javascript:alert('TCallLabel')");

DojoExteÿÿCPicPageÿÿ	CPicLayerÿÿ	CPicFrame€€ÿÿÿ?ÿÿÿþÿstartZzÿþÿÿÓ/** 

	Very simple two frame Flash file; frame 1 says we are all loaded, while frame 2

	says to execute a JavaScript call. This small file is necessary because ActionScript

	2.0 has no way to know when a specific frame has been called, which we use for all

	of our code. However, the Flash 6 communication we use kicks off a call by jumping

	to a specific frame and then calling Play() on the Flash player.

*/



DojoExternalIn8ÿÿ
CDocumentPagePage 1ÿþÿScene 1ÿþÿsêËC ÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿÏû6Dÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿø*@h�hhhhÿÿÿÿÀÀÀÿ´ÿþÿPropSheet::ActiveTabÿþÿ7628”ÿþÿ%PublishFormatProperties::htmlFileNameÿþÿflash6_gateway.htmlÿþÿ"PublishHtmlProperties::StartPausedÿþÿ0ÿþÿ PublishRNWKProperties::speed256Kÿþÿ0ÿþÿ!PublishGifProperties::PaletteNameÿþÿÿþÿPublishFormatProperties::jpegÿþÿ0ÿþÿPublishHtmlProperties::Loopÿþÿ1ÿþÿPublishProfileProperties::nameÿþÿDefaultÿþÿVector::Debugging Permittedÿþÿ0ÿþÿ"PublishQTProperties::MatchMovieDimÿþÿ1ÿþÿ PublishQTProperties::AlphaOptionÿþÿÿþÿ PublishQTProperties::LayerOptionÿþÿÿþÿ4PublishHtmlProperties::UsingDefaultAlternateFilenameÿþÿ1ÿþÿPublishHtmlProperties::Unitsÿþÿ0ÿþÿ%PublishHtmlProperties::showTagWarnMsgÿþÿ1ÿþÿVector::External Playerÿþÿÿþÿ&PublishRNWKProperties::singleRateAudioÿþÿ0ÿþÿ&PublishRNWKProperties::speedSingleISDNÿþÿ0ÿþÿ$PublishPNGProperties::OptimizeColorsÿþÿ1ÿþÿPublishQTProperties::Widthÿþÿ550ÿþÿ%PublishFormatProperties::projectorMacÿþÿ0ÿþÿ'PublishFormatProperties::gifDefaultNameÿþÿ1ÿþÿ&PublishFormatProperties::flashFileNameÿþÿ..\..\..\flash6_gateway.swfÿþÿVector::Package PathsÿþÿÿþÿVector::Compress Movieÿþÿ1ÿþÿ#PublishRNWKProperties::flashBitRateÿþÿ1200ÿþÿ%PublishRNWKProperties::mediaCopyrightÿþÿ(c) 2000ÿþÿPublishGifProperties::Smoothÿþÿ1ÿþÿPublishFormatProperties::htmlÿþÿ0ÿþÿ$PublishFormatProperties::pngFileNameÿþÿflash6_gateway.pngÿþÿ(PublishHtmlProperties::VerticalAlignmentÿþÿ1ÿþÿPublishHtmlProperties::Qualityÿþÿ4ÿþÿVector::FireFoxÿþÿ0ÿþÿ"PublishRNWKProperties::exportAudioÿþÿ1ÿþÿ PublishRNWKProperties::speed384Kÿþÿ0ÿþÿ!PublishRNWKProperties::exportSMILÿþÿ1ÿþÿ"PublishGifProperties::DitherOptionÿþÿÿþÿ-PublishFormatProperties::generatorDefaultNameÿþÿ1ÿþÿ!PublishHtmlProperties::DeviceFontÿþÿ0ÿþÿVector::Override Soundsÿþÿ0ÿþÿ'PublishRNWKProperties::mediaDescriptionÿþÿÿþÿ"PublishPNGProperties::FilterOptionÿþÿÿþÿPublishFormatProperties::gifÿþÿ0ÿþÿ(PublishFormatProperties::jpegDefaultNameÿþÿ1ÿþÿ(PublishFormatProperties::rnwkDefaultNameÿþÿ1ÿþÿ*PublishFormatProperties::generatorFileNameÿþÿflash6_gateway.swtÿþÿVector::Templateÿþÿ0ÿþÿ2PublishHtmlProperties::VersionDetectionIfAvailableÿþÿ0ÿþÿ*PublishHtmlProperties::HorizontalAlignmentÿþÿ1ÿþÿ"PublishHtmlProperties::DisplayMenuÿþÿ1ÿþÿVector::Protectÿþÿ0ÿþÿVector::Qualityÿþÿ80ÿþÿPublishJpegProperties::DPIÿþÿ4718592ÿþÿPublishGifProperties::Interlaceÿþÿ0ÿþÿ"PublishGifProperties::DitherSolidsÿþÿ0ÿþÿPublishPNGProperties::Smoothÿþÿ1ÿþÿPublishPNGProperties::BitDepthÿþÿ24-bit with AlphaÿþÿPublishQTProperties::Flattenÿþÿ1ÿþÿ#PublishFormatProperties::qtFileNameÿþÿflash6_gateway.movÿþÿPublishRNWKProperties::speed28Kÿþÿ1ÿþÿ!PublishRNWKProperties::mediaTitleÿþÿÿþÿ$PublishRNWKProperties::mediaKeywordsÿþÿÿþÿPublishGifProperties::Widthÿþÿ550ÿþÿPublishGifProperties::Loopÿþÿ1ÿþÿPublishFormatProperties::flashÿþÿ1ÿþÿPublishJpegProperties::Qualityÿþÿ80ÿþÿ$PublishRNWKProperties::realVideoRateÿþÿ100000ÿþÿ$PublishRNWKProperties::speedDualISDNÿþÿ0ÿþÿ#PublishGifProperties::MatchMovieDimÿþÿ1ÿþÿ#PublishGifProperties::PaletteOptionÿþÿÿþÿ"PublishPNGProperties::DitherOptionÿþÿÿþÿ0PublishFormatProperties::projectorMacDefaultNameÿþÿ1ÿþÿ'PublishFormatProperties::pngDefaultNameÿþÿ1ÿþÿ-PublishFormatProperties::projectorWinFileNameÿþÿflash6_gateway.exeÿþÿPublishHtmlProperties::Alignÿþÿ0ÿþÿ!PublishProfileProperties::versionÿþÿ1ÿþÿVector::Package Export Frameÿþÿ1ÿþÿ$PublishJpegProperties::MatchMovieDimÿþÿ1ÿþÿ#PublishPNGProperties::MatchMovieDimÿþÿ1ÿþÿ#PublishPNGProperties::PaletteOptionÿþÿÿþÿ)PublishFormatProperties::flashDefaultNameÿþÿ0ÿþÿ%PublishFormatProperties::jpegFileNameÿþÿflash6_gateway.jpgÿþÿPublishHtmlProperties::Widthÿþÿ550ÿþÿPublishHtmlProperties::Heightÿþÿ400ÿþÿVector::Omit Trace Actionsÿþÿ0ÿþÿVector::Debugging Passwordÿþÿÿþÿ"PublishJpegProperties::Progressiveÿþÿ0ÿþÿ"PublishPNGProperties::DitherSolidsÿþÿ0ÿþÿ#PublishQTProperties::PlayEveryFrameÿþÿ0ÿþÿPublishFormatProperties::pngÿþÿ0ÿþÿPublishFormatProperties::rnwkÿþÿ0ÿþÿ(PublishFormatProperties::htmlDefaultNameÿþÿ1ÿþÿ-PublishFormatProperties::projectorMacFileNameÿþÿflash6_gateway.hqxÿþÿ2PublishHtmlProperties::UsingDefaultContentFilenameÿþÿ1ÿþÿ!PublishHtmlProperties::WindowModeÿþÿ0ÿþÿ'PublishHtmlProperties::TemplateFileNameÿþÿ�C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Html\Default.htmlÿþÿVector::TopDownÿþÿ0ÿþÿVector::DeviceSoundÿþÿ0ÿþÿPublishJpegProperties::Sizeÿþÿ0ÿþÿPublishGifProperties::Heightÿþÿ400ÿþÿPublishPNGProperties::Interlaceÿþÿ0ÿþÿ"PublishFormatProperties::generatorÿþÿ0ÿþÿ&PublishHtmlProperties::ContentFilenameÿþÿÿþÿ(PublishHtmlProperties::AlternateFilenameÿþÿÿþÿ+PublishHtmlProperties::OwnAlternateFilenameÿþÿÿþÿVector::Reportÿþÿ0ÿþÿPublishRNWKProperties::speed56Kÿþÿ1ÿþÿPublishGifProperties::LoopCountÿþÿÿþÿ'PublishGifProperties::TransparentOptionÿþÿÿþÿPublishGifProperties::MaxColorsÿþÿ255ÿþÿ%PublishPNGProperties::RemoveGradientsÿþÿ0ÿþÿPublishQTProperties::Heightÿþÿ400ÿþÿPublishFormatProperties::qtÿþÿ0ÿþÿVector::Stream Compressÿþÿ7ÿþÿVector::Event Formatÿþÿ0ÿþÿVector::Versionÿþÿ6ÿþÿ"PublishRNWKProperties::audioFormatÿþÿ0ÿþÿ$PublishGifProperties::OptimizeColorsÿþÿ1ÿþÿ0PublishFormatProperties::projectorWinDefaultNameÿþÿ1ÿþÿPublishHtmlProperties::Scaleÿþÿ0ÿþÿVector::Event Compressÿþÿ7ÿþÿVector::ActionScriptVersionÿþÿ2ÿþÿPublishJpegProperties::Heightÿþÿ400ÿþÿ PublishRNWKProperties::speed512Kÿþÿ0ÿþÿ%PublishGifProperties::RemoveGradientsÿþÿ0ÿþÿPublishPNGProperties::Widthÿþÿ550ÿþÿPublishPNGProperties::Heightÿþÿ400ÿþÿ&PublishFormatProperties::qtDefaultNameÿþÿ1ÿþÿ$PublishFormatProperties::gifFileNameÿþÿflash6_gateway.gifÿþÿ"PublishHtmlProperties::VersionInfoÿþÿÿþÿVector::Stream Formatÿþÿ0ÿþÿPublishJpegProperties::Widthÿþÿ550ÿþÿ"PublishRNWKProperties::exportFlashÿþÿ1ÿþÿ&PublishRNWKProperties::showBitrateDlogÿþÿ1ÿþÿ(PublishRNWKProperties::speedCorporateLANÿþÿ0ÿþÿ"PublishRNWKProperties::mediaAuthorÿþÿÿþÿPublishGifProperties::Animatedÿþÿ0ÿþÿ&PublishGifProperties::TransparentAlphaÿþÿ128ÿþÿ!PublishPNGProperties::Transparentÿþÿ0ÿþÿ!PublishPNGProperties::PaletteNameÿþÿÿþÿ*PublishQTProperties::UseQTSoundCompressionÿþÿ0ÿþÿPublishQTProperties::Loopingÿþÿ0ÿþÿ%PublishFormatProperties::defaultNamesÿþÿ0ÿþÿ%PublishFormatProperties::projectorWinÿþÿ0ÿþÿ%PublishFormatProperties::rnwkFileNameÿþÿflash6_gateway.smilÿþÿ,PublishHtmlProperties::UsingOwnAlternateFileÿþÿ0ÿþÿPublishPNGProperties::MaxColorsÿþÿ255ÿþÿ%PublishQTProperties::ControllerOptionÿþÿ0ÿþÿ"PublishQTProperties::PausedAtStartÿþÿ0ÿÿÿÿÿþÿÿþÿüÿÿ	CColorDefÿ€ÿ€ÿ€3ÿPï€fÿPï0€™ÿPïH€ÌÿPï`€ÿÿPïx€3ÿï€33ÿ(ï€3fÿ<ï0€3™ÿCïH€3ÌÿFï`€3ÿÿHïx€fÿï0€f3ÿï0€ffÿ(ï0€f™ÿ5ïH€fÌÿ<ï`€fÿÿ@ïx€ÿ€333ÿ0€ÿ€3ÿ ï€33ÿxï€f3ÿdï0€™3ÿ]ïH€Ì3ÿZï`€ÿ3ÿXïx€33ÿÈï€333ÿ0€3f3ÿPPH€3™3ÿPx`€3Ì3ÿP�x€3ÿ3ÿPï�€f3ÿÜï0€f33ÿPH€ff3ÿ(PH€f™3ÿ<x`€fÌ3ÿC�x€fÿ3ÿFï�€ÿ€fffÿ`€ÿ€fÿ ï0€3fÿŒï0€ffÿxï0€™fÿkïH€Ìfÿdï`€ÿfÿ`ïx€3fÿ´ï0€33fÿ PH€3ffÿxPH€3™fÿdx`€3Ìfÿ]�x€3ÿfÿZï�€ffÿÈï0€f3fÿÈPH€fffÿ`€f™fÿP0x€fÌfÿPx�€fÿfÿPï¨€ÿ€™™™ÿ�€ÿ€™ÿ ïH€3™ÿ“ïH€f™ÿ…ïH€™™ÿxïH€Ì™ÿnï`€ÿ™ÿhïx€3™ÿ­ïH€33™ÿ x`€3f™ÿŒx`€3™™ÿxx`€3Ì™ÿk�x€3ÿ™ÿdï�€f™ÿ»ïH€f3™ÿ´x`€ff™ÿ 0x€f™™ÿx0x€fÌ™ÿdx�€fÿ™ÿ]ï¨€ÿ€ÌÌÌÿÀ€ÿ€Ìÿ ï`€3Ìÿ–ï`€fÌÿŒï`€™Ìÿ‚ï`€ÌÌÿxï`€ÿÌÿpïx€3Ìÿªï`€33Ìÿ �x€3fÌÿ“�x€3™Ìÿ…�x€3ÌÌÿx�x€3ÿÌÿnï�€fÌÿ´ï`€f3Ìÿ­�x€ffÌÿ x�€f™ÌÿŒx�€fÌÌÿxx�€fÿÌÿkï¨€ÿ€ÿÿÿÿð€ÿ€ÿÿ ïx€3ÿÿ˜ïx€fÿÿ�ïx€™ÿÿˆïx€Ìÿÿ€ïx€ÿÿÿxïx€3ÿÿ¨ïx€33ÿÿ ï�€3fÿÿ–ï�€3™ÿÿŒï�€3Ìÿÿ‚ï�€3ÿÿÿxï�€fÿÿ°ïx€f3ÿÿªï�€ffÿÿ ï¨€f™ÿÿ“ï¨€fÌÿÿ…ï¨€fÿÿÿxï¨€ÿ€ÿÿïx€ÿ€™ÿïH€™3ÿ
ïH€™fterface._gatewayReady();

stop();

ÿþÿ€€€ÿÿÿ?ÿÿÿþÿexecute ÿþÿ/DojoExternalInterface._handleJSCall();

stop();ÿþÿ€€ÿþÿLayer 1ÿÿÿÿOÿOÿ€€("javascript:alert('TCallLabel')");

DojoExte8ÿÿ
CDocumentPagePage 1ÿþÿScene 1ÿþÿsêËC ÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿDDÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÌÈ
h�hhhhÿÿÿÿÀÀÀÿ´ÿþÿPropSheet::ActiveTabÿþÿ7628”ÿþÿ!PublishGifProperties::PaletteNameÿþÿÿþÿ PublishRNWKProperties::speed256Kÿþÿ0ÿþÿ"PublishHtmlProperties::StartPausedÿþÿ0ÿþÿ%PublishFormatProperties::htmlFileNameÿþÿflash6_gateway.htmlÿþÿ PublishQTProperties::LayerOptionÿþÿÿþÿ PublishQTProperties::AlphaOptionÿþÿÿþÿ"PublishQTProperties::MatchMovieDimÿþÿ1ÿþÿVector::Debugging Permittedÿþÿ0ÿþÿPublishProfileProperties::nameÿþÿDefaultÿþÿPublishHtmlProperties::Loopÿþÿ1ÿþÿPublishFormatProperties::jpegÿþÿ0ÿþÿPublishQTProperties::Widthÿþÿ550ÿþÿ$PublishPNGProperties::OptimizeColorsÿþÿ1ÿþÿ&PublishRNWKProperties::speedSingleISDNÿþÿ0ÿþÿ&PublishRNWKProperties::singleRateAudioÿþÿ0ÿþÿVector::External Playerÿþÿÿþÿ%PublishHtmlProperties::showTagWarnMsgÿþÿ1ÿþÿPublishHtmlProperties::Unitsÿþÿ0ÿþÿ4PublishHtmlProperties::UsingDefaultAlternateFilenameÿþÿ1ÿþÿPublishGifProperties::Smoothÿþÿ1ÿþÿ%PublishRNWKProperties::mediaCopyrightÿþÿ(c) 2000ÿþÿ#PublishRNWKProperties::flashBitRateÿþÿ1200ÿþÿVector::Compress Movieÿþÿ1ÿþÿVector::Package Pathsÿþÿÿþÿ&PublishFormatProperties::flashFileNameÿþÿ..\..\..\flash6_gateway.swfÿþÿ'PublishFormatProperties::gifDefaultNameÿþÿ1ÿþÿ%PublishFormatProperties::projectorMacÿþÿ0ÿþÿ"PublishGifProperties::DitherOptionÿþÿÿþÿ!PublishRNWKProperties::exportSMILÿþÿ1ÿþÿ PublishRNWKProperties::speed384Kÿþÿ0ÿþÿ"PublishRNWKProperties::exportAudioÿþÿ1ÿþÿVector::FireFoxÿþÿ0ÿþÿPublishHtmlProperties::Qualityÿþÿ4ÿþÿ(PublishHtmlProperties::VerticalAlignmentÿþÿ1ÿþÿ$PublishFormatProperties::pngFileNameÿþÿflash6_gateway.pngÿþÿPublishFormatProperties::htmlÿþÿ0ÿþÿ"PublishPNGProperties::FilterOptionÿþÿÿþÿ'PublishRNWKProperties::mediaDescriptionÿþÿÿþÿVector::Override Soundsÿþÿ0ÿþÿ!PublishHtmlProperties::DeviceFontÿþÿ0ÿþÿ-PublishFormatProperties::generatorDefaultNameÿþÿ1ÿþÿPublishQTProperties::Flattenÿþÿ1ÿþÿPublishPNGProperties::BitDepthÿþÿ24-bit with AlphaÿþÿPublishPNGProperties::Smoothÿþÿ1ÿþÿ"PublishGifProperties::DitherSolidsÿþÿ0ÿþÿPublishGifProperties::Interlaceÿþÿ0ÿþÿPublishJpegProperties::DPIÿþÿ4718592ÿþÿVector::Qualityÿþÿ80ÿþÿVector::Protectÿþÿ0ÿþÿ"PublishHtmlProperties::DisplayMenuÿþÿ1ÿþÿ*PublishHtmlProperties::HorizontalAlignmentÿþÿ1ÿþÿ2PublishHtmlProperties::VersionDetectionIfAvailableÿþÿ0ÿþÿVector::Templateÿþÿ0ÿþÿ*PublishFormatProperties::generatorFileNameÿþÿflash6_gateway.swtÿþÿ(PublishFormatProperties::rnwkDefaultNameÿþÿ1ÿþÿ(PublishFormatProperties::jpegDefaultNameÿþÿ1ÿþÿPublishFormatProperties::gifÿþÿ0ÿþÿPublishGifProperties::Loopÿþÿ1ÿþÿPublishGifProperties::Widthÿþÿ550ÿþÿ$PublishRNWKProperties::mediaKeywordsÿþÿÿþÿ!PublishRNWKProperties::mediaTitleÿþÿÿþÿPublishRNWKProperties::speed28Kÿþÿ1ÿþÿ#PublishFormatProperties::qtFileNameÿþÿflash6_gateway.movÿþÿ"PublishPNGProperties::DitherOptionÿþÿÿþÿ#PublishGifProperties::PaletteOptionÿþÿÿþÿ#PublishGifProperties::MatchMovieDimÿþÿ1ÿþÿ$PublishRNWKProperties::speedDualISDNÿþÿ0ÿþÿ$PublishRNWKProperties::realVideoRateÿþÿ100000ÿþÿPublishJpegProperties::Qualityÿþÿ80ÿþÿPublishFormatProperties::flashÿþÿ1ÿþÿ#PublishPNGProperties::PaletteOptionÿþÿÿþÿ#PublishPNGProperties::MatchMovieDimÿþÿ1ÿþÿ$PublishJpegProperties::MatchMovieDimÿþÿ1ÿþÿVector::Package Export Frameÿþÿ1ÿþÿ!PublishProfileProperties::versionÿþÿ1ÿþÿPublishHtmlProperties::Alignÿþÿ0ÿþÿ-PublishFormatProperties::projectorWinFileNameÿþÿflash6_gateway.exeÿþÿ'PublishFormatProperties::pngDefaultNameÿþÿ1ÿþÿ0PublishFormatProperties::projectorMacDefaultNameÿþÿ1ÿþÿ#PublishQTProperties::PlayEveryFrameÿþÿ0ÿþÿ"PublishPNGProperties::DitherSolidsÿþÿ0ÿþÿ"PublishJpegProperties::Progressiveÿþÿ0ÿþÿVector::Debugging PasswordÿþÿÿþÿVector::Omit Trace Actionsÿþÿ0ÿþÿPublishHtmlProperties::Heightÿþÿ400ÿþÿPublishHtmlProperties::Widthÿþÿ550ÿþÿ%PublishFormatProperties::jpegFileNameÿþÿflash6_gateway.jpgÿþÿ)PublishFormatProperties::flashDefaultNameÿþÿ0ÿþÿPublishPNGProperties::Interlaceÿþÿ0ÿþÿPublishGifProperties::Heightÿþÿ400ÿþÿPublishJpegProperties::Sizeÿþÿ0ÿþÿVector::DeviceSoundÿþÿ0ÿþÿVector::TopDownÿþÿ0ÿþÿ'PublishHtmlProperties::TemplateFileNameÿþÿ�C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Html\Default.htmlÿþÿ!PublishHtmlProperties::WindowModeÿþÿ0ÿþÿ2PublishHtmlProperties::UsingDefaultContentFilenameÿþÿ1ÿþÿ-PublishFormatProperties::projectorMacFileNameÿþÿflash6_gateway.hqxÿþÿ(PublishFormatProperties::htmlDefaultNameÿþÿ1ÿþÿPublishFormatProperties::rnwkÿþÿ0ÿþÿPublishFormatProperties::pngÿþÿ0ÿþÿPublishQTProperties::Heightÿþÿ400ÿþÿ%PublishPNGProperties::RemoveGradientsÿþÿ0ÿþÿPublishGifProperties::MaxColorsÿþÿ255ÿþÿ'PublishGifProperties::TransparentOptionÿþÿÿþÿPublishGifProperties::LoopCountÿþÿÿþÿPublishRNWKProperties::speed56Kÿþÿ1ÿþÿVector::Reportÿþÿ0ÿþÿ+PublishHtmlProperties::OwnAlternateFilenameÿþÿÿþÿ(PublishHtmlProperties::AlternateFilenameÿþÿÿþÿ&PublishHtmlProperties::ContentFilenameÿþÿÿþÿ"PublishFormatProperties::generatorÿþÿ0ÿþÿ$PublishGifProperties::OptimizeColorsÿþÿ1ÿþÿ"PublishRNWKProperties::audioFormatÿþÿ0ÿþÿVector::Versionÿþÿ6ÿþÿVector::Event Formatÿþÿ0ÿþÿVector::Stream Compressÿþÿ7ÿþÿPublishFormatProperties::qtÿþÿ0ÿþÿPublishPNGProperties::Heightÿþÿ400ÿþÿPublishPNGProperties::Widthÿþÿ550ÿþÿ%PublishGifProperties::RemoveGradientsÿþÿ0ÿþÿ PublishRNWKProperties::speed512Kÿþÿ0ÿþÿPublishJpegProperties::Heightÿþÿ400ÿþÿVector::ActionScriptVersionÿþÿ2ÿþÿVector::Event Compressÿþÿ7ÿþÿPublishHtmlProperties::Scaleÿþÿ0ÿþÿ0PublishFormatProperties::projectorWinDefaultNameÿþÿ1ÿþÿPublishQTProperties::Loopingÿþÿ0ÿþÿ*PublishQTProperties::UseQTSoundCompressionÿþÿ0ÿþÿ!PublishPNGProperties::PaletteNameÿþÿÿþÿ!PublishPNGProperties::Transparentÿþÿ0ÿþÿ&PublishGifProperties::TransparentAlphaÿþÿ128ÿþÿPublishGifProperties::Animatedÿþÿ0ÿþÿ"PublishRNWKProperties::mediaAuthorÿþÿÿþÿ(PublishRNWKProperties::speedCorporateLANÿþÿ0ÿþÿ&PublishRNWKProperties::showBitrateDlogÿþÿ1ÿþÿ"PublishRNWKProperties::exportFlashÿþÿ1ÿþÿPublishJpegProperties::Widthÿþÿ550ÿþÿVector::Stream Formatÿþÿ0ÿþÿ"PublishHtmlProperties::VersionInfoÿþÿÿþÿ$PublishFormatProperties::gifFileNameÿþÿflash6_gateway.gifÿþÿ&PublishFormatProperties::qtDefaultNameÿþÿ1ÿþÿ"PublishQTProperties::PausedAtStartÿþÿ0ÿþÿ%PublishQTProperties::ControllerOptionÿþÿ0ÿþÿPublishPNGProperties::MaxColorsÿþÿ255ÿþÿ,PublishHtmlProperties::UsingOwnAlternateFileÿþÿ0ÿþÿ%PublishFormatProperties::rnwkFileNameÿþÿflash6_gateway.smilÿþÿ%PublishFormatProperties::projectorWinÿþÿ0ÿþÿ%PublishFormatProperties::defaultNamesÿþÿ0ÿÿÿÿÿþÿÿþÿüÿÿ	CColorDefÿ€ÿ€ÿ€3ÿPï€fÿPï0€™ÿPïH€ÌÿPï`€ÿÿPïx€3ÿï€33ÿ(ï€3fÿ<ï0€3™ÿCïH€3ÌÿFï`€3ÿÿHïx€fÿï0€f3ÿï0€ffÿ(ï0€f™ÿ5ïH€fÌÿ<ï`€fÿÿ@ïx€ÿ€333ÿ0€ÿ€3ÿ ï€33ÿxï€f3ÿdï0€™3ÿ]ïH€Ì3ÿZï`€ÿ3ÿXïx€33ÿÈï€333ÿ0€3f3ÿPPH€3™3ÿPx`€3Ì3ÿP�x€3ÿ3ÿPï�€f3ÿÜï0€f33ÿPH€ff3ÿ(PH€f™3ÿ<x`€fÌ3ÿC�x€fÿ3ÿFï�€ÿ€fffÿ`€ÿ€fÿ ï0€3fÿŒï0€ffÿxï0€™fÿkïH€Ìfÿdï`€ÿfÿ`ïx€3fÿ´ï0€33fÿ PH€3ffÿxPH€3™fÿdx`€3Ìfÿ]�x€3ÿfÿZï�€ffÿÈï0€f3fÿÈPH€fffÿ`€f™fÿP0x€fÌfÿPx�€fÿfÿPï¨€ÿ€™™™ÿ�€ÿ€™ÿ ïH€3™ÿ“ïH€f™ÿ…ïH€™™ÿxïH€Ì™ÿnï`€ÿ™ÿhïx€3™ÿ­ïH€33™ÿ x`€3f™ÿŒx`€3™™ÿxx`€3Ì™ÿk�x€3ÿ™ÿdï�€f™ÿ»ïH€f3™ÿ´x`€ff™ÿ 0x€f™™ÿx0x€fÌ™ÿdx�€fÿ™ÿ]ï¨€ÿ€ÌÌÌÿÀ€ÿ€Ìÿ ï`€3Ìÿ–ï`€fÌÿŒï`€™Ìÿ‚ï`€ÌÌÿxï`€ÿÌÿpïx€3Ìÿªï`€33Ìÿ �x€3fÌÿ“�x€3™Ìÿ…�x€3ÌÌÿx�x€3ÿÌÿnï�€fÌÿ´ï`€f3Ìÿ­�x€ffÌÿ x�€f™ÌÿŒx�€fÌÌÿxx�€fÿÌÿkï¨€ÿ€ÿÿÿÿð€ÿ€ÿÿ ïx€3ÿÿ˜ïx€fÿÿ�ïx€™ÿÿˆïx€Ìÿÿ€ïx€ÿÿÿxïx€3ÿÿ¨ïx€33ÿÿ ï�€3fÿÿ–ï�€3™ÿÿŒï�€3Ìÿÿ‚ï�€3ÿÿÿxï�€fÿÿ°ïx€f3ÿÿªï�€ffÿÿ ï¨€f™ÿÿ“ï¨€fÌÿÿ…ï¨€fÿÿÿxï¨€ÿ€ÿÿïx€ÿ€™ÿïH€™3ÿ
ïH€™fÿïH€™™ÿ(ïH€™Ìÿ2ï`€™ÿÿ8ïx€Ìÿï`€Ì3ÿ
ï`€Ìfÿï`€Ì™ÿï`€ÌÌÿ(ï`€Ìÿÿ0ïx€ÿÿïx€ÿ3ÿïx€ÿfÿïx€ÿ™ÿïx€ÿÌÿ ïx€ÿÿÿ(ïx€ÿ€ÿÿPïx€ÿ€™3ÿãïH€™33ÿx`€™f3ÿx`€™™3ÿ(x`€™Ì3ÿ5�x€™ÿ3ÿ<ï�€Ì3ÿæï`€Ì33ÿ�x€Ìf3ÿ
�x€Ì™3ÿ�x€ÌÌ3ÿ(�x€Ìÿ3ÿ2ï�€ÿ3ÿèïx€ÿ33ÿï�€ÿf3ÿ
ï�€ÿ™3ÿï�€ÿÌ3ÿï�€ÿÿ3ÿ(ï�€ÿ€ÿÿ ïx€ÿ€™fÿÕïH€™3fÿÜx`€™ffÿ0x€™™fÿ(0x€™Ìfÿ<x�€™ÿfÿCï¨€ÌfÿÜï`€Ì3fÿã�x€Ìffÿx�€Ì™fÿx�€ÌÌfÿ(x�€Ìÿfÿ5ï¨€ÿfÿàïx€ÿ3fÿæï�€ÿffÿï¨€ÿ™fÿ
ï¨€ÿÌfÿï¨€ÿÿfÿ(ï¨€ÿ€ÿÿÿ(ïx€ÿ€™™ÿÈïH€™3™ÿÈx`€™f™ÿÈ0x€™™™ÿ�€™Ì™ÿPP¨€™ÿ™ÿPïÀ€Ì™ÿÒï`€Ì3™ÿÕ�x€Ìf™ÿÜx�€Ì™™ÿP¨€ÌÌ™ÿ(P¨€Ìÿ™ÿ<ïÀ€ÿ™ÿØïx€ÿ3™ÿÜï�€ÿf™ÿãï¨€ÿ™™ÿïÀ€ÿÌ™ÿïÀ€ÿÿ™ÿ(ïÀ€ÿ€ÿÿÿxïx€ÿ€™Ìÿ¾ï`€™3Ìÿ»�x€™fÌÿ´x�€™™Ìÿ P¨€™ÌÌÿxP¨€™ÿÌÿdïÀ€ÌÌÿÈï`€Ì3ÌÿÈ�x€ÌfÌÿÈx�€Ì™ÌÿÈP¨€ÌÌÌÿÀ€ÌÿÌÿPïØ€ÿÌÿÐïx€ÿ3ÌÿÒï�€ÿfÌÿÕï¨€ÿ™ÌÿÜïÀ€ÿÌÌÿïØ€ÿÿÌÿ(ïØ€ÿ€ÿÿÿÈïx€ÿ€™ÿÿ¸ïx€™3ÿÿ´ï�€™fÿÿ­ï¨€™™ÿÿ ïÀ€™ÌÿÿŒïÀ€™ÿÿÿxïÀ€ÌÿÿÀïx€Ì3ÿÿ¾ï�€Ìfÿÿ»ï¨€Ì™ÿÿ´ïÀ€ÌÌÿÿ ïØ€ÌÿÿÿxïØ€ÿÿÿÈïx€ÿ3ÿÿÈï�€ÿfÿÿÈï¨€ÿ™ÿÿÈïÀ€ÿÌÿÿÈïØ€ÿÿÿÿð€ÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿïH€™™ÿ(ïH€™Ìÿ2ï`€™ÿÿ8ïx€Ìÿï`€Ì3ÿ
ï`€Ìfÿï`€Ì™ÿï`€ÌÌÿ(ï`€Ìÿÿ0ïx€ÿÿïx€ÿ3ÿïx€ÿfÿïx€ÿ™ÿïx€ÿÌÿ ïx€ÿÿÿ(ïx€ÿ€ÿÿPïx€ÿ€™3ÿãïH€™33ÿx`€™f3ÿx`€™™3ÿ(x`€™Ì3ÿ5�x€™ÿ3ÿ<ï�€Ì3ÿæï`€Ì33ÿ�x€Ìf3ÿ
�x€Ì™3ÿ�x€ÌÌ3ÿ(�x€Ìÿ3ÿ2ï�€ÿ3ÿèïx€ÿ33ÿï�€ÿf3ÿ
ï�€ÿ™3ÿï�€ÿÌ3ÿï�€ÿÿ3ÿ(ï�€ÿ€ÿÿ ïx€ÿ€™fÿÕïH€™3fÿÜx`€™ffÿ0x€™™fÿ(0x€™Ìfÿ<x�€™ÿfÿCï¨€ÌfÿÜï`€Ì3fÿã�x€Ìffÿx�€Ì™fÿx�€ÌÌfÿ(x�€Ìÿfÿ5ï¨€ÿfÿàïx€ÿ3fÿæï�€ÿffÿï¨€ÿ™fÿ
ï¨€ÿÌfÿï¨€ÿÿfÿ(ï¨€ÿ€ÿÿÿ(ïx€ÿ€™™ÿÈïH€™3™ÿÈx`€™f™ÿÈ0x€™™™ÿ�€™Ì™ÿPP¨€™ÿ™ÿPïÀ€Ì™ÿÒï`€Ì3™ÿÕ�x€Ìf™ÿÜx�€Ì™™ÿP¨€ÌÌ™ÿ(P¨€Ìÿ™ÿ<ïÀ€ÿ™ÿØïx€ÿ3™ÿÜï�€ÿf™ÿãï¨€ÿ™™ÿïÀ€ÿÌ™ÿïÀ€ÿÿ™ÿ(ïÀ€ÿ€ÿÿÿxïx€ÿ€™Ìÿ¾ï`€™3Ìÿ»�x€™fÌÿ´x�€™™Ìÿ P¨€™ÌÌÿxP¨€™ÿÌÿdïÀ€ÌÌÿÈï`€Ì3ÌÿÈ�x€ÌfÌÿÈx�€Ì™ÌÿÈP¨€ÌÌÌÿÀ€ÌÿÌÿPïØ€ÿÌÿÐïx€ÿ3ÌÿÒï�€ÿfÌÿÕï¨€ÿ™ÌÿÜïÀ€ÿÌÌÿïØ€ÿÿÌÿ(ïØ€ÿ€ÿÿÿÈïx€ÿ€™ÿÿ¸ïx€™3ÿÿ´ï�€™fÿÿ­ï¨€™™ÿÿ ïÀ€™ÌÿÿŒïÀ€™ÿÿÿxïÀ€ÌÿÿÀïx€Ì3ÿÿ¾ï�€Ìfÿÿ»ï¨€Ì™ÿÿ´ïÀ€ÌÌÿÿ ïØ€ÌÿÿÿxïØ€ÿÿÿÈïx€ÿ3ÿÿÈï�€ÿfÿÿÈï¨€ÿ™ÿÿÈïÀ€ÿÌÿÿÈïØ€ÿÿÿÿð€ÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿfýÿ`ÿÿÿÿzÿÿÿÿ€™fÿªÿÌÿÿÿÿÿÿ€ÿÿÿ*ÿÿÿ]ÿÿÿÿÿªÿÿÔÿÿÿÿÿÿÿþÿ"PublishQTProperties::QTSndSettingsÿÿCQTAudioSettingsÿÿÿþÿhÿþÿÿþÿ

ÿÿÿÿÿþÿÿþÿÿÿÿÿ€ÿfýÿ`ÿÿÿÿzÿÿÿÿ€™fÿªÿÌÿÿÿÿÿÿ€ÿÿÿ*ÿÿÿ]ÿÿÿÿÿªÿÿÔÿÿÿÿÿÿÿþÿ"PublishQTProperties::QTSndSettingsÿÿCQTAudioSettingsÿÿÿþÿhÿþÿÿþÿ

ÿÿÿÿÿþÿÿþÿ
__CPAN_DIR__ src/lang
__CPAN_FILE__ src/lang/array.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.array");

dojo.require("dojo.lang.common");

// FIXME: Is this worthless since you can do: if(name in obj)
// is this the right place for this?
dojo.lang.has = function(/*Object*/obj, /*String*/name){
	try{
		return typeof obj[name] != "undefined";
	}catch(e){ return false; }
}

dojo.lang.isEmpty = function(/*Object*/obj){
	if(dojo.lang.isObject(obj)){
		var tmp = {};
		var count = 0;
		for(var x in obj){
			if(obj[x] && (!tmp[x])){
				count++;
				break;
			} 
		}
		return count == 0;
	}else if(dojo.lang.isArrayLike(obj) || dojo.lang.isString(obj)){
		return obj.length == 0;
	}
}

dojo.lang.map = function(/*Array*/arr, /*Object|Function*/obj, /*Function?*/unary_func){
	var isString = dojo.lang.isString(arr);
	if(isString){
		// arr: String
		arr = arr.split("");
	}
	if(dojo.lang.isFunction(obj)&&(!unary_func)){
		unary_func = obj;
		obj = dj_global;
	}else if(dojo.lang.isFunction(obj) && unary_func){
		// ff 1.5 compat
		var tmpObj = obj;
		obj = unary_func;
		unary_func = tmpObj;
	}
	if(Array.map){
	 	var outArr = Array.map(arr, unary_func, obj);
	}else{
		var outArr = [];
		for(var i=0;i<arr.length;++i){
			outArr.push(unary_func.call(obj, arr[i]));
		}
	}
	if(isString) {
		return outArr.join(""); // String
	} else {
		return outArr; // Array
	}
}

dojo.lang.reduce = function(/*Array*/arr, initialValue, /*Object|null*/obj, /*Function*/binary_func){
	var reducedValue = initialValue;
	var ob = obj ? obj : dj_global;
	dojo.lang.map(arr, 
		function(val){
			reducedValue = binary_func.call(ob, reducedValue, val);
		}
	);
	return reducedValue;
}

// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
dojo.lang.forEach = function(/*Array*/anArray, /*Function*/callback, /*Object?*/thisObject){
	if(dojo.lang.isString(anArray)){
		// anArray: String
		anArray = anArray.split(""); 
	}
	if(Array.forEach){
		Array.forEach(anArray, callback, thisObject);
	}else{
		// FIXME: there are several ways of handilng thisObject. Is dj_global always the default context?
		if(!thisObject){
			thisObject=dj_global;
		}
		for(var i=0,l=anArray.length; i<l; i++){ 
			callback.call(thisObject, anArray[i], i, anArray);
		}
	}
}

dojo.lang._everyOrSome = function(/*Boolean*/every, /*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
	if(dojo.lang.isString(arr)){ 
		//arr: String
		arr = arr.split(""); 
	}
	if(Array.every){
		return Array[ every ? "every" : "some" ](arr, callback, thisObject);
	}else{
		if(!thisObject){
			thisObject = dj_global;
		}
		for(var i=0,l=arr.length; i<l; i++){
			var result = callback.call(thisObject, arr[i], i, arr);
			if(every && !result){
				return false; // Boolean
			}else if((!every)&&(result)){
				return true; // Boolean
			}
		}
		return Boolean(every); // Boolean
	}
}

dojo.lang.every = function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
	return this._everyOrSome(true, arr, callback, thisObject); // Boolean
}

dojo.lang.some = function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
	return this._everyOrSome(false, arr, callback, thisObject); // Boolean
}

dojo.lang.filter = function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
	var isString = dojo.lang.isString(arr);
	if(isString){ /*arr: String*/arr = arr.split(""); }
	var outArr;
	if(Array.filter){
		outArr = Array.filter(arr, callback, thisObject);
	} else {
		if(!thisObject){
			if(arguments.length >= 3){ dojo.raise("thisObject doesn't exist!"); }
			thisObject = dj_global;
		}

		outArr = [];
		for(var i = 0; i < arr.length; i++){
			if(callback.call(thisObject, arr[i], i, arr)){
				outArr.push(arr[i]);
			}
		}
	}
	if(isString){
		return outArr.join(""); // String
	} else {
		return outArr; // Array
	}
}

dojo.lang.unnest = function(/* ... */){
	// summary:
	//	Creates a 1-D array out of all the arguments passed,
	//	unravelling any array-like objects in the process
	//
	// usage:
	//	unnest(1, 2, 3) ==> [1, 2, 3]
	//	unnest(1, [2, [3], [[[4]]]]) ==> [1, 2, 3, 4]

	var out = [];
	for(var i = 0; i < arguments.length; i++){
		if(dojo.lang.isArrayLike(arguments[i])){
			var add = dojo.lang.unnest.apply(this, arguments[i]);
			out = out.concat(add);
		}else{
			out.push(arguments[i]);
		}
	}
	return out; // Array
}

dojo.lang.toArray = function(/*Object*/arrayLike, /*Number*/startOffset){
	// summary:
	//	Converts an array-like object (i.e. arguments, DOMCollection)
	//	to an array
	var array = [];
	for(var i = startOffset||0; i < arrayLike.length; i++){
		array.push(arrayLike[i]);
	}
	return array; // Array
}

__CPAN_FILE__ src/lang/assert.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.assert");

dojo.require("dojo.lang.common");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.type");

dojo.lang.assert = function(/* boolean */ booleanValue, /* string? */ message){
	/* summary: 
	 *   Throws an exception if the assertion fails.
	 * description: 
	 *   If the asserted condition is true, this method does nothing. If the
	 *   condition is false, we throw an error with a error message. 
	 * booleanValue: Must be true for the assertion to succeed.
	 * message: A string describing the assertion.
	 */

	 // throws: Throws an Error if 'booleanValue' is false.
	 if(!booleanValue){
		var errorMessage = "An assert statement failed.\n" +
			"The method dojo.lang.assert() was called with a 'false' value.\n";
		if(message){
			errorMessage += "Here's the assert message:\n" + message + "\n";
		}
		// Use throw instead of dojo.raise, until bug #264 is fixed:
		// dojo.raise(errorMessage);
		throw new Error(errorMessage);
	}
}

dojo.lang.assertType = function(/* anything */ value, /* misc. */ type, /* object? */ keywordParameters){
	/* summary: 
	 *   Throws an exception if 'value' is not of type 'type'
	 * description: 
	 *   Given a value and a data type, this method checks the type of the value
	 *   to make sure it matches the data type, and throws an exception if there
	 *   is a mismatch.
	 * value: Any literal value or object instance.
	 * type: A class of object, or a literal type, or the string name of a type, or an array with a list of types.
	 * keywordParameters: {optional: boolean}
	 */
	 
	/* examples: 
	 *   dojo.lang.assertType("foo", String);
	 *   dojo.lang.assertType(12345, Number);
	 *   dojo.lang.assertType(false, Boolean);
	 *   dojo.lang.assertType([6, 8], Array);
	 *   dojo.lang.assertType(dojo.lang.assertType, Function);
	 *   dojo.lang.assertType({foo: "bar"}, Object);
	 *   dojo.lang.assertType(new Date(), Date);
	 *   dojo.lang.assertType(null, Array, {optional: true});
	 * throws: Throws an Error if 'value' is not of type 'type'.
	 */
	if (dojo.lang.isString(keywordParameters)) {
		dojo.deprecated('dojo.lang.assertType(value, type, "message")', 'use dojo.lang.assertType(value, type) instead', "0.5");
	}
	if(!dojo.lang.isOfType(value, type, keywordParameters)){
		if(!dojo.lang.assertType._errorMessage){
			dojo.lang.assertType._errorMessage = "Type mismatch: dojo.lang.assertType() failed.";
		}
		dojo.lang.assert(false, dojo.lang.assertType._errorMessage);
	}
}

dojo.lang.assertValidKeywords = function(/* object */ object, /* array */ expectedProperties, /* string? */ message){
	/* summary: 
	 *   Throws an exception 'object' has any properties other than the 'expectedProperties'.
	 * description: 
	 *   Given an anonymous object and a list of expected property names, this
	 *   method check to make sure the object does not have any properties
	 *   that aren't on the list of expected properties, and throws an Error
	 *   if there are unexpected properties. This is useful for doing error
	 *   checking on keyword arguments, to make sure there aren't typos.
	 * object: An anonymous object.
	 * expectedProperties: An array of strings (or an object with all the expected properties).
	 * message: A message describing the assertion.
	 */
	 
	/* examples: 
	 *   dojo.lang.assertValidKeywords({a: 1, b: 2}, ["a", "b"]);
	 *   dojo.lang.assertValidKeywords({a: 1, b: 2}, ["a", "b", "c"]);
	 *   dojo.lang.assertValidKeywords({foo: "iggy"}, ["foo"]);
	 *   dojo.lang.assertValidKeywords({foo: "iggy"}, ["foo", "bar"]);
	 *   dojo.lang.assertValidKeywords({foo: "iggy"}, {foo: null, bar: null});
	 * throws: Throws an Error if 'object' has unexpected properties.
	 */
	var key;
	if(!message){
		if(!dojo.lang.assertValidKeywords._errorMessage){
			dojo.lang.assertValidKeywords._errorMessage = "In dojo.lang.assertValidKeywords(), found invalid keyword:";
		}
		message = dojo.lang.assertValidKeywords._errorMessage;
	}
	if(dojo.lang.isArray(expectedProperties)){
		for(key in object){
			if(!dojo.lang.inArray(expectedProperties, key)){
				dojo.lang.assert(false, message + " " + key);
			}
		}
	}else{
		for(key in object){
			if(!(key in expectedProperties)){
				dojo.lang.assert(false, message + " " + key);
			}
		}
	}
}

__CPAN_FILE__ src/lang/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.common");

dojo.lang.inherits = function(/*Function*/ subclass, /*Function*/ superclass){
	// summary: Set up inheritance between two classes.
	if(typeof superclass != 'function'){ 
		dojo.raise("dojo.inherits: superclass argument ["+superclass+"] must be a function (subclass: ["+subclass+"']");
	}
	subclass.prototype = new superclass();
	subclass.prototype.constructor = subclass;
	subclass.superclass = superclass.prototype;
	// DEPRECATED: super is a reserved word, use 'superclass'
	subclass['super'] = superclass.prototype;
}

dojo.lang._mixin = function(/*Object*/ obj, /*Object*/ props){
	// summary:	Adds all properties and methods of props to obj.
	var tobj = {};
	for(var x in props){
		// the "tobj" condition avoid copying properties in "props"
		// inherited from Object.prototype.  For example, if obj has a custom
		// toString() method, don't overwrite it with the toString() method
		// that props inherited from Object.protoype
		if((typeof tobj[x] == "undefined") || (tobj[x] != props[x])){
			obj[x] = props[x];
		}
	}
	// IE doesn't recognize custom toStrings in for..in
	if(dojo.render.html.ie 
		&& (typeof(props["toString"]) == "function")
		&& (props["toString"] != obj["toString"])
		&& (props["toString"] != tobj["toString"]))
	{
		obj.toString = props.toString;
	}
	return obj; // Object
}

dojo.lang.mixin = function(/*Object*/ obj, /*Object...*/props){
	// summary:	Adds all properties and methods of props to obj.
	for(var i=1, l=arguments.length; i<l; i++){
		dojo.lang._mixin(obj, arguments[i]);
	}
	return obj; // Object
}

dojo.lang.extend = function(/*Object*/ constructor, /*Object...*/ props){
	// summary:	Adds all properties and methods of props to constructor's prototype,
	//			making them available to all instances created with constructor.
	for(var i=1, l=arguments.length; i<l; i++){
		dojo.lang._mixin(constructor.prototype, arguments[i]);
	}
	return constructor; // Object
}

// Promote to dojo module
dojo.inherits = dojo.lang.inherits;
//dojo.lang._mixin = dojo.lang._mixin;
dojo.mixin = dojo.lang.mixin;
dojo.extend = dojo.lang.extend;

dojo.lang.find = function(	/*Array*/		array, 
							/*Object*/		value,
							/*Boolean?*/	identity,
							/*Boolean?*/	findLast){
	// summary:	Return the index of value in array, returning -1 if not found.
	// identity: If true, matches with identity comparison (===).  
	//					 If false, uses normal comparison (==).
	// findLast: If true, returns index of last instance of value.
	
	// examples:
	//  find(array, value[, identity [findLast]]) // recommended
 	//  find(value, array[, identity [findLast]]) // deprecated
							
	// support both (array, value) and (value, array)
	if(!dojo.lang.isArrayLike(array) && dojo.lang.isArrayLike(value)) {
		dojo.deprecated('dojo.lang.find(value, array)', 'use dojo.lang.find(array, value) instead', "0.5");
		var temp = array;
		array = value;
		value = temp;
	}
	var isString = dojo.lang.isString(array);
	if(isString) { array = array.split(""); }

	if(findLast) {
		var step = -1;
		var i = array.length - 1;
		var end = -1;
	} else {
		var step = 1;
		var i = 0;
		var end = array.length;
	}
	if(identity){
		while(i != end) {
			if(array[i] === value){ return i; }
			i += step;
		}
	}else{
		while(i != end) {
			if(array[i] == value){ return i; }
			i += step;
		}
	}
	return -1;	// number
}

dojo.lang.indexOf = dojo.lang.find;

dojo.lang.findLast = function(/*Array*/ array, /*Object*/ value, /*boolean?*/ identity){
	// summary:	Return index of last occurance of value in array, returning -1 if not found.
	// identity: If true, matches with identity comparison (===). If false, uses normal comparison (==).
	return dojo.lang.find(array, value, identity, true); // number
}

dojo.lang.lastIndexOf = dojo.lang.findLast;

dojo.lang.inArray = function(array /*Array*/, value /*Object*/){
	// summary:	Return true if value is present in array.
	return dojo.lang.find(array, value) > -1; // boolean
}

/**
 * Partial implmentation of is* functions from
 * http://www.crockford.com/javascript/recommend.html
 * NOTE: some of these may not be the best thing to use in all situations
 * as they aren't part of core JS and therefore can't work in every case.
 * See WARNING messages inline for tips.
 *
 * The following is* functions are fairly "safe"
 */

dojo.lang.isObject = function(/*anything*/ it){
	// summary:	Return true if it is an Object, Array or Function.
	if(typeof it == "undefined"){ return false; }
	return (typeof it == "object" || it === null || dojo.lang.isArray(it) || dojo.lang.isFunction(it)); // Boolean
}

dojo.lang.isArray = function(/*anything*/ it){
	// summary:	Return true if it is an Array.
	return (it && it instanceof Array || typeof it == "array"); // Boolean
}

dojo.lang.isArrayLike = function(/*anything*/ it){
	// summary:	Return true if it can be used as an array (i.e. is an object with an integer length property).
	if((!it)||(dojo.lang.isUndefined(it))){ return false; }
	if(dojo.lang.isString(it)){ return false; }
	if(dojo.lang.isFunction(it)){ return false; } // keeps out built-in constructors (Number, String, ...) which have length properties
	if(dojo.lang.isArray(it)){ return true; }
	// form node itself is ArrayLike, but not always iterable. Use form.elements instead.
	if((it.tagName)&&(it.tagName.toLowerCase()=='form')){ return false; }
	if(dojo.lang.isNumber(it.length) && isFinite(it.length)){ return true; }
	return false; // Boolean
}

dojo.lang.isFunction = function(/*anything*/ it){
	// summary:	Return true if it is a Function.
	if(!it){ return false; }
	// webkit treats NodeList as a function, which is bad
	if((typeof(it) == "function") && (it == "[object NodeList]")) { return false; }
	return (it instanceof Function || typeof it == "function"); // Boolean
}

dojo.lang.isString = function(/*anything*/ it){
	// summary:	Return true if it is a String.
	return (typeof it == "string" || it instanceof String);
}

dojo.lang.isAlien = function(/*anything*/ it){
	// summary:	Return true if it is not a built-in function.
	if(!it){ return false; }
	return !dojo.lang.isFunction() && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
}

dojo.lang.isBoolean = function(/*anything*/ it){
	// summary:	Return true if it is a Boolean.
	return (it instanceof Boolean || typeof it == "boolean"); // Boolean
}

/**
 * The following is***() functions are somewhat "unsafe". Fortunately,
 * there are workarounds the the language provides and are mentioned
 * in the WARNING messages.
 *
 */
dojo.lang.isNumber = function(/*anything*/ it){
	// summary:	Return true if it is a number.
	// description: 
	//		WARNING - In most cases, isNaN(it) is sufficient to determine whether or not
	// 		something is a number or can be used as such. For example, a number or string
	// 		can be used interchangably when accessing array items (array["1"] is the same as
	// 		array[1]) and isNaN will return false for both values ("1" and 1). However,
	// 		isNumber("1")  will return false, which is generally not too useful.
	// 		Also, isNumber(NaN) returns true, again, this isn't generally useful, but there
	// 		are corner cases (like when you want to make sure that two things are really
	// 		the same type of thing). That is really where isNumber "shines".
	//
	// Recommendation - Use isNaN(it) when possible
	
	return (it instanceof Number || typeof it == "number"); // Boolean
}

/*
 * FIXME: Should isUndefined go away since it is error prone?
 */
dojo.lang.isUndefined = function(/*anything*/ it){
	// summary: Return true if it is not defined.
	// description: 
	//		WARNING - In some cases, isUndefined will not behave as you
	// 		might expect. If you do isUndefined(foo) and there is no earlier
	// 		reference to foo, an error will be thrown before isUndefined is
	// 		called. It behaves correctly if you scope yor object first, i.e.
	// 		isUndefined(foo.bar) where foo is an object and bar isn't a
	// 		property of the object.
	//
	// Recommendation - Use typeof foo == "undefined" when possible

	return ((typeof(it) == "undefined")&&(it == undefined)); // Boolean
}

// end Crockford functions

__CPAN_FILE__ src/lang/func.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.func");

dojo.require("dojo.lang.common");

/**
 * Runs a function in a given scope (thisObject), can
 * also be used to preserve scope.
 *
 * hitch(foo, "bar"); // runs foo.bar() in the scope of foo
 * hitch(foo, myFunction); // runs myFunction in the scope of foo
 */
dojo.lang.hitch = function(thisObject, method){
	var fcn = (dojo.lang.isString(method) ? thisObject[method] : method) || function(){};

	return function() {
		return fcn.apply(thisObject, arguments);
	};
}

dojo.lang.anonCtr = 0;
dojo.lang.anon = {};
dojo.lang.nameAnonFunc = function(anonFuncPtr, namespaceObj, searchForNames){
	var nso = (namespaceObj || dojo.lang.anon);
	if( (searchForNames) ||
		((dj_global["djConfig"])&&(djConfig["slowAnonFuncLookups"] == true)) ){
		for(var x in nso){
			try{
				if(nso[x] === anonFuncPtr){
					return x;
				}
			}catch(e){} // window.external fails in IE embedded in Eclipse (Eclipse bug #151165)
		}
	}
	var ret = "__"+dojo.lang.anonCtr++;
	while(typeof nso[ret] != "undefined"){
		ret = "__"+dojo.lang.anonCtr++;
	}
	nso[ret] = anonFuncPtr;
	return ret;
}

dojo.lang.forward = function(funcName){
	// Returns a function that forwards a method call to this.func(...)
	return function(){
		return this[funcName].apply(this, arguments);
	};
}

dojo.lang.curry = function(ns, func /* args ... */){
	var outerArgs = [];
	ns = ns||dj_global;
	if(dojo.lang.isString(func)){
		func = ns[func];
	}
	for(var x=2; x<arguments.length; x++){
		outerArgs.push(arguments[x]);
	}
	// since the event system replaces the original function with a new
	// join-point runner with an arity of 0, we check to see if it's left us
	// any clues about the original arity in lieu of the function's actual
	// length property
	var ecount = (func["__preJoinArity"]||func.length) - outerArgs.length;
	// borrowed from svend tofte
	function gather(nextArgs, innerArgs, expected){
		var texpected = expected;
		var totalArgs = innerArgs.slice(0); // copy
		for(var x=0; x<nextArgs.length; x++){
			totalArgs.push(nextArgs[x]);
		}
		// check the list of provided nextArgs to see if it, plus the
		// number of innerArgs already supplied, meets the total
		// expected.
		expected = expected-nextArgs.length;
		if(expected<=0){
			var res = func.apply(ns, totalArgs);
			expected = texpected;
			return res;
		}else{
			return function(){
				return gather(arguments,// check to see if we've been run
										// with enough args
							totalArgs,	// a copy
							expected);	// how many more do we need to run?;
			};
		}
	}
	return gather([], outerArgs, ecount);
}

dojo.lang.curryArguments = function(ns, func, args, offset){
	var targs = [];
	var x = offset||0;
	for(x=offset; x<args.length; x++){
		targs.push(args[x]); // ensure that it's an arr
	}
	return dojo.lang.curry.apply(dojo.lang, [ns, func].concat(targs));
}

dojo.lang.tryThese = function(){
	for(var x=0; x<arguments.length; x++){
		try{
			if(typeof arguments[x] == "function"){
				var ret = (arguments[x]());
				if(ret){
					return ret;
				}
			}
		}catch(e){
			dojo.debug(e);
		}
	}
}

dojo.lang.delayThese = function(farr, cb, delay, onend){
	/**
	 * alternate: (array funcArray, function callback, function onend)
	 * alternate: (array funcArray, function callback)
	 * alternate: (array funcArray)
	 */
	if(!farr.length){ 
		if(typeof onend == "function"){
			onend();
		}
		return;
	}
	if((typeof delay == "undefined")&&(typeof cb == "number")){
		delay = cb;
		cb = function(){};
	}else if(!cb){
		cb = function(){};
		if(!delay){ delay = 0; }
	}
	setTimeout(function(){
		(farr.shift())();
		cb();
		dojo.lang.delayThese(farr, cb, delay, onend);
	}, delay);
}

__CPAN_FILE__ src/lang/type.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.type");
dojo.require("dojo.lang.common");

dojo.lang.whatAmI = function(value) {
	dojo.deprecated("dojo.lang.whatAmI", "use dojo.lang.getType instead", "0.5");
	return dojo.lang.getType(value);
}
dojo.lang.whatAmI.custom = {};

dojo.lang.getType = function(/* anything */ value){
	/* summary:
	 *	 Attempts to determine what type value is.
	 * value: Any literal value or object instance.
	 */
	try {
		if(dojo.lang.isArray(value)) { 
			return "array";	//	string 
		}
		if(dojo.lang.isFunction(value)) { 
			return "function";	//	string 
		}
		if(dojo.lang.isString(value)) { 
			return "string";	//	string 
		}
		if(dojo.lang.isNumber(value)) { 
			return "number";	//	string 
		}
		if(dojo.lang.isBoolean(value)) { 
			return "boolean";	//	string 
		}
		if(dojo.lang.isAlien(value)) { 
			return "alien";	//	string 
		}
		if(dojo.lang.isUndefined(value)) { 
			return "undefined";	//	string 
		}
		// FIXME: should this go first?
		for(var name in dojo.lang.whatAmI.custom) {
			if(dojo.lang.whatAmI.custom[name](value)) {
				return name;	//	string
			}
		}
		if(dojo.lang.isObject(value)) { 
			return "object";	//	string 
		}
	} catch(e) {}
	return "unknown";	//	string
}

dojo.lang.isNumeric = function(/* anything */ value){
	/* summary:
	 *   Returns true if value can be interpreted as a number
	 * value: Any literal value or object instance.
	 */
	 
	/* examples: 
	 *   dojo.lang.isNumeric(3);                 // returns true
	 *   dojo.lang.isNumeric("3");               // returns true
	 *   dojo.lang.isNumeric(new Number(3));     // returns true
	 *   dojo.lang.isNumeric(new String("3"));   // returns true
	 *
	 *   dojo.lang.isNumeric(3/0);               // returns false
	 *   dojo.lang.isNumeric("foo");             // returns false
	 *   dojo.lang.isNumeric(new Number("foo")); // returns false
	 *   dojo.lang.isNumeric(false);             // returns false
	 *   dojo.lang.isNumeric(true);              // returns false
	 */
	return (!isNaN(value) 
		&& isFinite(value) 
		&& (value != null) 
		&& !dojo.lang.isBoolean(value) 
		&& !dojo.lang.isArray(value) 
		&& !/^\s*$/.test(value)
	);	//	boolean
}

dojo.lang.isBuiltIn = function(/* anything */ value){
	/* summary:
	 *   Returns true if value is of a type provided by core JavaScript
	 * description: 
	 *   Returns true for any literal, and for any object that is an 
	 *   instance of a built-in type like String, Number, Boolean, 
	 *   Array, Function, or Error.
	 * value: Any literal value or object instance.
	 */
	return (dojo.lang.isArray(value)
		|| dojo.lang.isFunction(value)	
		|| dojo.lang.isString(value)
		|| dojo.lang.isNumber(value)
		|| dojo.lang.isBoolean(value)
		|| (value == null)
		|| (value instanceof Error)
		|| (typeof value == "error") 
	);	//	boolean
}

dojo.lang.isPureObject = function(/* anything */ value){
	/* summary:
	 *   Returns true for any value where the value of value.constructor == Object
	 * description: 
	 *   Returns true for any literal, and for any object that is an 
	 *   instance of a built-in type like String, Number, Boolean, 
	 *   Array, Function, or Error.
	 * value: Any literal value or object instance.
	 */
	
	/* examples: 
	 *   dojo.lang.isPureObject(new Object()); // returns true
	 *   dojo.lang.isPureObject({a: 1, b: 2}); // returns true
	 * 
	 *   dojo.lang.isPureObject(new Date());   // returns false
	 *   dojo.lang.isPureObject([11, 2, 3]);   // returns false
	 */
	return ((value != null) 
		&& dojo.lang.isObject(value) 
		&& value.constructor == Object
	);	//	boolean
}

dojo.lang.isOfType = function(/* anything */ value, /* function */ type, /* object? */ keywordParameters) {
	/* summary:
	 *	 Returns true if 'value' is of type 'type'
	 * description: 
	 *	 Given a value and a datatype, this method returns true if the
	 *	 type of the value matches the datatype. The datatype parameter
	 *	 can be an array of datatypes, in which case the method returns
	 *	 true if the type of the value matches any of the datatypes.
	 * value: Any literal value or object instance.
	 * type: A class of object, or a literal type, or the string name of a type, or an array with a list of types.
	 * keywordParameters: {optional: boolean}
	 */
	 
	/* examples: 
	 *   dojo.lang.isOfType("foo", String);                // returns true
	 *   dojo.lang.isOfType(12345, Number);                // returns true
	 *   dojo.lang.isOfType(false, Boolean);               // returns true
	 *   dojo.lang.isOfType([6, 8], Array);                // returns true
	 *   dojo.lang.isOfType(dojo.lang.isOfType, Function); // returns true
	 *   dojo.lang.isOfType({foo: "bar"}, Object);         // returns true
	 *   dojo.lang.isOfType(new Date(), Date);             // returns true
	 *
	 *   dojo.lang.isOfType("foo", "string");                // returns true
	 *   dojo.lang.isOfType(12345, "number");                // returns true
	 *   dojo.lang.isOfType(false, "boolean");               // returns true
	 *   dojo.lang.isOfType([6, 8], "array");                // returns true
	 *   dojo.lang.isOfType(dojo.lang.isOfType, "function"); // returns true
	 *   dojo.lang.isOfType({foo: "bar"}, "object");         // returns true
	 *   dojo.lang.isOfType(xxxxx, "undefined");             // returns true
	 *   dojo.lang.isOfType(null, "null");                   // returns true
	 *
	 *   dojo.lang.isOfType("foo", [Number, String, Boolean]); // returns true
	 *   dojo.lang.isOfType(12345, [Number, String, Boolean]); // returns true
	 *   dojo.lang.isOfType(false, [Number, String, Boolean]); // returns true
	 *
	 *   dojo.lang.isOfType(null, Date, {optional: true} );    // returns true	// description: 
	 */
	var optional = false;
	if (keywordParameters) {
		optional = keywordParameters["optional"];
	}
	if (optional && ((value === null) || dojo.lang.isUndefined(value))) {
		return true;	//	boolean
	}
	if(dojo.lang.isArray(type)){
		var arrayOfTypes = type;
		for(var i in arrayOfTypes){
			var aType = arrayOfTypes[i];
			if(dojo.lang.isOfType(value, aType)) {
				return true; 	//	boolean
			}
		}
		return false;	//	boolean
	}else{
		if(dojo.lang.isString(type)){
			type = type.toLowerCase();
		}
		switch (type) {
			case Array:
			case "array":
				return dojo.lang.isArray(value);	//	boolean
			case Function:
			case "function":
				return dojo.lang.isFunction(value);	//	boolean
			case String:
			case "string":
				return dojo.lang.isString(value);	//	boolean
			case Number:
			case "number":
				return dojo.lang.isNumber(value);	//	boolean
			case "numeric":
				return dojo.lang.isNumeric(value);	//	boolean
			case Boolean:
			case "boolean":
				return dojo.lang.isBoolean(value);	//	boolean
			case Object:
			case "object":
				return dojo.lang.isObject(value);	//	boolean
			case "pureobject":
				return dojo.lang.isPureObject(value);	//	boolean
			case "builtin":
				return dojo.lang.isBuiltIn(value);	//	boolean
			case "alien":
				return dojo.lang.isAlien(value);	//	boolean
			case "undefined":
				return dojo.lang.isUndefined(value);	//	boolean
			case null:
			case "null":
				return (value === null);	//	boolean
			case "optional":
				dojo.deprecated('dojo.lang.isOfType(value, [type, "optional"])', 'use dojo.lang.isOfType(value, type, {optional: true} ) instead', "0.5");
				return ((value === null) || dojo.lang.isUndefined(value));	//	boolean
			default:
				if (dojo.lang.isFunction(type)) {
					return (value instanceof type);	//	boolean
				} else {
					dojo.raise("dojo.lang.isOfType() was passed an invalid type");
				}
		}
	}
	dojo.raise("If we get here, it means a bug was introduced above.");
}

dojo.lang.getObject=function(/* String */ str){
	// summary:
	//   Will return an object, if it exists, based on the name in the passed string.
	var parts=str.split("."), i=0, obj=dj_global; 
	do{ 
		obj=obj[parts[i++]]; 
	}while(i<parts.length&&obj); 
	return (obj!=dj_global)?obj:null;	//	Object
}

dojo.lang.doesObjectExist=function(/* String */ str){
	// summary:
	//   Check to see if object [str] exists, based on the passed string.
	var parts=str.split("."), i=0, obj=dj_global; 
	do{ 
		obj=obj[parts[i++]]; 
	}while(i<parts.length&&obj); 
	return (obj&&obj!=dj_global);	//	boolean
}

__CPAN_FILE__ src/lang/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.lang.common",
		"dojo.lang.assert",
		"dojo.lang.array",
		"dojo.lang.type",
		"dojo.lang.func",
		"dojo.lang.extras",
		"dojo.lang.repr",
		"dojo.lang.declare"
	]
});
dojo.provide("dojo.lang.*");

__CPAN_FILE__ src/lang/repr.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.repr");

dojo.require("dojo.lang.common");
dojo.require("dojo.AdapterRegistry");
dojo.require("dojo.string.extras");

dojo.lang.reprRegistry = new dojo.AdapterRegistry();
dojo.lang.registerRepr = function(/*String*/name, /*Function*/check, /*Function*/wrap, /*Boolean?*/override){
	// summary:
	//	Register a repr function.  repr functions should take
	//	one argument and return a string representation of it
	//	suitable for developers, primarily used when debugging.
	//
	//	If override is given, it is used as the highest priority
	//	repr, otherwise it will be used as the lowest.

	dojo.lang.reprRegistry.register(name, check, wrap, override);
};

dojo.lang.repr = function(/*Object*/obj){
	// summary: Return a "programmer representation" for an object
	// description: returns a string representation of an object suitable for developers, primarily used when debugging

	if(typeof(obj) == "undefined"){
		// obj: undefined
		return "undefined"; // String
	}else if(obj === null){
		// obj: null
		return "null"; // String
	}

	try{
		if(typeof(obj["__repr__"]) == 'function'){
			return obj["__repr__"]();
		}else if((typeof(obj["repr"]) == 'function')&&(obj.repr != arguments.callee)){
			return obj["repr"]();
		}
		return dojo.lang.reprRegistry.match(obj);
	}catch(e){
		if(typeof(obj.NAME) == 'string' && (
				obj.toString == Function.prototype.toString ||
				obj.toString == Object.prototype.toString
			)){
			return obj.NAME; // String
		}
	}

	if(typeof(obj) == "function"){
		// obj: Function
		obj = (obj + "").replace(/^\s+/, "");
		var idx = obj.indexOf("{");
		if(idx != -1){
			obj = obj.substr(0, idx) + "{...}";
		}
	}
	return obj + ""; // String
}

dojo.lang.reprArrayLike = function(/*Array*/arr){
	// summary: Maps each element of arr to dojo.lang.repr and provides output in an array-like format
	// description: returns an array-like string representation of the provided array suitable for developers, primarily used when debugging
	try{
		var na = dojo.lang.map(arr, dojo.lang.repr);
		return "[" + na.join(", ") + "]"; // String
	}catch(e){ }
};

(function(){
	var m = dojo.lang;
	m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike);
	m.registerRepr("string", m.isString, m.reprString);
	m.registerRepr("numbers", m.isNumber, m.reprNumber);
	m.registerRepr("boolean", m.isBoolean, m.reprNumber);
	// m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber);
})();

__CPAN_FILE__ src/lang/extras.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.extras");

dojo.require("dojo.lang.common");

dojo.lang.setTimeout = function(/*Function*/func, /*int*/delay /*, ...*/){
	// summary:
	//	Sets a timeout in milliseconds to execute a function in a given context
	//	with optional arguments.
	//
	// usage:
	//	setTimeout (Object context, function func, number delay[, arg1[, ...]]);
	//	setTimeout (function func, number delay[, arg1[, ...]]);

	var context = window, argsStart = 2;
	if(!dojo.lang.isFunction(func)){
		context = func;
		func = delay;
		delay = arguments[2];
		argsStart++;
	}

	if(dojo.lang.isString(func)){
		func = context[func];
	}
	
	var args = [];
	for (var i = argsStart; i < arguments.length; i++){
		args.push(arguments[i]);
	}
	return dojo.global().setTimeout(function () { func.apply(context, args); }, delay); // int
}

dojo.lang.clearTimeout = function(/*int*/timer){
	// summary: clears timer by number from the execution queue
	dojo.global().clearTimeout(timer);
}

dojo.lang.getNameInObj = function(/*Object*/ns, /*unknown*/item){
	// summary: looks for a value in the object ns with a value matching item and returns the property name
	// ns: if null, dj_global is used
	// item: value to match
	if(!ns){ ns = dj_global; }

	for(var x in ns){
		if(ns[x] === item){
			return new String(x); // String
		}
	}
	return null; // null
}

dojo.lang.shallowCopy = function(/*Object*/obj, /*Boolean?*/deep){
	// summary: copies object obj one level deep, or full depth if deep is true
	var i, ret;	

	if(obj === null){ /*obj: null*/ return null; } // null
	
	if(dojo.lang.isObject(obj)){
		// obj: Object	
		ret = new obj.constructor();
		for(i in obj){
			if(dojo.lang.isUndefined(ret[i])){
				ret[i] = deep ? dojo.lang.shallowCopy(obj[i], deep) : obj[i];
			}
		}
	} else if(dojo.lang.isArray(obj)){
		// obj: Array
		ret = [];
		for(i=0; i<obj.length; i++){
			ret[i] = deep ? dojo.lang.shallowCopy(obj[i], deep) : obj[i];
		}
	} else {
		// obj: unknown
		ret = obj;
	}

	return ret; // unknown
}

dojo.lang.firstValued = function(/* ... */){
	// summary: Return the first argument that isn't undefined

	for(var i = 0; i < arguments.length; i++){
		if(typeof arguments[i] != "undefined"){
			return arguments[i]; // unknown
		}
	}
	return undefined; // undefined
}

dojo.lang.getObjPathValue = function(/*String*/objpath, /*Object?*/context, /*Boolean?*/create){
	// summary:
	//	Gets a value from a reference specified as a string descriptor,
	//	(e.g. "A.B") in the given context.
	//
	// context: if not specified, dj_global is used
	// create: if true, undefined objects in the path are created.

	with(dojo.parseObjPath(objpath, context, create)){
		return dojo.evalProp(prop, obj, create); // unknown
	}
}

dojo.lang.setObjPathValue = function(/*String*/objpath, /*unknown*/value, /*Object?*/context, /*Boolean?*/create){
	// summary:
	//	Sets a value on a reference specified as a string descriptor. 
	//	(e.g. "A.B") in the given context.
	//
	//	context: if not specified, dj_global is used
	//	create: if true, undefined objects in the path are created.

	if(arguments.length < 4){
		create = true;
	}
	with(dojo.parseObjPath(objpath, context, create)){
		if(obj && (create || (prop in obj))){
			obj[prop] = value;
		}
	}
}

__CPAN_FILE__ src/lang/declare.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.declare");

dojo.require("dojo.lang.common");
dojo.require("dojo.lang.extras");

dojo.lang.declare = function(/*String*/ className, /*Function|Array*/ superclass, /*Function?*/ init, /*Object|Array*/ props){
/*
 * summary: Create a feature-rich constructor with a compact notation
 *
 * className: the name of the constructor (loosely, a "class")
 *
 * superclass: may be a Function, or an Array of Functions. 
 *   If "superclass" is an array, the first element is used 
 *   as the prototypical ancestor and any following Functions 
 *   become mixin ancestors.
 *
 * init: an initializer function
 *
 * props: an object (or array of objects) whose properties are copied to the created prototype
 *
 * description: Create a constructor using a compact notation for inheritance and prototype extension.
 *
 *   "superclass" argument may be a Function, or an array of 
 *   Functions. 
 *
 *   If "superclass" is an array, the first element is used 
 *   as the prototypical ancestor and any following Functions 
 *   become mixin ancestors. 
 * 
 *   All "superclass(es)" must be Functions (not mere Objects).
 *
 *   Using mixin ancestors provides a type of multiple
 *   inheritance. Mixin ancestors prototypical 
 *   properties are copied to the subclass, and any 
 *   inializater/constructor is invoked. 
 *
 *   Properties of object "props" are copied to the constructor 
 *   prototype. If "props" is an array, properties of each
 *   object in the array are copied to the constructor prototype.
 *
 *   name of the class ("className" argument) is stored in 
 *   "declaredClass" property
 * 
 *   Initializer functions are called when an object 
 *   is instantiated from this constructor.
 * 
 * Aliased as "dojo.declare"
 *
 * Usage:
 *
 * dojo.declare("my.classes.bar", my.classes.foo,
 *	function() {
 *		// initialization function
 *		this.myComplicatedObject = new ReallyComplicatedObject(); 
 *	},{
 *	someValue: 2,
 *	someMethod: function() { 
 *		doStuff(); 
 *	}
 * });
 *
 */
	if((dojo.lang.isFunction(props))||((!props)&&(!dojo.lang.isFunction(init)))){ 
	 // parameter juggling to support omitting init param (also allows reordering init and props arguments)
		var temp = props;
		props = init;
		init = temp;
	}	
	var mixins = [ ];
	if(dojo.lang.isArray(superclass)){
		mixins = superclass;
		superclass = mixins.shift();
	}
	if(!init){
		init = dojo.evalObjPath(className, false);
		if((init)&&(!dojo.lang.isFunction(init))){ init = null };
	}
	var ctor = dojo.lang.declare._makeConstructor();
	var scp = (superclass ? superclass.prototype : null);
	if(scp){
		scp.prototyping = true;
		ctor.prototype = new superclass();
		scp.prototyping = false; 
	}
	ctor.superclass = scp;
	ctor.mixins = mixins;
	for(var i=0,l=mixins.length; i<l; i++){
		dojo.lang.extend(ctor, mixins[i].prototype);
	}
	ctor.prototype.initializer = null;
	ctor.prototype.declaredClass = className;
	if(dojo.lang.isArray(props)){
		dojo.lang.extend.apply(dojo.lang, [ctor].concat(props));
	}else{
		dojo.lang.extend(ctor, (props)||{});
	}
	dojo.lang.extend(ctor, dojo.lang.declare._common);
	ctor.prototype.constructor = ctor;
	ctor.prototype.initializer = (ctor.prototype.initializer)||(init)||(function(){});
	dojo.lang.setObjPathValue(className, ctor, null, true);
	return ctor; // Function
}

dojo.lang.declare._makeConstructor = function() {
	return function(){ 
		// get the generational context (which object [or prototype] should be constructed)
		var self = this._getPropContext();
		var s = self.constructor.superclass;
		if((s)&&(s.constructor)){
			if(s.constructor==arguments.callee){
				// if this constructor is invoked directly (my.ancestor.call(this))
				this._inherited("constructor", arguments);
			}else{
				this._contextMethod(s, "constructor", arguments);
			}
		}
		var ms = (self.constructor.mixins)||([]);
		for(var i=0, m; (m=ms[i]); i++) {
			(((m.prototype)&&(m.prototype.initializer))||(m)).apply(this, arguments);
		}
		if((!this.prototyping)&&(self.initializer)){
			self.initializer.apply(this, arguments);
		}
	}
}

dojo.lang.declare._common = {
	_getPropContext: function() { return (this.___proto||this); },
	// caches ptype context and calls method on it
	_contextMethod: function(ptype, method, args){
		var result, stack = this.___proto;
		this.___proto = ptype;
		try { result = ptype[method].apply(this,(args||[])); }
		catch(e) { throw e; }	
		finally { this.___proto = stack; }
		return result;
	},
	_inherited: function(prop, args){
		// summary
		//	Searches backward thru prototype chain to find nearest ancestral instance of prop.
		//	Internal use only.
		var p = this._getPropContext();
		do{
			if((!p.constructor)||(!p.constructor.superclass)){return;}
			p = p.constructor.superclass;
		}while(!(prop in p));
		return (dojo.lang.isFunction(p[prop]) ? this._contextMethod(p, prop, args) : p[prop]);
	}
}

dojo.declare = dojo.lang.declare;
__CPAN_DIR__ src/lang/timing
__CPAN_FILE__ src/lang/timing/Timer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.timing.Timer");
dojo.require("dojo.lang.func");

dojo.lang.timing.Timer = function(/*int*/ interval){
	// summary: Timer object executes an "onTick()" method repeatedly at a specified interval. 
	//			repeatedly at a given interval.
	// interval: Interval between function calls, in milliseconds.
	this.timer = null;
	this.isRunning = false;
	this.interval = interval;

	this.onStart = null;
	this.onStop = null;
};

dojo.extend(dojo.lang.timing.Timer, {
	onTick : function(){
		// summary: Method called every time the interval passes.  Override to do something useful.
	},
		
	setInterval : function(interval){
		// summary: Reset the interval of a timer, whether running or not.
		// interval: New interval, in milliseconds.
		if (this.isRunning){
			dj_global.clearInterval(this.timer);
		}
		this.interval = interval;
		if (this.isRunning){
			this.timer = dj_global.setInterval(dojo.lang.hitch(this, "onTick"), this.interval);
		}
	},
	
	start : function(){
		// summary: Start the timer ticking.
		// description: Calls the "onStart()" handler, if defined.
		// 				Note that the onTick() function is not called right away, 
		//				only after first interval passes.
		if (typeof this.onStart == "function"){
			this.onStart();
		}
		this.isRunning = true;
		this.timer = dj_global.setInterval(dojo.lang.hitch(this, "onTick"), this.interval);
	},
	
	stop : function(){
		// summary: Stop the timer.
		// description: Calls the "onStop()" handler, if defined.
		if (typeof this.onStop == "function"){
			this.onStop();
		}
		this.isRunning = false;
		dj_global.clearInterval(this.timer);
	}
});

__CPAN_FILE__ src/lang/timing/Streamer.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.timing.Streamer");
dojo.require("dojo.lang.timing.Timer");

dojo.lang.timing.Streamer = function(
	/* function */input, 
	/* function */output, 
	/* int */interval, 
	/* int */minimum,
	/* array */initialData
){
	//	summary
	//	Streamer will take an input function that pushes N datapoints into a
	//		queue, and will pass the next point in that queue out to an
	//		output function at the passed interval; this way you can emulate
	//		a constant buffered stream of data.
	//	input: the function executed when the internal queue reaches minimumSize
	//	output: the function executed on internal tick
	//	interval: the interval in ms at which the output function is fired.
	//	minimum: the minimum number of elements in the internal queue.

	var self = this;
	var queue = [];

	//	public properties
	this.interval = interval || 1000;
	this.minimumSize = minimum || 10;	//	latency usually == interval * minimumSize
	this.inputFunction = input || function(q){ };
	this.outputFunction = output || function(point){ };

	//	more setup
	var timer = new dojo.lang.timing.Timer(this.interval);
	var tick = function(){
		self.onTick(self);

		if(queue.length < self.minimumSize){
			self.inputFunction(queue);
		}

		var obj = queue.shift();
		while(typeof(obj) == "undefined" && queue.length > 0){
			obj = queue.shift();
		}
		
		//	check to see if the input function needs to be fired
		//	stop before firing the output function
		//	TODO: relegate this to the output function?
		if(typeof(obj) == "undefined"){
			self.stop();
			return;
		}

		//	call the output function.
		self.outputFunction(obj);
	};

	this.setInterval = function(/* int */ms){
		//	summary
		//	sets the interval in milliseconds of the internal timer
		this.interval = ms;
		timer.setInterval(ms);
	};

	this.onTick = function(/* dojo.lang.timing.Streamer */obj){ };
	// wrap the timer functions so that we can connect to them if needed.
	this.start = function(){
		//	summary
		//	starts the Streamer
		if(typeof(this.inputFunction) == "function" && typeof(this.outputFunction) == "function"){
			timer.start();
			return;
		}
		dojo.raise("You cannot start a Streamer without an input and an output function.");
	};
	this.onStart = function(){ };
	this.stop = function(){
		//	summary
		//	stops the Streamer
		timer.stop();
	};
	this.onStop = function(){ };

	//	finish initialization
	timer.onTick = this.tick;
	timer.onStart = this.onStart;
	timer.onStop = this.onStop;
	if(initialData){
		queue.concat(initialData);
	}
};

__CPAN_FILE__ src/lang/timing/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.lang.timing.*");

__CPAN_DIR__ src/data
__CPAN_FILE__ src/data/Read.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.Read");
dojo.require("dojo.lang.declare");
dojo.require("dojo.data.Result");
dojo.require("dojo.experimental");

/* summary:
 *   This is an abstract API that data provider implementations conform to.  
 *   This file defines methods signatures and intentionally leaves all the
 *   methods unimplemented.
 */
dojo.experimental("dojo.data.Read");
 
dojo.declare("dojo.data.Read", null, {
	get:
		function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) {
		/* summary:
		 *   Returns a single attribute value.
		 *   Returns defaultValue if item does not have a value for attribute.
		 *   Returns null if null was explicitly set as the attribute value.
		 *   Returns undefined if the item does not have a value for the given attribute.
		 *   (So, if store.hasAttribute(item, attribute) returns false, then
		 *   store.get(item, attribute) will return undefined.)
		 */
		 
		/* exceptions:
		 *   Conforming implementations should throw an exception if *item* is not
		 *   an item, or *attribute* is neither an attribute object or a string.
		 * examples:
		 *   var darthVader = store.get(lukeSkywalker, "father");
		 */
			dojo.unimplemented('dojo.data.Read.get');
			var attributeValue = null;
			return attributeValue; // a literal, an item, null, or undefined (never an array)
		},
	getValues:
		function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
		/* summary:
		 *   This getValues() method works just like the get() method, but getValues()
		 *   always returns an array rather than a single attribute value.  The array
		 *   may be empty, may contain a single attribute value, or may contain many
		 *   attribute values.
		 *   If the item does not have a value for the given attribute, then getValues()
		 *   will return an empty array: [].  (So, if store.hasAttribute(item, attribute)
		 *   returns false, then store.getValues(item, attribute) will return [].)
		 */
		 
		/* exceptions:
		 *   Throws an exception if item is not an item, or attribute is neither an 
		 *   attribute object or a string.
		 * examples:
		 *   var friendsOfLuke = store.get(lukeSkywalker, "friends");
		 */
			dojo.unimplemented('dojo.data.Read.getValues');
			var array = null;
			return array; // an array that may contain literals and items
		},
	getAttributes:
		function(/* item */ item) {
		/* summary:
		 *   Returns an array with all the attributes that this item has.
		 */
		 
		/* exceptions:
		 *   Throws an exception if item is not an item. 
		 * examples:
		 *   var array = store.getAttributes(kermit);
		 */
			dojo.unimplemented('dojo.data.Read.getAttributes');
			var array = null;
			return array; // array
		},
	hasAttribute:
		function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
		/* summary:
		 *   Returns true if the given *item* has a value or the given *attribute*.
		 */
		 
		/* exceptions:
		 *   Throws an exception if item is not an item, or attribute is neither an 
		 *   attribute object or a string.
		 * examples:
		 *   var yes = store.hasAttribute(kermit, "color");
		 */
			dojo.unimplemented('dojo.data.Read.hasAttribute');
			return false; // boolean
		},
	hasAttributeValue:
		function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) {
		/* summary:
		 *   Returns true if the given *value* is one of the values that getValue()
		 *   would return.
		 */
		 
		/* exceptions:
		 *   Throws an exception if item is not an item, or attribute is neither an 
		 *   attribute object or a string.
		 * examples:
		 *   var yes = store.hasAttributeValue(kermit, "color", "green");
		 */
			dojo.unimplemented('dojo.data.Read.hasAttributeValue');
			return false; // boolean
		},
	isItem:
		function(/* anything */ something) {
		/* summary:
		 *   Returns true if *something* is an item.  Returns false if *something*
		 *   is a literal or is any object other than an item.
		 */
		 
		/* examples:
		 *   var yes = store.isItem(store.newItem());
		 *   var no  = store.isItem("green");
		 */
			dojo.unimplemented('dojo.data.Read.isItem');
			return false; // boolean
		},
	find:
		function(/* implementation-dependent */ query, /* object */ optionalKeywordArgs ) {
		/* summary:
		 *   Given a query, this method returns a Result object containing
		 *   all the items in the query result set.
		 * description:
		 *   A Result object will always be returned, even if the result set
		 *   is empty.  A Result object will always be returned immediately.
		 *   By default the Result object will be fully populated with result
		 *   items as soon as it is created (synchronously).  The caller may request
		 *   an asynchronous Result, meaning a Result that will be populated
		 *   with result items at some point in the future.  If the caller requests
		 *   an asynchronous Result, the data store may return either a synchronous
		 *   or asynchronous Result, whichever it prefers.  Simple data store
		 *   implementations may always return synchronous Results.
		 *   For more info about the Result API, see dojo.data.Result
		 * query:
		 *   The query may be optional in some data store implementations.
		 *   The dojo.data.Read API does not specify the syntax or semantics
		 *   of the query itself -- each different data store implementation
		 *   may have its own notion of what a query should look like.
		 *   In most implementations the query will probably be a string, but
		 *   in some implementations the query might be a Date, or a number,
		 *   or some complex keyword parameter object.  The dojo.data.Read
		 *   API is completely agnostic about what the query actually is.
		 * optionalKeywordArgs:
		 *   The optionalKeywordArgs argument is a object like {async: true}.
		 *   All implementations should accept {async: true} and {async: false}
		 *   as valid parameters, although the API does not require that the
		 *   the implementation actually perform asynchronously when
		 *   {async: true} is set.  Some implementations may take additional
		 *   keyword options, such as {async: true, maxResults:100}.
		 */
		
		/* exceptions:
		 *   Throws an exception if the query is not valid, or if the query
		 *   is required but was not supplied.
		 * examples:
		 *   var results = store.find("all books");
		 *   var results = store.find();
		 *   var results = store.find("foo/bar", {async: true});
		 *   var results = store.find("foo/bar", {async: false});
		 *   var results = store.find({author:"King", {async: true, maxResults:100});
		 */
			dojo.unimplemented('dojo.data.Read.find');
			var result = null; // new dojo.data.Result().
			return result; // an object that implements dojo.data.Result
		},
	getIdentity:
		function(/* item */ item) {
		/* summary:
		 *   Returns a unique identifer for an item.  The return value will be
		 *   either a string or something that has a toString() method (such as,
		 *   for example, a dojo.uuid.Uuid object).
		 * description:
		 * ISSUE - 
		 *   Should we move this method out of dojo.data.Read, and put it somewhere
		 *   else, like maybe dojo.data.Identity?
		 */
		 
		/* exceptions:
		 *   Conforming implementations may throw an exception or return null if
		 *   item is not an item.
		 * examples:
		 *   var itemId = store.getIdentity(kermit);
		 *   assert(kermit === store.getByIdentity(store.getIdentity(kermit)));
		 */
			dojo.unimplemented('dojo.data.Read.getIdentity');
			var itemIdentifyString = null;
			return itemIdentifyString; // string
		},
	getByIdentity:
		function(/* string */ id) {
		/* summary:
		 *   Given the id of an item, this method returns the item that has that id.
		 *   Conforming implementations should return null if there is no item with
		 *   the given id.
		 * description:
		 * ISSUE - 
		 *   We may want to change the name from getByIdentity() to findByIdentity(),
		 *   to reflect the fact that an implementation may not be able to get the
		 *   item from a local cache, and may need to send a request to the server.
		 * ISSUE - 
		 *   Can this method run asynchronously?  Should the return value be a Deferred?
		 * ISSUE - 
		 *   Should we move this method out of dojo.data.Read, and put it somewhere
		 *   else, like maybe dojo.data.Identity?
		 */
		 
		/* examples:
		 *   var alaska = store.getByIdentity("AK");
		 *   assert("AK" == store.getIdentity(store.getByIdentity("AK")));
		 */
			dojo.unimplemented('dojo.data.Read.getByIdentity');
			var item = null;
			return item; // item
		}
});

__CPAN_FILE__ src/data/Write.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.Write");
dojo.require("dojo.lang.declare");
dojo.require("dojo.data.Read");
dojo.require("dojo.experimental");

/* summary:
 *   This is an abstract API that data provider implementations conform to.  
 *   This file defines methods signatures and intentionally leaves all the
 *   methods unimplemented.
 */
dojo.experimental("dojo.data.Write");
 
dojo.declare("dojo.data.Write", dojo.data.Read, {
	newItem:
		function(/* object? */ keywordArgs) {
		/* summary:
		 *   Returns a newly created item.  Sets the attributes of the new
		 *   item based on the keywordArgs provided.
		 */
		 
		/* exceptions:
		 *   Throws an exception if *keywordArgs* is a string or a number or
		 *   anything other than a simple anonymous object.
		 * examples:
		 *   var kermit = store.newItem({name: "Kermit"});
		 */
			var newItem;
			dojo.unimplemented('dojo.data.Write.newItem');
			return newItem; // item
		},
	deleteItem:
		function(/* item */ item) {
		/* summary:
		 *   Deletes an item from the store.
		 */
		 
		/* exceptions:
		 *   Throws an exception if *item* is not an item (if store.isItem(item)
		 *   returns false).
		 * examples:
		 *   var success = store.deleteItem(kermit);
		 */
			dojo.unimplemented('dojo.data.Write.deleteItem');
			return false; // boolean
		},
	set:
		function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
		/* summary:
		 *   Sets the value of an attribute on an item.
		 *   Replaces any previous value or values.
		 */
		 
		/* exceptions:
		 *   Throws an exception if *item* is not an item, or if *attribute*
		 *   is neither an attribute object or a string.
		 *   Throws an exception if *value* is undefined.
		 * examples:
		 *   var success = store.set(kermit, "color", "green");
		 */
			dojo.unimplemented('dojo.data.Write.set');
			return false; // boolean
		},
	setValues:
		function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
		/* summary:
		 *   Adds each value in the *values* array as a value of the given
		 *   attribute on the given item.
		 *   Replaces any previous value or values.
		 *   Calling store.setValues(x, y, []) (with *values* as an empty array) has
		 *   the same effect as calling store.clear(x, y).
		 */
		 
		/* exceptions:
		 *   Throws an exception if *values* is not an array, if *item* is not an
		 *   item, or if *attribute* is neither an attribute object or a string.
		 * examples:
		 *   var success = store.setValues(kermit, "color", ["green", "aqua"]);
		 *   success = store.setValues(kermit, "color", []);
		 *   if (success) {assert(!store.hasAttribute(kermit, "color"));}
		 */
			dojo.unimplemented('dojo.data.Write.setValues');
			return false; // boolean
		},
	clear:
		function(/* item */ item, /* attribute || string */ attribute) {
		/* summary:
		 *   Deletes all the values of an attribute on an item.
		 */
		 
		/* exceptions:
		 *   Throws an exception if *item* is not an item, or if *attribute*
		 *   is neither an attribute object or a string.
		 * examples:
		 *   var success = store.clear(kermit, "color");
		 *   if (success) {assert(!store.hasAttribute(kermit, "color"));}
		 */
			dojo.unimplemented('dojo.data.Write.clear');
			return false; // boolean
		},
	save:
		function() {
		/* summary:
		 *   Saves to the server all the changes that have been made locally.
		 *   The save operation may take some time.  By default the save will
		 *   be done synchronously, before the call returns.  The caller may
		 *   be request an asynchronous save by passing {async: true}.
		 *   If the caller requests an asynchronous save, the data store may do
		 *   either a synchronous or asynchronous save, whichever it prefers.
		 *   Different data store implementations may take additional optional
		 *   parameters.
		 * description:
		 * ISSUE - 
		 *   Should the async save take a callback, like this:
		 *     store.save({async: true, onComplete: callback});
		 *   Or should the async save return a Deferred, like this:
		 *     var deferred = store.save({async: true});
		 *     deferred.addCallbacks(successCallback, errorCallback);
		 *   Or should save() return boolean, like this:
		 *     var success = store.save();
		 */
		 
		/* examples:
		 *   var success = store.save();
		 *   var success = store.save({async: true});
		 */
			dojo.unimplemented('dojo.data.Write.save');
			return false; // boolean
		},
	revert:
		function() {
		/* summary:
		 *   Discards any unsaved changes.
		 */
		 
		/* examples:
		 *   var success = store.revert();
		 */
			dojo.unimplemented('dojo.data.Write.revert');
			return false; // boolean
		},
	isDirty:
		function(/* item (or store) */ item) {
		/* summary:
		 *   Returns true if the given item has been modified since the last save().
		 *   If the datastore object itself is given as a parameter instead of an
		 *   item, then this method returns true if any item has been modified since
		 *   the last save().
		 */
		 
		/* exceptions:
		 *   Throws an exception if *item* is neither an item nor the datastore itself.
		 * examples:
		 *   var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
		 *   var trueOrFalse = store.isDirty(store);  // true if any item is dirty
		 */
			dojo.unimplemented('dojo.data.Write.isDirty');
			return false; // boolean
		}
});

__CPAN_FILE__ src/data/Result.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.Result");
dojo.require("dojo.lang.declare");
dojo.require("dojo.experimental");

/* summary:
 *   This is an abstract API used by data provider implementations.  
 *   This file defines methods signatures and intentionally leaves all the
 *   methods unimplemented.
 */
dojo.experimental("dojo.data.Result");

dojo.declare("dojo.data.Result", null, {
	forEach:
		function(/* function */ callbackFunction, /* object? */ callbackObject, /* object? */ optionalKeywordArgs) {
		/* summary:
		 *   Loops through the result list, calling a callback function
		 *   for each item in the result list.
		 * description:
		 *   The forEach() method will call the callback function once for 
		 *   each item in the result list.  The forEach() method will pass 
		 *   3 arguments to the callbackFunction: an item, the index of 
		 *   item in the context of this forEach() loop, and the result object
		 *   itself.  The signature of this forEach() method was modeled on
		 *   the forEach() method of Mozilla's Array object in JavaScript 1.6:
		 *   http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
		 *   The forEach() method will returns true if the entire result list 
		 *   has been looped through, or false if the result list has not yet
		 *   been looped through.
		 *   The forEach() method will ignore any return value returned by
		 *   the callbackFunction.
		 *   After the forEach() operation has finished (or been cancelled)
		 *   result.forEach() can be called again on the same result object.
		 * ISSUES -
		 *   We haven't yet decided what other parameters we might allow to
		 *   support fancy features.  Here are some ideas:
		 *     results.forEach({callback:callbackFunction, onCompletion: finishedFunction});
		 *     results.forEach({callback:callbackFunction, first: 201, last: 300}); // partial loop
		 *     results.forEach({callback:callbackFunction, first: 200, numItems: 50}); // partial loop from 200 to 250
		 *   CCM - How to specify datastore-specific options to allow caching n
		 *   items before/after current window of items being viewed?
		 * callbackObject:
		 *   If a callbackObject is provided the callbackFunction will be called
		 *   in the context of the callbackObject (the callbackObject will be 
		 *   used as the 'this' for each invocation of the callbackFunction).
		 *   If callbackObject is not provided, or is null, the global object
		 *   associated with callback is used instead.
		 * optionalKeywordArgs:
		 *   The forEach() method may accept a third parameter, which should be
		 *   an object with keyword parameters.  Different implementations may
		 *   make use of different keyword paramters.  Conforming 
		 *   implementations ignore keyword parameters that they don't 
		 *   recognize.
		 */
		 
		/* examples:
		 *   var results = store.find("recent books");            // synchronous
		 *   var results = store.find("all books", {sync: false}); // asynchronous
		 *   someCallbackFunction = function(item, resultObject) {};
		 *   results.forEach(someCallbackFunction);
		 *   results.forEach({object:someHandlerObject, callback:"someCallbackMethod"});
		 */
			dojo.unimplemented('dojo.data.Result.forEach');
			return false; // boolean
		},
	getLength:
		function() {
		/* summary:
		 *   Returns an integer -- the number of items in the result list.
		 *   Returns -1 if the length is not known when the method is called.
		 */
			dojo.unimplemented('dojo.data.Result.getLength');
			return -1; // integer
		},
	inProgress:
		function() {
		/* summary:
		 *   Returns true if a forEach() loop is in progress.
		 */
			dojo.unimplemented('dojo.data.Result.inProgress');
			return false; // boolean
		},
	cancel:
		function() {
		/* summary:
		 *   Calling cancel() stops any and all processing associated with this
		 *   result object.  
		 * description: 
		 *   If a forEach() loop is in progress, calling cancel() will stop 
		 *   the loop.  If a store.find() is in progress, and that find() 
		 *   involves an XMLHttpRequest, calling cancel() will abort the 
		 *   XMLHttpRequest.  If callbacks have been set using setOnFindCompleted() 
		 *   or setOnError(), calling cancel() will cause those callbacks to 
		 *   not be called under any circumstances.
		 */
			dojo.unimplemented('dojo.data.Result.cancel');
		},
	setOnFindCompleted:
		function(/* function */ callbackFunction, /* object? */ callbackObject) {
		/* summary:
		 *   Allows you to register a callbackFunction that will
		 *   be called when all the results are available.
		 * description:
		 *   If a callbackObject is provided the callbackFunction will be 
		 *   called in the context of the callbackObject (the callbackObject
		 *   will be used as the 'this' for each invocation of the
		 *   callbackFunction).  If callbackObject is not provided, or is 
		 *   null, the global object associated with callback is used instead.
		 *   The setOnFindCompleted() method will ignore any return value 
		 *   returned by the callbackFunction.
		 * ISSUES -
		 *   We have not yet decided what parameters the setOnFindCompleted() 
		 *   will pass to the callbackFunction...
		 *   (A) The setOnFindCompleted() method will pass one parameter to the 
		 *   callbackFunction: the result object itself.
		 *   (B) The setOnFindCompleted() method will pass two parameters to the 
		 *   callbackFunction: an iterator object, and the result object itself.
		 */
			dojo.unimplemented('dojo.data.Result.setOnFindCompleted');
		},
	setOnError:
		function(/* function */ errorCallbackFunction, /* object? */ callbackObject) {
		/* summary:
		 *   Allows you to register a errorCallbackFunction that
		 *   will be called if there is any sort of error.
		 * description:
		 *   If a callbackObject is provided the errorCallbackFunction will
		 *   be called in the context of the callbackObject (the callbackObject
		 *   will be used as the 'this' for each invocation of the
		 *   errorCallbackFunction).  If callbackObject is not provided, or is 
		 *   null, the global object associated with callback is used instead.
		 *   The setOnError() method will pass two parameters to the 
		 *   errorCallbackFunction: an Error object, and the result object 
		 *   itself:
		 *     errorCallbackFunction(errorObject, resultObject); 
		 *   The setOnError() method will ignore any return value returned 
		 *   by the errorCallbackFunction.
		 */
			dojo.unimplemented('dojo.data.Result.setOnError');
		},
	getStore:
		function() {
		/* summary:
		 *   Returns the datastore object that created this result list
		 */
			dojo.unimplemented('dojo.data.Result.getStore');
			return null; // an object that implements dojo.data.Read
		}
});

__CPAN_DIR__ src/data/old
__CPAN_FILE__ src/data/old/to_do.txt
Existing Features
 * can import data from .json or .csv format files
 * can import data from del.icio.us
 * can create and modify data programmatically
 * can bind data to dojo.widget.Chart
 * can bind data to dojo.widget.SortableTable
 * can bind one data set to multiple widgets
 * notifications: widgets are notified when data changes
 * notification available per-item or per-resultSet
 * can create ad-hoc attributes
 * attributes can be loosely-typed 
 * attributes can have meta-data like type and display name
 * half-implemented support for sorting
 * half-implemented support for export to .json
 * API for getting data in simple arrays 
 * API for getting ResultSets with iterators (precursor to support for something like the openrico.org live grid)
 
~~~~~~~~~~~~~~~~~~~~~~~~
To-Do List
 * be able to import data from an html <table></table>
 * think about being able to import data from some type of XML 
 * think about integration with dojo.undo.Manager
 * think more about how to represent the notion of different data types
 * think about what problems we'll run into when we have a MySQL data provider
 * in TableBindingHack, improve support for data types in the SortableTable binding
 * deal with ids (including MySQL multi-field keys)
 * add support for item-references:  employeeItem.set('department', departmentItem);
 * deal with Attributes as instances of Items, not just subclasses of Items
 * unit tests for compare/sort code
 * unit tests for everything
 * implement item.toString('json') and item.toString('xml')
 * implement dataProvider.newItem({name: 'foo', age: 26})
 * deal better with transactions
 * add support for deleting items
 * don't send out multiple notifications to the same observer
 * deal with item versions
 * prototype a Yahoo data provider -- http://developer.yahoo.net/common/json.html
 * prototype a data provider that enforces strong typing
 * prototype a data provider that prevents ad-hoc attributes
 * prototype a data provider that enforces single-kind item
 * prototype a data provider that allows for login/authentication
 * have loosely typed result sets play nicely with widgets that expect strong typing
 * prototype an example of spreadsheet-style formulas or derivation rules
 * experiment with some sort of fetch() that returns only a subset of a data provider's items


__CPAN_FILE__ src/data/old/Item.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.Item");
dojo.require("dojo.data.old.Observable");
dojo.require("dojo.data.old.Value");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.assert");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Item = function(/* dojo.data.old.provider.Base */ dataProvider) {
	/**
	 * summary:
	 * An Item has attributes and attribute values, sort of like 
	 * a record in a database, or a 'struct' in C.  Instances of
	 * the Item class know how to store and retrieve their
	 * attribute values.
	 */
	dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
	dojo.data.old.Observable.call(this);
	this._dataProvider = dataProvider;
	this._dictionaryOfAttributeValues = {};
};
dojo.inherits(dojo.data.old.Item, dojo.data.old.Observable);

// -------------------------------------------------------------------
// Public class methods
// -------------------------------------------------------------------
dojo.data.old.Item.compare = function(/* dojo.data.old.Item */ itemOne, /* dojo.data.old.Item */ itemTwo) {
	/**
	 * summary:
	 * Given two Items to compare, this method returns 0, 1, or -1.
	 * This method is designed to be used by sorting routines, like
	 * the JavaScript built-in Array sort() method.
	 * 
	 * Example:
	 * <pre>
	 *   var a = dataProvider.newItem("kermit");
	 *   var b = dataProvider.newItem("elmo");
	 *   var c = dataProvider.newItem("grover");
	 *   var array = new Array(a, b, c);
	 *   array.sort(dojo.data.old.Item.compare);
	 * </pre>
	 */
	dojo.lang.assertType(itemOne, dojo.data.old.Item);
	if (!dojo.lang.isOfType(itemTwo, dojo.data.old.Item)) {
		return -1;
	}
	var nameOne = itemOne.getName();
	var nameTwo = itemTwo.getName();
	if (nameOne == nameTwo) {
		var attributeArrayOne = itemOne.getAttributes();
		var attributeArrayTwo = itemTwo.getAttributes();
		if (attributeArrayOne.length != attributeArrayTwo.length) {
			if (attributeArrayOne.length > attributeArrayTwo.length) {
				return 1; 
			} else {
				return -1;
			}
		}
		for (var i in attributeArrayOne) {
			var attribute = attributeArrayOne[i];
			var arrayOfValuesOne = itemOne.getValues(attribute);
			var arrayOfValuesTwo = itemTwo.getValues(attribute);
			dojo.lang.assert(arrayOfValuesOne && (arrayOfValuesOne.length > 0));
			if (!arrayOfValuesTwo) {
				return 1;
			}
			if (arrayOfValuesOne.length != arrayOfValuesTwo.length) {
				if (arrayOfValuesOne.length > arrayOfValuesTwo.length) {
					return 1; 
				} else {
					return -1;
				}
			}
			for (var j in arrayOfValuesOne) {
				var value = arrayOfValuesOne[j];
				if (!itemTwo.hasAttributeValue(value)) {
					return 1;
				}
			}
			return 0;
		}
	} else {
		if (nameOne > nameTwo) {
			return 1; 
		} else {
			return -1;  // 0, 1, or -1
		}
	}
};

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Item.prototype.toString = function() {
	/**
	 * Returns a simple string representation of the item.
	 */
	var arrayOfStrings = [];
	var attributes = this.getAttributes();
	for (var i in attributes) {
		var attribute = attributes[i];
		var arrayOfValues = this.getValues(attribute);
		var valueString;
		if (arrayOfValues.length == 1) {
			valueString = arrayOfValues[0];
		} else {
			valueString = '[';
			valueString += arrayOfValues.join(', ');
			valueString += ']';
		}
		arrayOfStrings.push('  ' + attribute + ': ' + valueString);
	}
	var returnString = '{ ';
	returnString += arrayOfStrings.join(',\n');
	returnString += ' }';
	return returnString; // string
};

dojo.data.old.Item.prototype.compare = function(/* dojo.data.old.Item */ otherItem) {
	/**
	 * summary: Compares this Item to another Item, and returns 0, 1, or -1.
	 */ 
	return dojo.data.old.Item.compare(this, otherItem); // 0, 1, or -1
};

dojo.data.old.Item.prototype.isEqual = function(/* dojo.data.old.Item */ otherItem) {
	/**
	 * summary: Returns true if this Item is equal to the otherItem, or false otherwise.
	 */
	return (this.compare(otherItem) == 0); // boolean
};

dojo.data.old.Item.prototype.getName = function() {
	return this.get('name');
};

dojo.data.old.Item.prototype.get = function(/* string or dojo.data.old.Attribute */ attributeId) {
	/**
	 * summary: Returns a single literal value, like "foo" or 33.
	 */ 
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
		return null; // null
	}
	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
		return literalOrValueOrArray.getValue(); // literal
	}
	if (dojo.lang.isArray(literalOrValueOrArray)) {
		var dojoDataValue = literalOrValueOrArray[0];
		return dojoDataValue.getValue(); // literal
	}
	return literalOrValueOrArray; // literal
};

dojo.data.old.Item.prototype.getValue = function(/* string or dojo.data.old.Attribute */ attributeId) {
	/**
	 * summary: Returns a single instance of dojo.data.old.Value.
	 */ 
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
		return null; // null
	}
	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
		return literalOrValueOrArray; // dojo.data.old.Value
	}
	if (dojo.lang.isArray(literalOrValueOrArray)) {
		var dojoDataValue = literalOrValueOrArray[0];
		return dojoDataValue; // dojo.data.old.Value
	}
	var literal = literalOrValueOrArray;
	dojoDataValue = new dojo.data.old.Value(literal);
	this._dictionaryOfAttributeValues[attributeId] = dojoDataValue;
	return dojoDataValue; // dojo.data.old.Value
};

dojo.data.old.Item.prototype.getValues = function(/* string or dojo.data.old.Attribute */ attributeId) {
	/**
	 * summary: Returns an array of dojo.data.old.Value objects.
	 */ 
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
		return null; // null
	}
	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
		var array = [literalOrValueOrArray];
		this._dictionaryOfAttributeValues[attributeId] = array;
		return array; // Array
	}
	if (dojo.lang.isArray(literalOrValueOrArray)) {
		return literalOrValueOrArray; // Array
	}
	var literal = literalOrValueOrArray;
	var dojoDataValue = new dojo.data.old.Value(literal);
	array = [dojoDataValue];
	this._dictionaryOfAttributeValues[attributeId] = array;
	return array; // Array
};

dojo.data.old.Item.prototype.load = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
	/**
	 * summary: 
	 * Used for loading an attribute value into an item when
	 * the item is first being loaded into memory from some
	 * data store (such as a file).
	 */ 
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	this._dataProvider.registerAttribute(attributeId);
	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
		this._dictionaryOfAttributeValues[attributeId] = value;
		return;
	}
	if (!(value instanceof dojo.data.old.Value)) {
		value = new dojo.data.old.Value(value);
	}
	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
		var array = [literalOrValueOrArray, value];
		this._dictionaryOfAttributeValues[attributeId] = array;
		return;
	}
	if (dojo.lang.isArray(literalOrValueOrArray)) {
		literalOrValueOrArray.push(value);
		return;
	}
	var literal = literalOrValueOrArray;
	var dojoDataValue = new dojo.data.old.Value(literal);
	array = [dojoDataValue, value];
	this._dictionaryOfAttributeValues[attributeId] = array;
};

dojo.data.old.Item.prototype.set = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
	/**
	 * summary: 
	 * Used for setting an attribute value as a result of a
	 * user action.
	 */ 
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	this._dataProvider.registerAttribute(attributeId);
	this._dictionaryOfAttributeValues[attributeId] = value;
	this._dataProvider.noteChange(this, attributeId, value);
};

dojo.data.old.Item.prototype.setValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* dojo.data.old.Value */ value) {
	this.set(attributeId, value);
};

dojo.data.old.Item.prototype.addValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
	/**
	 * summary: 
	 * Used for adding an attribute value as a result of a
	 * user action.
	 */ 
	this.load(attributeId, value);
	this._dataProvider.noteChange(this, attributeId, value);
};

dojo.data.old.Item.prototype.setValues = function(/* string or dojo.data.old.Attribute */ attributeId, /* Array */ arrayOfValues) {
	/**
	 * summary: 
	 * Used for setting an array of attribute values as a result of a
	 * user action.
	 */
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	dojo.lang.assertType(arrayOfValues, Array);
	this._dataProvider.registerAttribute(attributeId);
	var finalArray = [];
	this._dictionaryOfAttributeValues[attributeId] = finalArray;
	for (var i in arrayOfValues) {
		var value = arrayOfValues[i];
		if (!(value instanceof dojo.data.old.Value)) {
			value = new dojo.data.old.Value(value);
		}
		finalArray.push(value);
		this._dataProvider.noteChange(this, attributeId, value);
	}
};

dojo.data.old.Item.prototype.getAttributes = function() {
	/**
	 * summary: 
	 * Returns an array containing all of the attributes for which
	 * this item has attribute values.
	 */ 
	var arrayOfAttributes = [];
	for (var key in this._dictionaryOfAttributeValues) {
		arrayOfAttributes.push(this._dataProvider.getAttribute(key));
	}
	return arrayOfAttributes; // Array
};

dojo.data.old.Item.prototype.hasAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
	/**
	 * summary: Returns true if the given attribute of the item has been assigned any value.
	 */ 
	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
	return (attributeId in this._dictionaryOfAttributeValues); // boolean
};

dojo.data.old.Item.prototype.hasAttributeValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
	/**
	 * summary: Returns true if the given attribute of the item has been assigned the given value.
	 */ 
	var arrayOfValues = this.getValues(attributeId);
	for (var i in arrayOfValues) {
		var candidateValue = arrayOfValues[i];
		if (candidateValue.isEqual(value)) {
			return true; // boolean
		}
	}
	return false; // boolean
};



__CPAN_FILE__ src/data/old/Type.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.Type");
dojo.require("dojo.data.old.Item");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Type = function(/* dojo.data.old.provider.Base */ dataProvider) {
	/**
	 * summary:
	 * A Type represents a type of value, like Text, Number, Picture,
	 * or Varchar.
	 */
	dojo.data.old.Item.call(this, dataProvider);
};
dojo.inherits(dojo.data.old.Type, dojo.data.old.Item);

__CPAN_FILE__ src/data/old/ResultSet.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.ResultSet");
dojo.require("dojo.lang.assert");
dojo.require("dojo.collections.Collections");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.ResultSet = function(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfItems) {
	/**
	 * summary:
	 * A ResultSet holds a collection of Items.  A data provider
	 * returns a ResultSet in reponse to a query.
	 * (The name "Result Set" comes from the MySQL terminology.)
	 */
	dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
	dojo.lang.assertType(arrayOfItems, Array, {optional: true});
	dojo.data.old.Observable.call(this);
	this._dataProvider = dataProvider;
	this._arrayOfItems = [];
	if (arrayOfItems) {
		this._arrayOfItems = arrayOfItems;
	}
};
dojo.inherits(dojo.data.old.ResultSet, dojo.data.old.Observable);

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.ResultSet.prototype.toString = function() {
	var returnString = this._arrayOfItems.join(', ');
	return returnString; // string
};

dojo.data.old.ResultSet.prototype.toArray = function() {
	return this._arrayOfItems; // Array
};

dojo.data.old.ResultSet.prototype.getIterator = function() {
	return new dojo.collections.Iterator(this._arrayOfItems);
};

dojo.data.old.ResultSet.prototype.getLength = function() {
	return this._arrayOfItems.length; // integer
};

dojo.data.old.ResultSet.prototype.getItemAt = function(/* numeric */ index) {
	return this._arrayOfItems[index];
};

dojo.data.old.ResultSet.prototype.indexOf = function(/* dojo.data.old.Item */ item) {
	return dojo.lang.indexOf(this._arrayOfItems, item); // integer
};

dojo.data.old.ResultSet.prototype.contains = function(/* dojo.data.old.Item */ item) {
	return dojo.lang.inArray(this._arrayOfItems, item); // boolean
};

dojo.data.old.ResultSet.prototype.getDataProvider = function() {
	return this._dataProvider; // dojo.data.old.provider.Base
};
__CPAN_FILE__ src/data/old/Attribute.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.Attribute");
dojo.require("dojo.data.old.Item");
dojo.require("dojo.lang.assert");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Attribute = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ attributeId) {
	/**
	 * summary:
	 * An Attribute object represents something like a column in 
	 * a relational database.
	 */
	dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
	dojo.lang.assertType(attributeId, String);
	dojo.data.old.Item.call(this, dataProvider);
	this._attributeId = attributeId;
};
dojo.inherits(dojo.data.old.Attribute, dojo.data.old.Item);

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Attribute.prototype.toString = function() {
	return this._attributeId; // string
};

dojo.data.old.Attribute.prototype.getAttributeId = function() {
	/**
	 * summary: 
	 * Returns the string token that uniquely identifies this
	 * attribute within the context of a data provider.
	 * For a data provider that accesses relational databases,
	 * typical attributeIds might be tokens like "name", "age", 
	 * "ssn", or "dept_key".
	 */ 
	return this._attributeId; // string
};

dojo.data.old.Attribute.prototype.getType = function() {
	/**
	 * summary: Returns the data type of the values of this attribute.
	 */ 
	return this.get('type'); // dojo.data.old.Type or null
};

dojo.data.old.Attribute.prototype.setType = function(/* dojo.data.old.Type or null */ type) {
	/**
	 * summary: Sets the data type for this attribute.
	 */ 
	this.set('type', type);
};

__CPAN_FILE__ src/data/old/Kind.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.Kind");
dojo.require("dojo.data.old.Item");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Kind = function(/* dojo.data.old.provider.Base */ dataProvider) {
	/**
	 * summary:
	 * A Kind represents a kind of item.  In the dojo data model
	 * the item Snoopy might belong to the 'kind' Dog, where in
	 * a Java program the object Snoopy would belong to the 'class'
	 * Dog, and in MySQL the record for Snoopy would be in the 
	 * table Dog.
	 */
	dojo.data.old.Item.call(this, dataProvider);
};
dojo.inherits(dojo.data.old.Kind, dojo.data.old.Item);

__CPAN_FILE__ src/data/old/Observable.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.Observable");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.assert");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Observable = function() {
};

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Observable.prototype.addObserver = function(/* object */ observer) {
	/**
	 * summary: Registers an object as an observer of this item,
	 * so that the object will be notified when the item changes.
	 */ 
	dojo.lang.assertType(observer, Object);
	dojo.lang.assertType(observer.observedObjectHasChanged, Function);
	if (!this._arrayOfObservers) {
		this._arrayOfObservers = [];
	}
	if (!dojo.lang.inArray(this._arrayOfObservers, observer)) {
		this._arrayOfObservers.push(observer);
	}
};

dojo.data.old.Observable.prototype.removeObserver = function(/* object */ observer) {
	/**
	 * summary: Removes the observer registration for a previously
	 * registered object.
	 */ 
	if (!this._arrayOfObservers) {
		return;
	}
	var index = dojo.lang.indexOf(this._arrayOfObservers, observer);
	if (index != -1) {
		this._arrayOfObservers.splice(index, 1);
	}
};

dojo.data.old.Observable.prototype.getObservers = function() {
	/**
	 * summary: Returns an array with all the observers of this item.
	 */ 
	return this._arrayOfObservers; // Array or undefined
};


__CPAN_FILE__ src/data/old/Value.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.Value");
dojo.require("dojo.lang.assert");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Value = function(/* anything */ value) {
	/**
	 * summary:
	 * A Value represents a simple literal value (like "foo" or 334),
	 * or a reference value (a pointer to an Item).
	 */
	this._value = value;
	this._type = null;
};

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Value.prototype.toString = function() {
	return this._value.toString(); // string
};

dojo.data.old.Value.prototype.getValue = function() {
	/**
	 * summary: Returns the value itself.
	 */ 
	return this._value; // anything
};

dojo.data.old.Value.prototype.getType = function() {
	/**
	 * summary: Returns the data type of the value.
	 */ 
	dojo.unimplemented('dojo.data.old.Value.prototype.getType');
	return this._type; // dojo.data.old.Type
};

dojo.data.old.Value.prototype.compare = function() {
	dojo.unimplemented('dojo.data.old.Value.prototype.compare');
};

dojo.data.old.Value.prototype.isEqual = function() {
	dojo.unimplemented('dojo.data.old.Value.prototype.isEqual');
};

__CPAN_FILE__ src/data/old/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.experimental");

dojo.experimental("dojo.data.old.*");
dojo.kwCompoundRequire({
	common: [
		"dojo.data.old.Item",
		"dojo.data.old.ResultSet",
		"dojo.data.old.provider.FlatFile"
	]
});
dojo.provide("dojo.data.old.*");


__CPAN_DIR__ src/data/old/provider
__CPAN_FILE__ src/data/old/provider/MySql.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.provider.MySql");
dojo.require("dojo.data.old.provider.Base");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.MySql = function() {
	/**
	 * summary:
	 * A MySql Data Provider knows how to connect to a MySQL database
	 * on a server and and make the content records available as 
	 * dojo.data.old.Items.
	 */
	dojo.unimplemented('dojo.data.old.provider.MySql');
};

dojo.inherits(dojo.data.old.provider.MySql, dojo.data.old.provider.Base);

__CPAN_FILE__ src/data/old/provider/Delicious.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.provider.Delicious");
dojo.require("dojo.data.old.provider.FlatFile");
dojo.require("dojo.data.old.format.Json");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.Delicious = function() {
	/**
	 * summary:
	 * The Delicious Data Provider can be used to take data from
	 * del.icio.us and make it available as dojo.data.old.Items
	 * In order to use the Delicious Data Provider, you need 
	 * to have loaded a script tag that looks like this:
	 * <script type="text/javascript" src="http://del.icio.us/feeds/json/gumption?count=8"></script>
	 */
	dojo.data.old.provider.FlatFile.call(this);
	// Delicious = null;
	if (Delicious && Delicious.posts) {
		dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, Delicious.posts);
	} else {
		// document.write("<script type='text/javascript'>dojo.data.old.provider.Delicious._fetchComplete()</script>");		
		/*
		document.write("<script type='text/javascript'>alert('boo!');</script>");		
		document.write("<script type='text/javascript'>var foo = 'not dojo'; alert('dojo == ' + foo);</script>");		
		document.write("<script type='text/javascript'>var foo = fetchComplete; alert('dojo == ' + foo);</script>");		
		fetchComplete();
		*/
		// dojo.debug("Delicious line 29: constructor");
	}
	var u = this.registerAttribute('u');
	var d = this.registerAttribute('d');
	var t = this.registerAttribute('t');
	
	u.load('name', 'Bookmark');
	d.load('name', 'Description');
	t.load('name', 'Tags');
	
	u.load('type', 'String');
	d.load('type', 'String');
	t.load('type', 'String');
};
dojo.inherits(dojo.data.old.provider.Delicious, dojo.data.old.provider.FlatFile);

/********************************************************************
 * FIXME: the rest of this is work in progress
 *
 
dojo.data.old.provider.Delicious.prototype.getNewItemToLoad = function() {
	var newItem = this._newItem();
	this._currentArray.push(newItem);
	return newItem; // dojo.data.old.Item
};

dojo.data.old.provider.Delicious.prototype.fetchArray = function(query) {
	if (!query) {	
		query = "gumption";
	}
	this._currentArray = [];
	alert("Delicious line 60: loadDataProviderFromArrayOfJsonData");
	alert("Delicious line 61: " + dojo);
		var sourceUrl = "http://del.icio.us/feeds/json/" + query + "?count=8";
		document.write("<script type='text/javascript' src='" + sourceUrl + "'></script>");
		document.write("<script type='text/javascript'>alert('line 63: ' + Delicious.posts[0].u);</script>");		
		document.write("<script type='text/javascript'>callMe();</script>");		
	alert("line 66");
	dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, Delicious.posts);
	return this._currentArray; // Array
};

callMe = function() {
	alert("callMe!");
};

*/

__CPAN_FILE__ src/data/old/provider/FlatFile.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.provider.FlatFile");
dojo.require("dojo.data.old.provider.Base");
dojo.require("dojo.data.old.Item");
dojo.require("dojo.data.old.Attribute");
dojo.require("dojo.data.old.ResultSet");
dojo.require("dojo.data.old.format.Json");
dojo.require("dojo.data.old.format.Csv");
dojo.require("dojo.lang.assert");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.FlatFile = function(/* keywords */ keywordParameters) {
	/**
	 * summary:
	 * A Json Data Provider knows how to read in simple JSON data
	 * tables and make their contents accessable as Items.
	 */
	dojo.lang.assertType(keywordParameters, "pureobject", {optional: true});
	dojo.data.old.provider.Base.call(this);
	this._arrayOfItems = [];
	this._resultSet = null;
	this._dictionaryOfAttributes = {};

	if (keywordParameters) {
		var jsonObjects = keywordParameters["jsonObjects"];
		var jsonString  = keywordParameters["jsonString"];
		var fileUrl     = keywordParameters["url"];
		if (jsonObjects) {
			dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, jsonObjects);
		}
		if (jsonString) {
			dojo.data.old.format.Json.loadDataProviderFromFileContents(this, jsonString);
		}
		if (fileUrl) {
			var arrayOfParts = fileUrl.split('.');
			var lastPart = arrayOfParts[(arrayOfParts.length - 1)];
			var formatParser = null;
			if (lastPart == "json") {
				formatParser = dojo.data.old.format.Json;
			}
			if (lastPart == "csv") {
				formatParser = dojo.data.old.format.Csv;
			}
			if (formatParser) {
				var fileContents = dojo.hostenv.getText(fileUrl);
				formatParser.loadDataProviderFromFileContents(this, fileContents);
			} else {
				dojo.lang.assert(false, "new dojo.data.old.provider.FlatFile({url: }) was passed a file without a .csv or .json suffix");
			}
		}
	}
};
dojo.inherits(dojo.data.old.provider.FlatFile, dojo.data.old.provider.Base);

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.FlatFile.prototype.getProviderCapabilities = function(/* string */ keyword) {
	dojo.lang.assertType(keyword, String, {optional: true});
	if (!this._ourCapabilities) {
		this._ourCapabilities = {
			transactions: false,
			undo: false,
			login: false,
			versioning: false,
			anonymousRead: true,
			anonymousWrite: false,
			permissions: false,
			queries: false,
			strongTyping: false,
			datatypes: [String, Date, Number]
		};
	}
	if (keyword) {
		return this._ourCapabilities[keyword];
	} else {
		return this._ourCapabilities;
	}
};

dojo.data.old.provider.FlatFile.prototype.registerAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
	var registeredAttribute = this.getAttribute(attributeId);
	if (!registeredAttribute) {
		var newAttribute = new dojo.data.old.Attribute(this, attributeId);
		this._dictionaryOfAttributes[attributeId] = newAttribute;
		registeredAttribute = newAttribute;
	}
	return registeredAttribute; // dojo.data.old.Attribute
};

dojo.data.old.provider.FlatFile.prototype.getAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
	var attribute = (this._dictionaryOfAttributes[attributeId] || null);
	return attribute; // dojo.data.old.Attribute or null
};

dojo.data.old.provider.FlatFile.prototype.getAttributes = function() {
	var arrayOfAttributes = [];
	for (var key in this._dictionaryOfAttributes) {
		var attribute = this._dictionaryOfAttributes[key];
		arrayOfAttributes.push(attribute);
	}
	return arrayOfAttributes; // Array
};

dojo.data.old.provider.FlatFile.prototype.fetchArray = function(query) {
	/**
	 * summary: Returns an Array containing all of the Items.
	 */ 
	return this._arrayOfItems; // Array
};

dojo.data.old.provider.FlatFile.prototype.fetchResultSet = function(query) {
	/**
	 * summary: Returns a ResultSet containing all of the Items.
	 */ 
	if (!this._resultSet) {
		this._resultSet = new dojo.data.old.ResultSet(this, this.fetchArray(query));
	}
	return this._resultSet; // dojo.data.old.ResultSet
};

// -------------------------------------------------------------------
// Private instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.FlatFile.prototype._newItem = function() {
	var item = new dojo.data.old.Item(this);
	this._arrayOfItems.push(item);
	return item; // dojo.data.old.Item
};

dojo.data.old.provider.FlatFile.prototype._newAttribute = function(/* String */ attributeId) {
	dojo.lang.assertType(attributeId, String);
	dojo.lang.assert(this.getAttribute(attributeId) === null);
	var attribute = new dojo.data.old.Attribute(this, attributeId);
	this._dictionaryOfAttributes[attributeId] = attribute;
	return attribute; // dojo.data.old.Attribute
};

dojo.data.old.provider.Base.prototype._getResultSets = function() {
	return [this._resultSet]; // Array
};


__CPAN_FILE__ src/data/old/provider/JotSpot.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.provider.JotSpot");
dojo.require("dojo.data.old.provider.Base");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.JotSpot = function() {
	/**
	 * summary:
	 * A JotSpot Data Provider knows how to read data from a JotSpot data 
	 * store and make the contents accessable as dojo.data.old.Items.
	 */
	dojo.unimplemented('dojo.data.old.provider.JotSpot');
};

dojo.inherits(dojo.data.old.provider.JotSpot, dojo.data.old.provider.Base);


__CPAN_FILE__ src/data/old/provider/Base.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.provider.Base");
dojo.require("dojo.lang.assert");

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.Base = function() {
	/**
	 * summary:
	 * A Data Provider serves as a connection to some data source,
	 * like a relational database.  This data provider Base class
	 * serves as an abstract superclass for other data provider
	 * classes.
	 */
	this._countOfNestedTransactions = 0;
	this._changesInCurrentTransaction = null;
};

// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.Base.prototype.beginTransaction = function() {
	/**
	 * Marks the beginning of a transaction.
	 *
	 * Each time you call beginTransaction() you open a new transaction, 
	 * which you need to close later using endTransaction().  Transactions
	 * may be nested, but the beginTransaction and endTransaction calls
	 * always need to come in pairs.
	 */
	if (this._countOfNestedTransactions === 0) {
		this._changesInCurrentTransaction = [];
	}
	this._countOfNestedTransactions += 1;
};

dojo.data.old.provider.Base.prototype.endTransaction = function() {
	/**
	 * Marks the end of a transaction.
	 */
	this._countOfNestedTransactions -= 1;
	dojo.lang.assert(this._countOfNestedTransactions >= 0);

	if (this._countOfNestedTransactions === 0) {
		var listOfChangesMade = this._saveChanges();
		this._changesInCurrentTransaction = null;
		if (listOfChangesMade.length > 0) {
			// dojo.debug("endTransaction: " + listOfChangesMade.length + " changes made");
			this._notifyObserversOfChanges(listOfChangesMade);
		}
	}
};

dojo.data.old.provider.Base.prototype.getNewItemToLoad = function() {
	return this._newItem(); // dojo.data.old.Item
};

dojo.data.old.provider.Base.prototype.newItem = function(/* string */ itemName) {
	/**
	 * Creates a new item.
	 */
	dojo.lang.assertType(itemName, String, {optional: true});
	var item = this._newItem();
	if (itemName) {
		item.set('name', itemName);
	}
	return item; // dojo.data.old.Item
};

dojo.data.old.provider.Base.prototype.newAttribute = function(/* string */ attributeId) {
	/**
	 * Creates a new attribute.
	 */
	dojo.lang.assertType(attributeId, String, {optional: true});
	var attribute = this._newAttribute(attributeId);
	return attribute; // dojo.data.old.Attribute
};

dojo.data.old.provider.Base.prototype.getAttribute = function(/* string */ attributeId) {
	dojo.unimplemented('dojo.data.old.provider.Base');
	var attribute;
	return attribute; // dojo.data.old.Attribute
};

dojo.data.old.provider.Base.prototype.getAttributes = function() {
	dojo.unimplemented('dojo.data.old.provider.Base');
	return this._arrayOfAttributes; // Array
};

dojo.data.old.provider.Base.prototype.fetchArray = function() {
	dojo.unimplemented('dojo.data.old.provider.Base');
	return []; // Array
};

dojo.data.old.provider.Base.prototype.fetchResultSet = function() {
	dojo.unimplemented('dojo.data.old.provider.Base');
	var resultSet;
	return resultSet; // dojo.data.old.ResultSet
};

dojo.data.old.provider.Base.prototype.noteChange = function(/* dojo.data.old.Item */ item, /* string or dojo.data.old.Attribute */ attribute, /* anything */ value) {
	var change = {item: item, attribute: attribute, value: value};
	if (this._countOfNestedTransactions === 0) {
		this.beginTransaction();
		this._changesInCurrentTransaction.push(change);
		this.endTransaction();
	} else {
		this._changesInCurrentTransaction.push(change);
	}
};

dojo.data.old.provider.Base.prototype.addItemObserver = function(/* dojo.data.old.Item */ item, /* object */ observer) {
	/**
	 * summary: Registers an object as an observer of an item,
	 * so that the object will be notified when the item changes.
	 */
	dojo.lang.assertType(item, dojo.data.old.Item);
	item.addObserver(observer);
};

dojo.data.old.provider.Base.prototype.removeItemObserver = function(/* dojo.data.old.Item */ item, /* object */ observer) {
	/**
	 * summary: Removes the observer registration for a previously
	 * registered object.
	 */ 
	dojo.lang.assertType(item, dojo.data.old.Item);
	item.removeObserver(observer);
};

// -------------------------------------------------------------------
// Private instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.Base.prototype._newItem = function() {
	var item = new dojo.data.old.Item(this);
	return item; // dojo.data.old.Item
};

dojo.data.old.provider.Base.prototype._newAttribute = function(/* String */ attributeId) {
	var attribute = new dojo.data.old.Attribute(this);
	return attribute; // dojo.data.old.Attribute
};

dojo.data.old.provider.Base.prototype._saveChanges = function() {
	var arrayOfChangesMade = this._changesInCurrentTransaction;
	return arrayOfChangesMade; // Array
};

dojo.data.old.provider.Base.prototype._notifyObserversOfChanges = function(/* Array */ arrayOfChanges) {
	var arrayOfResultSets = this._getResultSets();
	for (var i in arrayOfChanges) {
		var change = arrayOfChanges[i];
		var changedItem = change.item;
		var arrayOfItemObservers = changedItem.getObservers();
		for (var j in arrayOfItemObservers) {
			var observer = arrayOfItemObservers[j];
			observer.observedObjectHasChanged(changedItem, change);
		}
		for (var k in arrayOfResultSets) {
			var resultSet = arrayOfResultSets[k];
			var arrayOfResultSetObservers = resultSet.getObservers();
			for (var m in arrayOfResultSetObservers) {
				observer = arrayOfResultSetObservers[m];
				observer.observedObjectHasChanged(resultSet, change);
			}
		}
	}
};

dojo.data.old.provider.Base.prototype._getResultSets = function() {
	dojo.unimplemented('dojo.data.old.provider.Base');
	return []; // Array
};


__CPAN_DIR__ src/data/old/format
__CPAN_FILE__ src/data/old/format/Json.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.format.Json");
dojo.require("dojo.lang.assert");

dojo.data.old.format.Json = new function() {

	// -------------------------------------------------------------------
	// Public functions
	// -------------------------------------------------------------------
	this.loadDataProviderFromFileContents = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ jsonFileContents) {
		dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base);
		dojo.lang.assertType(jsonFileContents, String);
		var arrayOfJsonData = eval("(" + jsonFileContents + ")");
		this.loadDataProviderFromArrayOfJsonData(dataProvider, arrayOfJsonData);
	};
	
	this.loadDataProviderFromArrayOfJsonData = function(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) {
		dojo.lang.assertType(arrayOfJsonData, Array, {optional: true});
		if (arrayOfJsonData && (arrayOfJsonData.length > 0)) {
			var firstRow = arrayOfJsonData[0];
			dojo.lang.assertType(firstRow, [Array, "pureobject"]);
			if (dojo.lang.isArray(firstRow)) {
				_loadDataProviderFromArrayOfArrays(dataProvider, arrayOfJsonData);
			} else {
				dojo.lang.assertType(firstRow, "pureobject");
				_loadDataProviderFromArrayOfObjects(dataProvider, arrayOfJsonData);
			}
		}
	};

	this.getJsonStringFromResultSet = function(/* dojo.data.old.ResultSet */ resultSet) {
		dojo.unimplemented('dojo.data.old.format.Json.getJsonStringFromResultSet');
		var jsonString = null;
		return jsonString; // String
	};

	// -------------------------------------------------------------------
	// Private functions
	// -------------------------------------------------------------------
	function _loadDataProviderFromArrayOfArrays(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) {
		/** 
		 * Example: 
		 * var arrayOfJsonStates = [
		 * 	 [ "abbr",  "population",  "name" ]
		 * 	 [  "WA",     5894121,      "Washington"    ],
		 * 	 [  "WV",     1808344,      "West Virginia" ],
		 * 	 [  "WI",     5453896,      "Wisconsin"     ],
		 *   [  "WY",      493782,      "Wyoming"       ] ];
		 * this._loadFromArrayOfArrays(arrayOfJsonStates);
		 */
		var arrayOfKeys = arrayOfJsonData[0];
		for (var i = 1; i < arrayOfJsonData.length; ++i) {
			var row = arrayOfJsonData[i];
			var item = dataProvider.getNewItemToLoad();
			for (var j in row) {
				var value = row[j];
				var key = arrayOfKeys[j];
				item.load(key, value);
			}
		}
	}

	function _loadDataProviderFromArrayOfObjects(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) {
		/** 
		 * Example: 
		 * var arrayOfJsonStates = [
		 * 	 { abbr: "WA", name: "Washington" },
		 * 	 { abbr: "WV", name: "West Virginia" },
		 * 	 { abbr: "WI", name: "Wisconsin", song: "On, Wisconsin!" },
		 * 	 { abbr: "WY", name: "Wyoming", cities: ["Lander", "Cheyenne", "Laramie"] } ];
		 * this._loadFromArrayOfArrays(arrayOfJsonStates);
		 */
		// dojo.debug("_loadDataProviderFromArrayOfObjects");
		for (var i in arrayOfJsonData) {
			var row = arrayOfJsonData[i];
			var item = dataProvider.getNewItemToLoad();
			for (var key in row) {
				var value = row[key];
				if (dojo.lang.isArray(value)) {
					var arrayOfValues = value;
					for (var j in arrayOfValues) {
						value = arrayOfValues[j];
						item.load(key, value);
						// dojo.debug("loaded: " + key + " = " + value); 
					}
				} else {
					item.load(key, value);
				}
			}
		}
	}
	
}();


__CPAN_FILE__ src/data/old/format/Csv.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.old.format.Csv");
dojo.require("dojo.lang.assert");


dojo.data.old.format.Csv = new function() {

	// -------------------------------------------------------------------
	// Public functions
	// -------------------------------------------------------------------
	this.getArrayStructureFromCsvFileContents = function(/* string */ csvFileContents) {
		/**
		 * Given a string containing CSV records, this method parses
		 * the string and returns a data structure containing the parsed
		 * content.  The data structure we return is an array of length
		 * R, where R is the number of rows (lines) in the CSV data.  The 
		 * return array contains one sub-array for each CSV line, and each 
		 * sub-array contains C string values, where C is the number of 
		 * columns in the CSV data.
		 * 
		 * For example, given this CSV string as input:
		 * <pre>
		 *   "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
		 * </pre>
		 * We will return this data structure:
		 * <pre>
		 *   [["Title", "Year", "Producer"]
		 *    ["Alien", "1979", "Ridley Scott"],  
		 *    ["Blade Runner", "1982", "Ridley Scott"]]
		 * </pre>
		 */
		dojo.lang.assertType(csvFileContents, String);
		
		var lineEndingCharacters = new RegExp("\r\n|\n|\r");
		var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
		var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
		var doubleQuotes = new RegExp('""','g');
		var arrayOfOutputRecords = [];
		
		var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
		for (var i in arrayOfInputLines) {
			var singleLine = arrayOfInputLines[i];
			if (singleLine.length > 0) {
				var listOfFields = singleLine.split(',');
				var j = 0;
				while (j < listOfFields.length) {
					var space_field_space = listOfFields[j];
					var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
					var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
					var firstChar = field.charAt(0);
					var lastChar = field.charAt(field.length - 1);
					var secondToLastChar = field.charAt(field.length - 2);
					var thirdToLastChar = field.charAt(field.length - 3);
					if ((firstChar == '"') && 
							((lastChar != '"') || 
							 ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) {
						if (j+1 === listOfFields.length) {
							// alert("The last field in record " + i + " is corrupted:\n" + field);
							return null;
						}
						var nextField = listOfFields[j+1];
						listOfFields[j] = field_space + ',' + nextField;
						listOfFields.splice(j+1, 1); // delete element [j+1] from the list
					} else {
						if ((firstChar == '"') && (lastChar == '"')) {
							field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
							field = field.replace(doubleQuotes, '"');   // replace "" with "
						}
						listOfFields[j] = field;
						j += 1;
					}
				}
				arrayOfOutputRecords.push(listOfFields);
			}
		}
		return arrayOfOutputRecords; // Array
	};

	this.loadDataProviderFromFileContents = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ csvFileContents) {
		dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base);
		dojo.lang.assertType(csvFileContents, String);
		var arrayOfArrays = this.getArrayStructureFromCsvFileContents(csvFileContents);
		if (arrayOfArrays) {
			var arrayOfKeys = arrayOfArrays[0];
			for (var i = 1; i < arrayOfArrays.length; ++i) {
				var row = arrayOfArrays[i];
				var item = dataProvider.getNewItemToLoad();
				for (var j in row) {
					var value = row[j];
					var key = arrayOfKeys[j];
					item.load(key, value);
				}
			}
		}
	};
	
	this.getCsvStringFromResultSet = function(/* dojo.data.old.ResultSet */ resultSet) {
		dojo.unimplemented('dojo.data.old.format.Csv.getCsvStringFromResultSet');
		var csvString = null;
		return csvString; // String
	};
	
}();

__CPAN_DIR__ src/data/csv
__CPAN_FILE__ src/data/csv/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.experimental");

dojo.experimental("dojo.data.csv.*");
dojo.kwCompoundRequire({
	common: [
		"dojo.data.csv.CsvStore",
		"dojo.data.csv.Result"
	]
});
dojo.provide("dojo.data.csv.*");


__CPAN_FILE__ src/data/csv/Result.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.csv.Result");
dojo.require("dojo.data.Result");
dojo.require("dojo.lang.assert");

dojo.declare("dojo.data.csv.Result", dojo.data.Result, {
	/* summary:
	 *   dojo.data.csv.Result implements the dojo.data.Result API.  This
	 *   is a fairly general purpose Result object that could be used
	 *   by any datastore implementation that can provide an array of items
	 *   in response to a query.
	 */
	initializer: 
		function(/* array */ arrayOfItems, /* object */ dataStore) {
			dojo.lang.assertType(arrayOfItems, Array);
			this._arrayOfItems = arrayOfItems;
			this._dataStore = dataStore;
			this._cancel = false;
			this._inProgress = false;
		},
	forEach:
		function(/* function */ callbackFunction, /* object? */ callbackObject, /* object? */ optionalKeywordArgs) {
			// summary: See dojo.data.Result.forEach()
			dojo.lang.assertType(callbackFunction, Function); 
			dojo.lang.assertType(callbackObject, Object, {optional:true}); 
			dojo.lang.assertType(optionalKeywordArgs, "pureobject", {optional:true}); 
			this._inProgress = true;
			for (var i in this._arrayOfItems) {
				var item = this._arrayOfItems[i];
				if (!this._cancel) {
					callbackFunction.call(callbackObject, item, i, this);
				}
			}
			this._inProgress = false;
			this._cancel = false;
			
			return true; // boolean
		},
	getLength:
		function() {
			// summary: See dojo.data.Result.getLength()
			return this._arrayOfItems.length; // integer
		},
	inProgress:
		function() {
			// summary: See dojo.data.Result.inProgress()
			return this._inProgress; // boolean
		},
	cancel:
		function() {
			// summary: See dojo.data.Result.cancel()
			if (this._inProgress) {
				this._cancel = true;
			}
		},
	setOnFindCompleted:
		function(/* function */ callbackFunction, /* object? */ callbackObject) {
			// summary: See dojo.data.Result.setOnFindCompleted()
			dojo.unimplemented('dojo.data.csv.Result.setOnFindCompleted');
		},
	setOnError:
		function(/* function */ errorCallbackFunction, /* object? */ callbackObject) {
			// summary: See dojo.data.Result.setOnError()
			dojo.unimplemented('dojo.data.csv.Result.setOnError');
		},
	getStore:
		function() {
			// summary: See dojo.data.Result.getStore()
			return this._dataStore; // an object that implements dojo.data.Read
		}
});


__CPAN_FILE__ src/data/csv/CsvStore.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.data.csv.CsvStore");
dojo.require("dojo.data.Read");
dojo.require("dojo.lang.assert");

dojo.declare("dojo.data.csv.CsvStore", dojo.data.Read, {
	/* summary:
	 *   The CsvStore implements the dojo.data.Read API.  
	 */
	 
	/* examples:
	 *   var csvStore = new dojo.data.csv.CsvStore({url:"movies.csv");
	 *   var csvStore = new dojo.data.csv.CsvStore({url:"http://example.com/movies.csv");
	 *   var fileContents = dojo.hostenv.getText("movies.csv");
	 *   var csvStore = new dojo.data.csv.CsvStore({string:fileContents);
	 */
	initializer: 
		function(/* object */ keywordParameters) {
			// keywordParameters: {string: String, url: String}
			this._arrayOfItems = [];
			this._loadFinished = false;
			this._csvFileUrl = keywordParameters["url"];
			this._csvFileContents = keywordParameters["string"];
		},
	get:
		function(/* item */ item, /* attribute or attribute-name-string */ attribute, /* value? */ defaultValue) {
			// summary: See dojo.data.Read.get()
			var attributeValue = item[attribute] || defaultValue;
			return attributeValue; // a literal, an item, null, or undefined (never an array)
		},
	getValues:
		function(/* item */ item, /* attribute or attribute-name-string */ attribute) {
			// summary: See dojo.data.Read.getValues()
			var array = [this.get(item, attribute)];
			return array; // an array that may contain literals and items
		},
	getAttributes:
		function(/* item */ item) {
			// summary: See dojo.data.Read.getAttributes()
			var array = this._arrayOfKeys;
			return array; // array
		},
	hasAttribute:
		function(/* item */ item, /* attribute or attribute-name-string */ attribute) {
			// summary: See dojo.data.Read.hasAttribute()
			for (var i in this._arrayOfKeys) {
				if (this._arrayOfKeys[i] == attribute) {
					return true;
				}
			}
			return false; // boolean
		},
	hasAttributeValue:
		function(/* item */ item, /* attribute or attribute-name-string */ attribute, /* anything */ value) {
			// summary: See dojo.data.Read.hasAttributeValue()
			return (this.get(item, attribute) == value); // boolean
		},
	isItem:
		function(/* anything */ something) {
			// summary: See dojo.data.Read.isItem()
			for (var i in this._arrayOfItems) {
				if (this._arrayOfItems[i] == something) {
					return true;
				}
			}
			return false; // boolean
		},
	find:
		function(/* implementation-dependent */ query, /* object */ optionalKeywordArgs ) {
			// summary: See dojo.data.Read.find()
			if (!this._loadFinished) {
				if (this._csvFileUrl) {
					this._csvFileContents = dojo.hostenv.getText(this._csvFileUrl);
				}
				var arrayOfArrays = this._getArrayOfArraysFromCsvFileContents(this._csvFileContents);
				if (arrayOfArrays.length == 0) {
					this._arrayOfKeys = [];
				} else {
					this._arrayOfKeys = arrayOfArrays[0];
				}
				this._arrayOfItems = this._getArrayOfItemsFromArrayOfArrays(arrayOfArrays);
			}
			var result = new dojo.data.csv.Result(this._arrayOfItems, this);
			return result; // dojo.data.csv.Result
		},
	getIdentity:
		function(/* item */ item) {
			// summary: See dojo.data.Read.getIdentity()
			for (var i in this._arrayOfItems) {
				if (this._arrayOfItems[i] == item) {
					return i;
				}
			}
			return null; // boolean
		},
	getByIdentity:
		function(/* string */ id) {
			// summary: See dojo.data.Read.getByIdentity()
			var i = parseInt(id);
			if (i < this._arrayOfItems.length) {
				return this._arrayOfItems[i];
			} else {
				return null;
			}
		},

	// -------------------------------------------------------------------
	// Private methods
	_getArrayOfArraysFromCsvFileContents:
		function(/* string */ csvFileContents) {
			/* summary:
			 *   Parses a string of CSV records into a nested array structure.
			 * description:
			 *   Given a string containing CSV records, this method parses
			 *   the string and returns a data structure containing the parsed
			 *   content.  The data structure we return is an array of length
			 *   R, where R is the number of rows (lines) in the CSV data.  The 
			 *   return array contains one sub-array for each CSV line, and each 
			 *   sub-array contains C string values, where C is the number of 
			 *   columns in the CSV data.
			 */
			 
			/* example:
			 *   For example, given this CSV string as input:
			 *     "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
			 *   We will return this data structure:
			 *     [["Title", "Year", "Producer"]
			 *      ["Alien", "1979", "Ridley Scott"],  
			 *      ["Blade Runner", "1982", "Ridley Scott"]]
			 */
			dojo.lang.assertType(csvFileContents, String);
			
			var lineEndingCharacters = new RegExp("\r\n|\n|\r");
			var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
			var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
			var doubleQuotes = new RegExp('""','g');
			var arrayOfOutputRecords = [];
			
			var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
			for (var i in arrayOfInputLines) {
				var singleLine = arrayOfInputLines[i];
				if (singleLine.length > 0) {
					var listOfFields = singleLine.split(',');
					var j = 0;
					while (j < listOfFields.length) {
						var space_field_space = listOfFields[j];
						var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
						var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
						var firstChar = field.charAt(0);
						var lastChar = field.charAt(field.length - 1);
						var secondToLastChar = field.charAt(field.length - 2);
						var thirdToLastChar = field.charAt(field.length - 3);
						if ((firstChar == '"') && 
								((lastChar != '"') || 
								 ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) {
							if (j+1 === listOfFields.length) {
								// alert("The last field in record " + i + " is corrupted:\n" + field);
								return null;
							}
							var nextField = listOfFields[j+1];
							listOfFields[j] = field_space + ',' + nextField;
							listOfFields.splice(j+1, 1); // delete element [j+1] from the list
						} else {
							if ((firstChar == '"') && (lastChar == '"')) {
								field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
								field = field.replace(doubleQuotes, '"');   // replace "" with "
							}
							listOfFields[j] = field;
							j += 1;
						}
					}
					arrayOfOutputRecords.push(listOfFields);
				}
			}
			return arrayOfOutputRecords; // Array
		},

	_getArrayOfItemsFromArrayOfArrays:
		function(/* array */ arrayOfArrays) {
			/* summary:
			 *   Converts a nested array structure into an array of keyword objects.
			 */
			 
			/* example:
			 *   For example, given this as input:
			 *     [["Title", "Year", "Producer"]
			 *      ["Alien", "1979", "Ridley Scott"],  
			 *      ["Blade Runner", "1982", "Ridley Scott"]]
			 *   We will return this as output:
			 *     [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"},
			 *      {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}]
			 */
			dojo.lang.assertType(arrayOfArrays, Array);
			var arrayOfItems = [];
			if (arrayOfArrays.length > 1) {
				var arrayOfKeys = arrayOfArrays[0];
				for (var i = 1; i < arrayOfArrays.length; ++i) {
					var row = arrayOfArrays[i];
					var item = {};
					for (var j in row) {
						var value = row[j];
						var key = arrayOfKeys[j];
						item[key] = value;
					}
					arrayOfItems.push(item);
				}
			}
			return arrayOfItems; // Array
		}
});


__CPAN_DIR__ src/storage
__CPAN_FILE__ src/storage/browser.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.storage.browser");

dojo.require("dojo.storage");
dojo.require("dojo.flash");
dojo.require("dojo.json");
dojo.require("dojo.uri.*");

/** 
		Storage provider that uses features in Flash to achieve permanent storage.
		
		@author Brad Neuberg, bkn3@columbia.edu 
*/
dojo.storage.browser.FlashStorageProvider = function(){
}

dojo.inherits(dojo.storage.browser.FlashStorageProvider, dojo.storage);

// instance methods and properties
dojo.lang.extend(dojo.storage.browser.FlashStorageProvider, {
	"namespace": "default",
	initialized: false,
	_available: null,
	_statusHandler: null,
	
	initialize: function(){
		if(djConfig["disableFlashStorage"] == true){
			return;
		}
		
		// initialize our Flash
		var loadedListener = function(){
			dojo.storage._flashLoaded();
		}
		dojo.flash.addLoadedListener(loadedListener);
		var swfloc6 = dojo.uri.dojoUri("Storage_version6.swf").toString();
		var swfloc8 = dojo.uri.dojoUri("Storage_version8.swf").toString();
		dojo.flash.setSwf({flash6: swfloc6, flash8: swfloc8, visible: false});
	},
	
	isAvailable: function(){
		if(djConfig["disableFlashStorage"] == true){
			this._available = false;
		}
		
		return this._available;
	},
	
	setNamespace: function(ns){
		this["namespace"] = ns;
	},

	put: function(key, value, resultsHandler){
		if(this.isValidKey(key) == false){
			dojo.raise("Invalid key given: " + key);
		}
			
		this._statusHandler = resultsHandler;
		
		// serialize the value
		// Handle strings differently so they have better performance
		if(dojo.lang.isString(value)){
			value = "string:" + value;
		}else{
			value = dojo.json.serialize(value);
		}
		
		dojo.flash.comm.put(key, value, this["namespace"]);
	},

	get: function(key){
		if(this.isValidKey(key) == false){
			dojo.raise("Invalid key given: " + key);
		}
		
		var results = dojo.flash.comm.get(key, this["namespace"]);

		if(results == ""){
			return null;
		}
    
		// destringify the content back into a 
		// real JavaScript object
		// Handle strings differently so they have better performance
		if(!dojo.lang.isUndefined(results) && results != null 
			 && /^string:/.test(results)){
			results = results.substring("string:".length);
		}else{
			results = dojo.json.evalJson(results);
		}
    
		return results;
	},

	getKeys: function(){
		var results = dojo.flash.comm.getKeys(this["namespace"]);
		
		if(results == ""){
			return [];
		}

		// the results are returned comma seperated; split them
		return results.split(",");
	},

	clear: function(){
		dojo.flash.comm.clear(this["namespace"]);
	},
	
	remove: function(key){
	},
	
	isPermanent: function(){
		return true;
	},

	getMaximumSize: function(){
		return dojo.storage.SIZE_NO_LIMIT;
	},

	hasSettingsUI: function(){
		return true;
	},

	showSettingsUI: function(){
		dojo.flash.comm.showSettings();
		dojo.flash.obj.setVisible(true);
		dojo.flash.obj.center();
	},

	hideSettingsUI: function(){
		// hide the dialog
		dojo.flash.obj.setVisible(false);
		
		// call anyone who wants to know the dialog is
		// now hidden
		if(dojo.storage.onHideSettingsUI != null &&
			!dojo.lang.isUndefined(dojo.storage.onHideSettingsUI)){
			dojo.storage.onHideSettingsUI.call(null);	
		}
	},
	
	/** 
			The provider name as a string, such as 
			"dojo.storage.FlashStorageProvider". 
	*/
	getType: function(){
		return "dojo.storage.FlashStorageProvider";
	},
	
	/** Called when the Flash is finished loading. */
	_flashLoaded: function(){
		this.initialized = true;

		// indicate that this storage provider is now loaded
		dojo.storage.manager.loaded();
	},
	
	/** 
			Called if the storage system needs to tell us about the status
			of a put() request. 
	*/
	_onStatus: function(statusResult, key){
		var ds = dojo.storage;
		var dfo = dojo.flash.obj;
		//dojo.debug("_onStatus, statusResult="+statusResult+", key="+key);
		if(statusResult == ds.PENDING){
			dfo.center();
			dfo.setVisible(true);
		}else{
			dfo.setVisible(false);
		}
		
		if((!dj_undef("_statusHandler", ds))&&(ds._statusHandler != null)){
			ds._statusHandler.call(null, statusResult, key);		
		}
	}
});

// register the existence of our storage providers
dojo.storage.manager.register("dojo.storage.browser.FlashStorageProvider",
								new dojo.storage.browser.FlashStorageProvider());

// now that we are loaded and registered tell the storage manager to initialize
// itself
dojo.storage.manager.initialize();

__CPAN_FILE__ src/storage/dashboard.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.storage");
dojo.require("dojo.json");
dojo.provide("dojo.storage.dashboard");

dojo.storage.dashboard.StorageProvider = function(){
	this.initialized = false;
}

dojo.inherits(dojo.storage.dashboard.StorageProvider, dojo.storage.StorageProvider);

dojo.lang.extend(dojo.storage.dashboard.StorageProvider, {
	storageOnLoad: function(){
		this.initialized = true;
	},

	set: function(key, value, ns){
		if (ns && widget.system){
			widget.system("/bin/mkdir " + ns);
			var system = widget.system("/bin/echo " + value + " >" + ns + "/" + key);
			if(system.errorString){
				return false;
			}
			return true;
		}

		return widget.setPreferenceForKey(dojo.json.serialize(value), key);
	},

	get: function(key, ns){
		if (ns && widget.system) {
			var system = widget.system("/bin/cat " + ns + "/" + key);
			if(system.errorString){
				return "";
			}
			return system.outputString;
		}

		return dojo.json.evalJson(widget.preferenceForKey(key));
	}
});

dojo.storage.setProvider(new dojo.storage.dashboard.StorageProvider());

__CPAN_FILE__ src/storage/storage_dialog.fla
ÐÏà¡±á>þÿ	þÿÿÿ	
�ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRoot Entryÿÿÿÿÿÿÿÿpª|YªrÏƒRASH°™ !eÆÀContentsÿÿÿÿÿÿÿÿÿÿÿÿ{jPage 1ÿÿÿÿÿÿÿÿÿÿÿÿ¿Media 1ÿÿÿÿþÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿýÿÿÿýÿÿÿ
BþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRoot Entryÿÿÿÿÿÿÿÿpª|YªrÏƒRASH°:73ºdÆÀContentsÿÿÿÿÿÿÿÿÿÿÿÿ{jPage 1ÿÿÿÿÿÿÿÿÿÿÿÿ¿Media 1ÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿýÿÿÿýÿÿÿýÿÿÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€	

 !"#$%&'()*+,-./0123456789:;<=>?@A…ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†‡ˆ‰‹ÿÿÿÿ�ÿÿÿÿŽ��‘’“”þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ	

 !"#$%&'()*+,-./0123456789:þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ8ÿÿ
CDocumentPagePage 1ÿþÿScene 1ÿþÿ8">D¼ÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿöðGDÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿÿCSwfPageMedia 1ÿþÿButtonÿþÿ	ëW?·Ô±CÿþÿButtonÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿþÿButtonÿþÿmx.controls.Buttonÿþÿ‚C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\TMP3yjbts6p08..swf]oCWSç’xœÌ;	l\×q³ÿÿ].)’")R«ƒÔE¦,Ëº,É‡¨ƒ‡DYÚ•—ò!_ëÏÝOî—þÞýÉ&i”Ä‰
§¥#a";NU
œIÑºpÚ&­Ü´5ê¶ìê¢hÔ…Ñ´Hš44ÝÎÌ{ï»+Å(£´üoÞ¼y3ófæÍ{oò_‚ŽW¡=#Z­V»
{ '"×`ÿ^¾|ºÚÿ"²X{ë_õ…ïn~lâ�Õ‹Ÿ)î<±ü‹ÿ¼ø¯?N=`ÿñ×^¿µÖ.¨á�OÅbüG°}¸s9“ÓàØ¬ë–ŠÙR®Â~ê8Çg`aÖº:Ú?~9ý±ýN~rtðó?q.oyýÙoü×…Èk•‡ŸüèW?;öWÏýÆ�¯ÜúCœæqkà¨ÃúCøµÔàæ­‚5RrJú¶«Ð¿Ô
-öBa-Õv±
É¥^F´r“sp`ÑE8rYµ\îštÒ	!‡®äèc9H›9»tÖ›q�”&êiŒ¥é»UíL{ñÅ¥¸ýšõÂÿüÛ;ÅGôáÌ�Ÿ}äs¯±²?Û4qÏ‹ðgRšØ&M4,M¬^šÝ(Íìj�3ð;»¦¤9ùÀ�Ÿýû7·¿òèÁ¡_}g›ÖºýÊ¶¤d>þ�1ß¢˜ïeæã0éZå0ïýØÓZ¿-OV6~³ëoç‹ß’,·}`,·†õÝ#y+{!Èóaýô›§úµ	À9\³˜µ&Fa¶˜³¦í¢•CÍò–=“waÎÎ¹y@rqÞ*”¦ÎÓ¼“ö/YPu+8hž> ›7+G]Ø€ówà¤ŽUœÁqvu²lfuv
‘ìâ­ywqIÀ2wVá(›•ªåÙjvÀGàd	§¦¶ÁÃð!ÑŸš:oe]xH´ŽV*æ‚øœ¤ñ· )Â®ylÏZ0m:HYÉé}ÜÏb©Ö	!kÆ±/Zg*ÖEÛš;mV/@¶b™®5V(»§Kqì2‰/:Å˜²fìâ¸í8P(]´Î–ÀAâ«˜chæ¢]µ§p}2ó�YÙB}Ïgó€Ï@n¶ìØYœÇŸbÚ1«yÇrqQ¬jÖ,[P*Þ[Î!Ž÷qzÖqm0{¦gOb9H gA±4IßÈG—¤ÒÌ\î¬
dfœÒ”éàâœòåEÂi«JËš©”J.,v"äTÉÌQ„=c°d€‰CrtIƒxd¢ç
v}kýô«'ýo#‰Ìæ�2 Æ�-éÄó¾¬âñq²÷–a·2v[zxq…g:È·C•µ_²°lâÎÝ
	Ñl7;ÂÍÎ‰áÅ¾ e`<ÝZ¾KiŸÄ]#!?ô:aä¢'†4-¾<y‚äE–!€yEh[Úc¼ëP!Dá²]$•9Ã°ý{5b…ˆˆI�„îM3CÃö2t&µŒ"Á�'àŸoÔ–:pr£	änÔZOÐ«€w0 æ2_ºxÏ¡ i¤¼œ´ÇÿúÏ ù·jH,àg@jû	5tL‰ãS]q¨a\Ï^6–®À¤ }x‰DÁž/À
‰ôÂ‰4Ö›&4£ÇW¦ÞÄBd¶1�€ƒÒš¾bëP­	>Ñƒñ7Ïí`G‚ªÁÙ¢ï�#”BG)tf(ÆvÖ±ª©’¢ž’~Ô¨$á;­_-|MxÏš´½…,³«Ú„'ß×¥ÌÂãcºiŒAö�Kû>>Ð¸:;DÔ0=õž„
HÖTýÚ�ÔoÔ„”úe”Ç,n;ü;GŽµbÏÀ=…ô7*d)
R4ß‡AèGx\}ø¡ßæú$Y¼¡y˜^¸
)ïx@Ú~Ù©òrÐsï¯‘µæëÐl4©A^ì�»$»âw"ïÝþ×±(k‚¦Ä]hXàm¸1ÞF…×c¼M‡†…ž„(Ò~g„&ÃŠL¢KDôpØ^nö†›‰‰º`«�á¹°ýŒ¶MTë-ó ´ebßÐ0!ó˜WñEØÀæ‰S4Q�˜WÇNV„É0ëa©â[ÀE(Öå2êrÔVßÛ£‘aÛ€Á0‡™“dè¥"eVboGRça¹†Æ¿‰w^IT“»ª¡'…†ã¤“!ú—<™­íô�Z¬Ü�YoCÉ‰Rä
�ÆªËŽíIá¿Qm5@å¥ˆŒÛ·us0À=±ƒ�B·7Ç¡ÿ¸7(ß‘N©A��í$Õák]t#É�O@åþ’hAŒ[c­ßy¬]uôë$H»Ó‰HÛˆÓs½Ùv¿'žv_Gæ=iŽÿÿCPicPageÿÿ	CPicLayerÿÿ	CPicFrameÿÿCPicSwf%	I}vÿþÿÿþÿcloseButton	ÿþÿiconÿþÿÿþÿiconöƒFôÈÿ¾L“ì¡sÎ¶ÿþÿÿþÿlabelÿþÿFinishedÿþÿlabelE»b[cF•EÀ\G½ŒÿþÿÿþÿlabelPlacementÿþÿleftÿþÿrightÿþÿtopÿþÿbottomÿþÿlabelPlacementå•¢T åIŸÄß^æãD©ÿþÿÿþÿselectedÿþÿfalseÿþÿselectedî/Ï?ëZJ�ñ…ƒ|úìgÿþÿÿþÿtoggleÿþÿfalseÿþÿtoggleg¿¥íY˜D¾ê±Ìœ²ÿþÿÿþÿenabledÿþÿtrueÿþÿenabled!º—À­RG¸5S8ìêbmÿþÿOtherÿþÿvisibleÿþÿtrueÿþÿvisibleD*Lc³XTC¦$úv±¢ÿþÿOtherÿþÿ	minHeightÿþÿ0ÿþÿ	minHeightÃP¬»¸K¨‰u@•&ÓjÿþÿSizeÿþÿminWidthÿþÿ0ÿþÿminWidth!7“C2«I”»¼ú l/›ÿþÿSizeÿþÿÿ<component metaDataFetched='true' schemaUrl='' schemaOperation='' sceneRootLabel='Scene 1' oldCopiedComponentPath='1'>
	<eventMap>
		<property name="selected" value="click" />
	</eventMap>
	<property name="selected">
<schema name="Boolean" base="Boolean" class="mx.data.types.Bool" required="true" readonly="false" writeonly="false" category="simple" original="true">
			<properties>
				<property name="defaultLabel" value="" />
				<property name="defaultUIControl" value="" />
			</properties>
		</schema>
	</property>
</component>
ÿÿCPicText€€/Xÿþÿ
ð_sansÿ(Press Finished when doneÿþÿÿþÿÿþÿ€€îîîÿÿó_!l¡Þ0”ê0_!0lÿÿÿ?ÿÿÿþÿZzÿþÿÿV// know when the close button is pressed; this is needed as a workaround when

// showing the storage configuration dialog, since there is no way we can

// know when that panel's close button is pressed

closeButton.onMouseDown = function(){

	// some versions of Flash don't have access to containing parents 

	// objects, like DojoExternalInterface; only Flash 8 seems to have access

	if(typeof DojoExternalInterface != "undefined"){ // flash 8

		DojoExternalInterface.call("dojo.storage.hideSettingsUI", null);

	}else{ // flash 6

		fscommand("call", "dojo.storage.hideSettingsUI");

	}

};ÿþÿ€€ÿþÿLayer 1ÿÿÿÿOÿOÿ€€", "dojo.storage.hideSettingsUI");

};ÿþÿ€€ÿþÿLayer 1ÿÿÿÿOÿOÿ€€ÿþÿrightÿþÿtopÿþÿbottomÿþÿlabelPlacementå•¢T åIŸÄß^æãD©ÿþÿÿþÿselectedÿþÿ8ÿÿ
CDocumentPagePage 1ÿþÿScene 1ÿþÿ8">D¼ÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿöðGDÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿÿCSwfPageMedia 1ÿþÿButtonÿþÿ	ëW?·Ô±CÿþÿButtonÿþÿÿþÿÿþÿÿþÿÿÿÿÿÿþÿButtonÿþÿmx.controls.Buttonÿþÿ‚C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\TMP3yjbts6p08..swf]oCWSç’xœÌ;	l\×q³ÿÿ].)’")R«ƒÔE¦,Ëº,É‡¨ƒ‡DYÚ•—ò!_ëÏÝOî—þÞýÉ&i”Ä‰
§¥#a";NU
œIÑºpÚ&­Ü´5ê¶ìê¢hÔ…Ñ´Hš44ÝÎÌ{ï»+Å(£´üoÞ¼y3ófæÍ{oò_‚ŽW¡=#Z­V»
{ '"×`ÿ^¾|ºÚÿ"²X{ë_õ…ïn~lâ�Õ‹Ÿ)î<±ü‹ÿ¼ø¯?N=`ÿñ×^¿µÖ.¨á�OÅbüG°}¸s9“ÓàØ¬ë–ŠÙR®Â~ê8Çg`aÖº:Ú?~9ý±ýN~rtðó?q.oyýÙoü×…Èk•‡ŸüèW?;öWÏýÆ�¯ÜúCœæqkà¨ÃúCøµÔàæ­‚5RrJú¶«Ð¿Ô
-öBa-Õv±
É¥^F´r“sp`ÑE8rYµ\îštÒ	!‡®äèc9H›9»tÖ›q�”&êiŒ¥é»UíL{ñÅ¥¸ýšõÂÿüÛ;ÅGôáÌ�Ÿ}äs¯±²?Û4qÏ‹ðgRšØ&M4,M¬^šÝ(Íìj�3ð;»¦¤9ùÀ�Ÿýû7·¿òèÁ¡_}g›ÖºýÊ¶¤d>þ�1ß¢˜ïeæã0éZå0ïýØÓZ¿-OV6~³ëoç‹ß’,·}`,·†õÝ#y+{!Èóaýô›§úµ	À9\³˜µ&Fa¶˜³¦í¢•CÍò–=“waÎÎ¹y@rqÞ*”¦ÎÓ¼“ö/YPu+8hž> ›7+G]Ø€ówà¤ŽUœÁqvu²lfuv
‘ìâ­ywqIÀ2wVá(›•ªåÙjvÀGàd	§¦¶ÁÃð!ÑŸš:oe]xH´ŽV*æ‚øœ¤ñ· )Â®ylÏZ0m:HYÉé}ÜÏb©Ö	!kÆ±/Zg*ÖEÛš;mV/@¶b™®5V(»§Kqì2‰/:Å˜²fìâ¸í8P(]´Î–ÀAâ«˜chæ¢]µ§p}2ó�YÙB}Ïgó€Ï@n¶ìØYœÇŸbÚ1«yÇrqQ¬jÖ,[P*Þ[Î!Ž÷qzÖqm0{¦gOb9H gA±4IßÈG—¤ÒÌ\î¬
dfœÒ”éàâœòåEÂi«JËš©”J.,v"äTÉÌQ„=c°d€‰CrtIƒxd¢ç
v}kýô«'ýo#‰Ìæ�2 Æ�-éÄó¾¬âñq²÷–a·2v[zxq…g:È·C•µ_²°lâÎÝ
	Ñl7;ÂÍÎ‰áÅ¾ e`<ÝZ¾KiŸÄ]#!?ô:aä¢'†4-¾<y‚äE–!€yEh[Úc¼ëP!Dá²]$•9Ã°ý{5b…ˆˆI�„îM3CÃö2t&µŒ"Á�'àŸoÔ–:pr£	änÔZOÐ«€w0 æ2_ºxÏ¡ i¤¼œ´ÇÿúÏ ù·jH,àg@jû	5tL‰ãS]q¨a\Ï^6–®À¤ }x‰DÁž/À
‰ôÂ‰4Ö›&4£ÇW¦ÞÄBd¶1�€ƒÒš¾bëP­	>Ñƒñ7Ïí`G‚ªÁÙ¢ï�#”BG)tf(ÆvÖ±ª©’¢ž’~Ô¨$á;­_-|MxÏš´½…,³«Ú„'ß×¥ÌÂãcºiŒAö�Kû>>Ð¸:;DÔ0=õž„
HÖTýÚ�ÔoÔ„”úe”Ç,n;ü;GŽµbÏÀ=…ô7*d)
R4ß‡AèGx\}ø¡ßæú$Y¼¡y˜^¸
)ïx@Ú~Ù©òrÐsï¯‘µæëÐl4©A^ì�»$»âw"ïÝþ×±(k‚¦Ä]hXàm¸1ÞF…×c¼M‡†…ž„(Ò~g„&ÃŠL¢KDôpØ^nö†›‰‰º`«�á¹°ýŒ¶MTë-ó ´ebßÐ0!ó˜WñEØÀæ‰S4Q�˜WÇNV„É0ëa©â[ÀE(Öå2êrÔVßÛ£‘aÛ€Á0‡™“dè¥"eVboGRça¹†Æ¿‰w^IT“»ª¡'…†ã¤“!ú—<™­íô�Z¬Ü�YoCÉ‰Rä
�ÆªËŽíIá¿Qm5@å¥ˆŒÛ·us0À=±ƒ�B·7Ç¡ÿ¸7(ß‘N©A��í$Õák]t#É�O@åþ’hAŒ[c­ßy¬]uôë$H»Ó‰HÛˆÓs½Ùv¿'žv_Gæ=iŽªZ|o4’ºÜçaIÀm>€�d´bÎ)#Áäì2®ïOª$M,çðŒ…R0´÷½QH)\µˆÒ™¦4¶ýÉã>~¨¼žˆ´µýMašÎMñXtV×ÙoKÀ~[’<÷ß@“­‘ôß‹ß”¿hˆV`O§¼,NÝFünaý½�ÐsP©|M:H“
5K�ÐbxN®‰]O“{š†ó1Ùd
ÃÈ'kJl“Ï“E’Y--:Ô¥µ·§C2)µ!•þH°ÃóÞR0½Q0^þ;’4ÔZ�Vn{áñÎCÏãqo–&™€Áœ!9ú=9b“t#†™BŒ§ýn-dûzü®tb±Ë?Õ ×œ‡T¤þŒ!S¢àô‡ÄîR§Ã9on¶#ú¾é0ì@ž6£,Ö‡BÚ¬þ_µÉfaè!‰¶za&pQ1ÿ2fà/k!jA³¼K˜%žÈÐ ‡ã‡S~ëHü(–ø1äÈJ3âÇü³˜8Ê�
*c<nœ|^`áïñÅ8Àûy8dÚ'&Z·ôwJÈ»¢eðÝ!_Š¦t‘LOOwßöÌ•Ÿ®]åþÑ“#ïºxIÞ¶«ÛÁeê^„ „+Ís˜Q+Í_zO¨°«
®Dà‰'ž€®ÞW‡Þzùèé¾};�>�a;ùbçaüZZPÍ›¹ÒÜ/èf§CIÐÁ¼vÂ±J®2™ÏÍIF—KFðý £>ôæËãoD÷�•Œv…�â«Ñ_£ËÃŒv1£ãt˜¯µÞ† n^�uâ×Vãº\E–¶‚`:ŽxûUXcõLÓ0AM\huÃ¤](;–¸Ü-Í¥ø=R|úÅ�¼5yì�µûz¥ø+Ââ—*9«ò¿G‰ßÎ¯`ñ�9�Ï
é
/tõ=sÖ}þÍw?Ñù…]ï~�_:n÷1¿âw%@ÞžÉ;tGõþ³ü4±Ü_;þÒC×ç}Ìö	Û¡›±&6×tu§´2¸º+à¯kµ?‘«Û-V·Þ¾)\]ÛE0¹ÞÖ(Ò~ûjíëžQ¦ÐB¦ðkµ_©ý÷À±KSXÁS¯™ÂD±‰Ê›pÙT–È�–&Á.WJó-M) Ûï5ò(9Jl–ïUüa±=m´�6®�kØQr·‰KŽ ™Ü‰�Ü÷–‘/
Å«°+èw«`Ôš61«J„ÕB‚VÃ½âRclÞµŠU»T$ÔØ¹44?2®òéØJ"×óÎ.4Zlè8´·ÿ•+áùÖxäÐÒ7"h-dþsô{ï�ëB/ÝŽwïý§‘/¾T}öG•¿;‚h›±£¿­¶·Ö}[¾xÉÑƒp5~ˆöNŠúZB4Úûù
ÙŒ†ímÊ7Pw®9uÂ,æ«B†Þ<Æ×ZºŽ—´O,i;Å#SÈJ);yø:/eg«i³‰äµÖq­¨O®t„¸GŽFÌ²;[¡¥Ã0kv¬úÊÇº"èŠ¨Ù5Ðõ\E)¶›É¯Sž6‹æÊ"sƒ·˜kiò0R*”KEôõÐzÞŽý×s
ôüVR¬g§èýÙ¥kÜhER+wß“�„öË�AòH”òûM!)×(íýÁñß~æ±F’¸OÓÄÝÐýÐOå¼+!qæ£ïr£íº÷[µ+ÜHà„+ÿcä¥°"6…¿¹ú×!h0$íÓBÚ®ÊsŠÚ26ˆ†@Û@#@PÙÜHeçÛ‘PœÜd
Þ@Zš-FÙ"_")#Ê÷IQÍU÷:&½—šªîjì)àôpò°‰]Eÿ‚·Shw�+QL2ÛÐØJ33ã£œr‚U4§êŒpS=KP³`å#H Q]ÁpñTâƒù—h5j£÷µ�oàõZ‹zè}í«¢1€‹FPÝ[¥Po=ì�LßÆ¯/S¿,ù2}™dB]ÚôxK¼ &sÊBY%•�¥„�q0@òaàƒÖ‰éíÛÀ.«µæMŒt¸ófÖÃM�Éœ1³Ð—«;ó;yÓÞÙd¿®u&tüÔ‹è2êÑ·ziêb³o2®\)¹%w¡ly›½À¢fúø1ÈUÌ9Èd4c¹"(Ç�çÊxÅ,Ð+ÙEÓ±éd&:ÃICÁž§™�NNZî™J©<î˜3UÎö�“÷ˆ8×¯R <iDü,^;’JqÅù€G¬¡qúÏ'N<ú_ø´	8Œç£b0¬øÞÏÉÀÍhlq¿°�ž¥‹Ž§0];7ñ}¥¸‚�·ñž tu@ŒÓ�…©´.vr½ÁÀ}%;;äq¨Í¿òŠÄ—¥�žª¢üx¥§$‘Ž:" nWÚi‚dJrß¹˜ ÷Ð·C¤ZÖ_“ý9ñ<É°6àç«x›¡¥ÄW,¬þ]žg0‰Òq]”…Òz]ä3ðJÓ(s
½…Xî/jˆÒ$](1ºÖdŠ(Ÿùö¥‚Â³†¤gm`Ïªó¬,zÆNkè|y�F<õû-¿ÛÄ�ÙßGÐƒ«ne6ëÊ¶ïSþ+m&ƒÞ“ÉˆrõGÀäã¹÷W@kÚåw`Ñô>ÜR™Þ†eËûÁ,S6+äÕ!úS%Œ�õF� Ó^ÄÊøÁ«‚‹‘… 2"Àe¼PW
B=ª]
µ±uŸzîV!••–·sT¬‹ª<gWË¦›Í�]$±$Iï•\Pô›ÜË¯Û êøC!)hçê±çäJ§0˜U `¹ùRî,Å~›´íLEéA(Ê!£’[ìGEŠx(RYéPÍÛ¸¸Yª&pŽ:Î¨]
jˆªî4=É‹pLÅxZÈ=@?ç¼Ïº”%ñ}E<Ô#¦P;~È%$Zœ™†‹DÃ)Þ?Å÷YkÞ·-'§6—žåé‹yB›Ä6T‰Ï$iCŒRÅ®kfóì²cÄ1«Uµ/-¦J�Ÿ©9ª:¨X3T€PaÔ`e…–³ÐáJª…K:j•Q¶©YÛÉñ§XµÙ2LÛÅ\Ù;zÑ´
ÌêœYæ¯*ÎEòûžJ»n�£Ì•�£?UV2ed´‘¦™»Ê‚ÜUƒÛ©b\µë<R
ŸGÑGQ•ávV~Œ0U]›«­ˆÍf­*ZºíØîÂe¶4ƒébâ«˜› Te4ÉÒ�¯”
$Õ“ì”�,næÍ*êœ¶f«â.ˆ*)!6Êž5Ñ3(ÇdS¬Š•ÎâªZ¤,^#îµ²fŽ²œ)b´lŽU3™™ŒŸ„°£²á•*ÓEû­Î5~ƒ‰[¤ƒXÓ˜NñÏ¸Y°�þd÷¦Kaõ´Y™Á)ðŸSg9z†ÀivÛE}f
vC´Ð7ï>$jjÈþ�ò•"áü˜ŸT*U!×b 
_’²[…)+7^¢ÌO–;±6 NðÀ§ÊC1(òÇH8+S¬uÕÁã3»:QÄ¸d»jLÓ¬ÊŒUg(ñ‡Ý³sþoï�!D¡/1=žRÇ$_*û»„ìæ¼™óT®XÓV£ìðÚ¢[îZf.çÙ¦ã-Èp.#6í‰ó°ðÿ.Ë,­mÈ2Å=¸Nç!<x^øô†gÈh:!rÑzÌGÌçƒ3ÎˆÌ
ãò¦}Zeš×š–}m
}Ë¼¾ö†¾¯¯ó}Ëúº¼¾îôõx}Ûeß
–®7©f¨SG<}|™Üw�Á+“jšºÁm�Á‰ºìYñ¶ÊãmµHõõ!Ðò^j¼
ScÙ¿Æ›¾ê&J¤‘µA"ƒJvW7,öšô°:"ô_‡¿�¿u>é9�¿Ÿ¿õ×ç¯ßãoC�Hëø[ïó·q±—ÎQ8F±$r³G@Uªl’/ÊwKÆ6Ñ™GQùJ·‡«A
M<¨x‚ë]èk½ #�ãÀVïø´­Á¢6yZ¹Éh¶�àQIlli›/ÒPÙíÙ›ƒd¤LÛI¦ºªŸÜŽr·xävúä<r·4’Ûá“»u±›Ž'O�2PSÐs’î.ÿ×tbB�vá§»=T0€‡Q­N­»Øgö¥eUÈmü–¯lh¿°BCYáoÊo»Cž‡$E½KßUÄ.ùˆÝŒ)®k¹=|Z�‘%T¢@KKÔ½ßÁO¬BXÂÜu{ä“ëÞdšj{®Ö¤wÖyÓ@@Ž&¬ÉQwÕ�JÈ…:àU2„µu¨¿A-wy&|�V3BîcLuæÌ…*|	”JOq¥�x0'1ŸðæÅ}ÀS
#'CoÀ·xoÀZ½¡'¹î‰Wû0kçOku(¦:²Áøá8ßáçÛˆsTmÈºeÐ!>-ó[€¨
�y[…WßD�Ù«6À£E^t1&U!ãQ7±s$~ÿº±~]¶F|æ –÷9¨HF“µ�%½âDìñ8#Â:–ÜÀÓñø	´³	t¨ëó4^gkä
M+³#Mh³£Lèäâ*z¢ˆ
�>¿ƒÃnˆÎïca<(Ê¦¤#êÝËU�Sb4�èu-‘“Ÿ^\K:¤ÉùÜÍñ1Éà“Ý÷`iw“’¥Æ#Š´c‚vRÆ¯òŒë–RM.kÎˆË"-¾‰Œœ¿î1Œ”²ò†7ÊÀ<4ƒXRuaáPCØ¿KÕP¥
®P04š'‡ä
˜ßÒÍ§Ò®ŸÔ‡N'#ŠÁ+Ép¾(ªÓàZÖÛ[ï]ÜF”Ð$5ÿ E:-‚NLÑù’,m½Oˆé×wÈkEÞRµøý¬¨ûüjQñŠÒF9ˆ±ZA±4™ö
p˜äMr¾û“Þßë¦¤ä9·¸Bí@(„.„Øªh¨nM[ÅÕéÁÓÈƒ‹íä-C({žžiÄ’�ñJ‹?ª¹ájúT}<}X
¶â�†_F''~4í—÷ø•ôê:6ÓP^÷˜²ÖØÊ%ÌÅµQ»æŒ(8Fð”¦J°ìâ ðœˆAhzÐr¢´Ì)\æ¢T{Žë¾Mï?»·XÓ¤?é¢õø;“æm‹êª
vÌ´�Î[sÅ[^ˆ@WÖÄÛ­Ð
SÊ§ET1áœÒ„/¢Ý,îŸ¯‹pýõ+d§e�½€{¦­ô9©TÇ×H”S€á:b…7>ß)6@J*)s®ÒGòG#Jþƒ¼Þ`§~\pUÜ¾!Jp…á…7ãJx3>ÜŒƒ‰u5Ý£êµ¢AˆuäÚq¥ö”ü¸ƒØ{©æåIh:×�à\1¹Ë)ä9�â?Uƒ}S%H!¥>$Wø—åV5jðc‚hŒÑv%9‹Ïú«•¨×ÞãÍ•:«ê�/&YôP@Ÿt9É¼R¾dëSâÿ)#tÆÿÛÞ›@Çu]‚¿ª~UýÂ¾‘ @�àN‚ûN‘wˆ $ª@�”dI¶ÀP  ‚(ˆ¤¼È²%“^ÂX^˜flyë8Þí8Nœ3Ó9™¤“žvÔîé%�ÌØŸô™Lwr<Óé>>í8‹#Ì»Ë[ÿÿ…‚D¹™±uTàÛ—ûÞï¾»^Ï±À zÖýÎzø|›•¡t
Œºöƒ·çUO¾ìILì%	µw|Ñx"*©�â�7[àœ¬…Ã`ÌË
ünÒÛœ¦¼+øý>—'ÙM1è€Gð1O+©Ã‡¼ÿ>o/ø�Zpº+²gP¾<¶2Í‹‘fQ
b��` ’ac|dþ–4O³€f5£úoÉ×:ªo$C£úd’`ön.F‡¹€YZ¯Ë6¦aÌSIzR¼‡„ð¥ðÿÆB·¨™B:Ôº‡k�rj½SëE¬•äZïuj½7¦Ö{Iø2Aµ®;µnÄÔº�µnq­÷9µÞSëýXë×ú€SëƒF­eF­”û¡î:®ûNÝ›1uouÿÒ£º¿èÔýPÌh?„£ýu®õ’SëÃ1µ>ŒµÞÎµ>âÔúhÌ8?jŒó×ý˜S÷c1=~{¬Q‡vN‚ä?@ƒ(û>>uaŸæpŸæ¸™)üVs(êz‹’VÐ©—Nˆ±•\ðÎAÙêë4ÊZçV3
‰Æ¹	5¦ûÜø*¨ÁÁÕhøØMÖ„š‘ãy&Ïbº’Ø¦ÆÕÅ„_"­‘ãYþ/…
J„ãŸ8´‰&G¨ÖŽÓêqÉ#–ðíc¿½*üæ�'¸‚Ò÷Ï1q*ü2ÞL$â½0…àãòÖþÄ z3&ƒ÷‚B›ùlxY^ <ÚçÍí`�s'�ÓÜí.!ãåÁ#·�…¾Â]Y8Ucì‰Gö	@ÛÅu#®£²ä’xK“úº	 ÃOÂ/–ÑßèŠ©W"íˆ1¥N)ÃeÎá@3æ”:Ïdô4#¡'F·ÑÚÝˆügÛ�²YiãN'H„0BÜÏY,™å’õØ|V7¾c7ÿJmP×WÔ§Ïà•Ù^±Ô§¡û„Ú ¡›ŠèMé¸¦5\Íõí6¡'WWÃ°•aˆ_�9UÙ!áy¬xI“f@¼WK±ÔÈg`7'Qñ¹‚#û	ïŠÑÞà=Ç$£‚èCâ¾äÅÓ2ð9ô˜óLääÏÿtàV;„Îï%(ÓwGäÊƒþ26Á¯`&ê:%‚ÏÊOXîW¡Ü!Ä’ƒÏSk_ ¾Hÿ|‰þù2ýóúç«Ôa;”r@´2Kòp|M¾+¿>hg×`öÒ¸ì:Ìþ5�MÉË™MÑ‰Ù_p³Wqv7f1®ñÌþ†[{‹ÖPÙ¿îfoçì­˜ýÍ¸Æ1û7ÜÚ›¸öFÌþ|\í³Ûâ²0û7ã²›1û[FßD}2ZÔç·”¨ÏflíhH'D,JˆÎ–žûrjÝøšøBâ¤ç¢Åæ´à€Ëû·…,ÁWrEqNA²ƒŒ?(©ê`™Ž»�ÅYÒ1ó£Ók¶Yœ‰TE†fZ÷šÑM/ÈÞì )‘DÒdJSÔÎH)<ÉHòSôøw�“¬ ¦p
È%LÓ(jˆ>t¹,’ÅV«Ylu|Lµ89mž¤i§ø(jÐ…uá+À
”…›Táf,\�D[‹Úæ[x›oÄm¾ÅÝæ(\±ýä¹s CÀ²ó
ŸÎBÅ=‰UQ;�JÙuôf/ŒŽé naˆ'¸²&ëå&¦JSESx‚Ï®ÀFX„"$…±8!”Rb ÕÈcÜmÙI‡vteiUñ	iŠmÉK
“¬ÆÛÒ&/ó·Ù0‰=«H;i«æÄFUÜÍFÝJtþÔHü¾v°ÝìîÐ¢»ËxA�h§®_÷x¿Õc�n*‡ˆïm$š[%�¹^ñ˜ëpœ
Æ8oIúxÉ{ÝjŒ‡P#A¨1B¯©»¦øîš¨»æ;Ù]K|w-Ô]ë�\ÿ6ÑN[ìú·-¸þmQëß†ã\r'Á²4,K	,íw²»eñÝ-£î:îdw�ñÝuRwËïä¢w�i”ØEïZpÑ»¢½Ç¹âN‚ee<XVXVÝU{½w«ë}+_ïÛðzß{½‡Ä*ç¾�‚ê7þR C•.ùPM}Õ»˜CUI`šÂˆxç�@0`l'¥”¼ƒ]Ø8…]´8jî-N'¹ûdýM.òŽ�äd{<àd�[ð_�)ÝnoIèä÷ù§·€ï`ë¡þA“7$—QÞ®Œ4'$Ž<Ä¬‚¤þ ™;\d„ˆ,’(Ï&M0MáblÞI»…›ÖÝ*¥b4©ê!EºÎ–Ž¤Q ðàk-Ê‘õ H3-�× ŽÖI›éDìÇ˜tû©Ç¿
ˆ- �£¢‚
¡ƒLåhrZªö0hV‡Á6>6àa°-ú0°>Ðù†Ïd¡Þ�RÆŸVýùËÇkHjØŽ—#‹Õ»W‹kå£²-wl•¥³B†TI)Ïì”ñF'fÄ<àÔŠ÷Ö¯ãÅ¡'Æób¸ÀÊý³3¢4uþMó [ºXPy,MN<£R,áì±‰ÉI
9Zùå‘Qí¼îQª ö‚R¥ö!@Ýá’LGE‰¢æÅPþŒNíµÆáæž�)–Ëv¦¶+HgK£…kn`ƒ²4c�³0m�NFÇ@™s&EÿÞ•ñ‰YXøQïâL±8%RçŠâ½v”¼kÅÉÉÒoäZaÊ/L–ú°„N@1Ì¦.£¯|Kâ{Ïx"šïB~Jâs´`Jìëg¡ñTÏC…iyW2ìêÑi>4�åÝvC}$õÚ^‘dTS«÷¬Š¢¯ˆ¿Y¢
JJŠ8˜£j¯�¯
tf�gun1¨qP»˜ÔD îf7+Q&ÕÉä%0øh¶dÜ`ê‰®ä'´:¦Œn)n0õr0xùÊÁ4F5Ñ½@¢rÒÑ‚&qÛ5‹_‹øµŠ_›ø-¿¥â×žNd•=9pkJ×ËDj‡øuŠßrñƒÚ]â·BüVŠ_·ø­¿Õâ·FüÖŠß:ñ[/~Äo£øm¿ñÛ,~[Äo«øm¿í¢·eÔÛÐ[}°Coä�`{ÑveÁD°;f’ƒ=ÙyÈÛ+þ‰ûD¢øg¿()dšØlúÑ�¶xÁÁ¬÷Ïç½l-5¿š?Ü+:½�'q8íGÄï¨¿ãâwBüNŠ´Þ´ªyjÞ�ÀYÂ5[P¸Sâ×'~§˜ýâ×+¦UGµ«»ÞP×ûv¾Þ×âõ¾=Z9Õ°©ÐÐ\•ndR§âõSuy}±+­U[#5Z%Uij]MVB:9§ð(äHõC{ÑÐ˜­hmRÀG�sxÙ¡˜Ì“…$*2fF¤^kiêAq¡R…KÅkhÐ‡ô÷PâWY-y�L“6)¶307ë¨’‚ò#µSš:'Ç ž"v;X¹_ÜQ½ª8(ž¢d¥»‡Å´–¤¡¥Jƒ"ìzÈšÓpSÃ3&…r‘"å³4c¼ÌPP)´J¥UìP oŽ«¡6§Ô»“U³ÆÃŠ� ðŒ‘B‘8mÌ°"Ø¥s³3EhÇ '[7-Ù¶`TÏ@­CÔ7=‘è¤ñ4iÉ´Sï¶Ûõùlè~ýŒ33sÎÐòÊ†4L%®™åÕ¨¼ZÒÝñ;‘m!å[\óZ%Ywsˆ·‚pH
¼‰®½äTñ
…ØªCõ!)ÌÉj!Åÿ¦Cí·Lñ‰zâ·€L¨Üº!ñÁ5žfBYB‰ ECª•
·Þÿ´tÁxL¬J�Gñ.°ŒÏbÙm›‚R›i½�ÚiSý±¦™˜ÿ%€hËtì`–úÒƒ?‰´?´ÓVŒâ÷çM	�e@ ÙPúöQÖYäuÈÕè$Á}q
›)`º8XR×X‰Ö®Ó*Þ­¦²J÷%–‘Od·¯Õ¡¾VË¾ÖDöe/Ô´…»VŠÒ(Ã|ZêV�gà›)�¼&®‹Ÿˆ4“Ø`�’DGâˆ	Í�š¤Wò¾Âk *A­—¤)é°À±Lã7ûiñÜ|È3ËnÊ³Ð†LÓàY7(«tFeoTV#õÇÀŠh~�÷Ó~<N¹à–†'}á¦)özÆú'Þ‹\£”±F›Õö?1ž$Ê¢'í)ù9[¬IR[ÌU:ä™ßÒ�‘æ�ds¾ÃªRÛN¾b8¾�aØ‘x›;ˆm¸—A
"K¢ìÙÁ”tÞ)æ¿‹a#Ï@”GØ-?ˆ=ò<ÛmHŒ5yÖWW¯f»÷f#Ë²%é’íÆ£«+Øìg–´óI1Éè€’œ¹'Zræ`p'à÷fo´*˜û@E
C Ô¡ÃÁÄ¦éfá™£ÚŽ.·xÌ¾p$¶*þÍG?2TnÁŒ8>èˆÔäœ'¤xÇIGú#‹Ù½:»J\ú~…KïÀÖŽ6€)¥„ˆ¹¸ôÔìLi²¼Ý26ßpß¨ycsö[‘5U²mŠi¬:„p#ÊØ]qÖµn¦Å>lÑ�Å�º“s3e@˜lóÒÅLqŒ
R\š˜BL
�–ý	­L°… .•dÚ ­²z8’Ù››ÀáNìýY°C04TžE,ˆù"ðhÍAaaicGL�—3lØŠÓø0ë"·ÀÅ±&þ/"Ô™>*^ž/¶;êÝ¯ƒ³…‹@{±½�®šÀäB�^�Vv¬ƒÈÄ:Œ›J
“#Ñ&S }²ó1^ºbŒƒÇ7;1âé�†¸'º”6Äàmð 6XŒ¹2EÏ*1¡áÙ©�±1Ø*$ûÎhÔŠÎŠÕ›�)«Dœ÷¬X39onË@kTx´¬z¢œÙ²(„u U�P…(gvÂ]Œ‰Ç …1†BcjXÏ;€š¢‘[Y”:O6ÓÀB.Ie²\Ä±‹VŒ$¡èý!ú’–Ø¤­Ì¸he�±§ Š/ÒÒÒ9ÍW~­ÃÚ¬ý*,ÌÍ–‹ÓâËÓïÑ»Ø>ï-N®™Ð°eJ…oC–FG?ýv]åZÜÃš³>>"cÏÐëv�Þ€ö[P~¬ð†¹DÝ/Â‹vnZÎ„8eU["½•DÓ©ep-ç�¡²à#c¦	 ‡
È1´9»›ßb¶åª¢ùÙ”�”Ë .�Á�…#ùžÇDô€7ŸûU¿Mµx~ð{Fû§àËÂP´‰ÿbGêHä4ù�Â‡Ôñ–“¥ÈRÜi¶…UÕE(³Êî‹¾YìOUE³;:Ç©K:´eFÌü¤©QT%ÍF1ÁXó‘­>'þNé;¼ÛÝ7:ß°G7[7Ýúw° ÿÓ.zi
ÊçÅ½ZR(ÒÊ§B
Ë7IâzÕ�¥/1ºQÉ”$4t
Ž%ì¡ÇÏ³¢šAáÜ¼¡wï£„­ÌÀçwÔ¢”!”-×ø½45¸Dü–J…Àö…J/ƒ'¦´	ØI^dÀ,7[Ž†f*¾ÙµsGÇÄÅWÜì”òr!5ÞåH YØ[¦Ç’•JÕ¶›ê§YÕÖR ¿Ä=®ò}1 iE!O[pMŸ±:IŸð~^@tö…ýÊ¥²_skM»‰]Æã:~<oòÂCX_a²PÕ�o ’N¶'‘y¦@\Š]¸Q34UÖà´ôP�„\ÝüŸÄ¹7d è‘½‹7v*èé‹XÝ‹ZJ\WV'xŠ{Áxûc)zóâ\Óyc�WXÂgˆ8¡<Ü°šG›lÕŠèNM8ªdÐUŸlÆÍQòÈÛIà×,ç'ÔnVêŠ£šüÛ=0ŸPns“Ù&™+ˆ›X€ÃX»ƒêlX�§jÐJ-oOø»“´ž”÷¤Ï�Ç³³R1¥ìÚÙ¥öÃJÒ‘:<Ô‘Ï†täÁÂ 'µXˆ|�Ã5tœTBixºfµÙJE7æ]ë´ˆxŒ5Ž½ø¸7ºÔæoðû£"r+mþå¸—³ôÍè=¦©9Æ^þ${¢7½³—“îå$íå¤RË_`/WDÙ’±ß-»
+�Ó ¥n…g×¶„rÔ®= ‰<E°r@8CêI‡{è
Kûò q£mæõ:„Dî|wd%Î¼GŒDÌw½§ú2NþÝÐ”.©.×]Îåú%—½V“ÛÁ½õg=êÞ'¿¦
HƒÕñýx�IS¿‡Ío¿D¬Ô
Fª˜Ö‘~#ï¨ÌÛ†Ä½89…£7›¤Å‡½(?«,P…(žð‰ˆh³u¬Ü|‹ª3íæPoÇá«É«”$HX×Â™_^=®rß€Yá|YV…úpeø¬Qî"@|+�`ÌÄc:·ý[$ 5ÑL´à~yížZ¨> }V}H9-O‰~ß0àó€ø=(#gÄï!ÉS+¿³2ò°j”Ðþÿ¶^Óbã5Î”Î-ˆé´Ø˜Ž3¥óæ”–šSzÄœÒ£æ”:Ì)=fNéMò{Z®Õ^w×s¯²·<¯,g›Ì£®±ú	u‰<¹�‰-}ß¼Ù)úCº3Ï§‰ÂCÍÓë-é„u¿…|¬™]<©ºXc¤o¹bµ=¥íÇÀÛ;÷:¤ÎÌ¡xòñãªŸ1ý©~
v?Ž%¿§BÖ†å†ãí^Ôn*µ?j¿¨Û/Æ·?¦Ú¿¸ÈöÇuûãÕ´?j·PP=8to�ãA½T¿LrK2â¯êEŸ`‹;^
:“bå÷mîyeŒh¢ÂžÚ¹‘žu§yIÙ9q7ë.bÜM—CŒ»)y‡”
kYÔ}:x«,16…‚²À�¸>{X~ÔegH¼*;‘°˜ÖþÎæ·ËŽŸ±;¾îøŠÓñ–Š›†®–ð¼æ´ñ-žÏjx¾m@�×Ô½�š¥r×ñÂ ã.Ñbï«(ƒ9jñÞ5=i„Æ™ÎOþ�±›á¹
í½Ë9lÒ‹¸aÞi|p-1>qó*ìFîåùp/±‹ðÎÅ/×xwØ>•^Ø¸¡½'¶R@¹ÒN%©	Ò�P{Q�
ï¥³žäp6ü©*f<ŽØ"üR‡'\—_R^L¸ÍþŸUâ‹ð‚´‡H¸Á–Òô™ãï3Ù¥i÷~ô_	Ü8‰ÄQ^½Èû€™‡×þ6FÂgåQ›†ÎÊM
¿ ­“<	‚õ&˜ˆýÎ•/Yh_²/x6yB>eVËR42
“oòï›ï-^t™pskúœ÷ï¥y9!cæäJYð£5¿Jù ¾Ö>d¾�¤åª—þ«<�Û…¾B®þá×Rýšªþé0DRNº”Î�Ø}4Tü\�ÉüQÅ×þX4_ûVðKŒKþ(Š,úÛhÜŽ#ÇØáSê5º\…6©¼î€8à¿l˜Š@¦ùÇ¹Œ|ß#y¿;Ž|R÷ìŸÂ€#ŸFÍ0Ž|­Gp¯hÓC¿|ŽC­@@!*÷ó*÷*÷¤
}Qå~I¥}Y…ÚUè+*ôUúš
�R¡¯«®†:‚/qhiðY=|™C�¿Â¡sA+‡ÎízSð=ü*‡ú‚¯r¨7ø<‡Î_ãÐƒÁ¤¹Õ@Zö8œâÐCÁ94|�CKbeÎÉÇ²Ø"çe‘þØ"Ke‘b‹<"‹œ‰-ò¨,’�-¢¨ßQP©Èc²ÈÃ±EÞ¤iè	ëç–€Öiã>±çÅÚu8Þ/ Ý+VåœXÁ¥Hÿ;1p«O´à3Á§ƒOŸ^>|<øe<ïDn3ä6‹9. èÇ=/RŸ‡ÔÍÁg5.õ+,&GÒ¿JHÚç±|ðü:‚“ø]_Ä/"ø’®ËFWÚ©îW¨îW©î×¨î)ªûuò“#?)o>“?h›Tù&¹ÈÙã¶Õ™]àìaÛê‰Ìáì¢mõäÕÊžü¦’=Ù‰S=Ú°ÆƒCtgœì‰’:™]un4§ßQIê$$ob‰¡ ¬	²ã!„\½!)¯¡yÊŽ@‰äPJV™‰È(Œ^Ð’ÃZÜ7ÄÐ%krõCRÀZŠ‡k°êãE2¤!:PÒ"pzbö¸˜“ÁRfv³ãè-”`H2HgKvÉ×)åPŠ(sB‰mhK®CI§{�ÜZ@ˆµˆv�ÅÊî.(^±›âjË¡Ë8–¹\¸Š0ÌÙk^¾9C�Åd´¨º”�19þÊÈ(	h†¶ÌêŒAÁçÐûž%GdÊäòB<N,?NkbQa/?(Ká
/NL�š˜œÔ‹ŠS£˜`¨%Äˆha€° ;32Õû$œFÉê*âz›¬~Ã9£Íæ·Å°Çå×²>‹dù+y Å	h1"WÀÓw?¬CJ@€ )Ðo»I‹ï7Eî6á‚ï6¾aÂ‘ýôŠìŒ#of†('2÷/(�Yª/õ›¤F•TOæÚ…†`ª,P´N­'æ_º“8ë'ZÙS'c)P——o½¢à50;¹ÃSìä·¿ÆAeó¡IÙ|hV¼W0ãÙ¢ÍB´\Ž¶|Ÿä!¥]yÊ/æ±“†Û�ß,›&µ—áº¶ÚæÆÛU]íXÆñvÙ¹¡gî´­)Å!|4‡Rìf9q9õ‹ôw¥qâ.æ‰!Ò
Î–q€hÄ%5`�P³îW�M%!.`Ñ—öØh�\¼î0[	ç�•sXoÂt‚ŠÊf$§1¬R=¯fƒÏRºæß„—ØØ¾kõŒV™¼©]Q¬rÛ§Oà–41¬Å�B°®ŸEÒãÇ�æ2EÑUÌpVÌð—æ�sµšçz›½ƒßÌÂÒCD‚MšH°)DYÙ�×ZÑL]b³=ˆ®ŠƒPrû6µq,¼@ZaÊ}y@}i«mýÑ¥š#>S5b;mê–¯™Y›S>h®ÄÂÄæ›\0öù«ÎÝ"Y7!ã&äÜ„ÀMH»	’ë¿Ìô‚²C3VSä'§‘#» ÒÐ®6þ»;_«×Ñˆ¯µó�ìZ:ð‚=ðD4t+¤Ê^6»Š‘}lÐUDê‚ýøi³`K]pê#	ÓÄÇy:ï‚½~#Ñ¡h�Ÿ­U
÷àw œ£C&Øç7páœç×†Šfý(+�5„I
4kZãçj±„æ"÷Qa4f{¯(’­P¦”uñP‹M	ä0¥Þi"×‡d£dpŸµ˜fý­•¿Ï¯õ3z4X¦ÖtŠ±
jqPU?\ÆÀlâV“ÞC&¸öÁÌÖ.°$Ê5U,3¹r´$;c@5&øyùŽàò�ôÔôÁÞL­=wuß„ƒÂ÷œ^/YÕìfó2ºqk˜
ejä'%› ¿óS¸¼õDÃNaaŽÀ¼’Ì©SI¼@”¤d,ÔÙ99bXÚÇõ¡}L)¥mþ6‹«�èW÷½Y•ð‰“¡&{™å¢.uy?ÊüƒoÃ‚.“¨ÔýLîÇ)í¿�1_â·ËLE[×§HTs�…=ô…9
½ê’8Ã¡™ô©èxÈp–[¢?æ{@•xPµ!Ñ›3ySo0'õ0< 6KÌˆñPï­ºk¬‘(
^Ž92ktÛ*r€ñ�\š6QÈL¢W¤&‰x…ý¨Ä´“HäÊJk0 -˜ÊI:›´&´£Ô›t-Y+SLW¼Ô¸÷iÐY½Í–xbl¨5œ•8×Ã#;éÔgPd7xZM$�IÝˆõ«‚`>•9rÕóˆ¥àšUœ…ÇgáMQœ…Dð¸*ðDð$kÁi‘M.ôæà-z*’štÁ]
V¡U¡¢
�©ÐEW¡‰à‡žV¡K*4©B—UhJ…J*4
¡­zk0CTÖ2ý3ËRú‡¸ì¸¥¤Îß•X�¿·VÔù{««ów“¯áßgy`‡	A¦Ínf·ÐeÔåA¤·–å9õ6&Çåìã˜ýŒ›½>¯8o"{ÆÈ®ŽZûvE­Ý…´\Ã'DÌ¦ÖA+§¼•s×Þó
�¨z£.ÑA´¥Zž[Ë°¬e±BzŸžœ)j2˜yp[
Y©ˆjÏ±vÁ±‡çŠs@°{ë)B•˜2£(¨ã…©ÑÉ"+CMOO^óf3®}3fØºCªA‡èÿÃé5/ø¡ýº°}£ntÞµÙK½AC«ç¥Çyº7<Õz–�þ,¿É_ÂÅùò‰M²^™òéOúé~FÉ›ä‹–ŽÑRp¤tfâ,¶&.�¯Î+ƒHMJižïÏâíÉãzgTÝšhº”Ž¿ÞÚ83Iè
‹ÔÅ©“Eêc‹ÔË"
±E”hkÃÍ.”ÈÞìep­@;‰Ë¡¿älïMHÏ¡NÆ—K%VQÊ_ý¶4¢H&}Ëbâ§”ÅDz,ø¾Ü0°½ê—
šÍ×R*hAHs<¤ÐgP¯¯^ Šü4ÙWr+&.÷ˆ|‰'TôçEþ¹yEUkQL~	ƒÓüÂ[¢;'ËåI l
„†ð]Ú'½B&dOšÔU.)“èÛÎù.>]	pûŽš…c<ÕÀ€‚öc7¥þS,Þ%†±ŒÜÏ‚¿
lAÒ–þ‰¬––S ¼ƒ&¹Lª¼Ðh}9Ú<ÚTŸÂƒÑ³ˆvTìo@ Ä`+U­A§eêjÙÍWË¼ZvG_-�ô‡/—ÿT•oœNî‹¿\Âõôõq]<X¼v?U¼T¼&Oò2HJS²Þeø¢Á¼G¦=ñZqîÝ(ÅU6-F9³4ñÏ#S“¾ÙµÙbù|iVÌLÆ ðKg
³ª£ãB]CCI`‹èøë½(ùîC°J°Yjªh•Rü[(�LL@ì8Êãc³µ‰2•��™„(iµÿK@NÎC°Ìt&KWÎˆ5žäiãM]	_¸¤aRënc¤´?=F
ø‹ çùfò–ý)>}8Íàá$’Ì9È^}¾ÁùÉ'U#k"¾ûZ¾§*\…µê*”ƒ�"‹õXVžµ`Û¯Þ¸Ø™Z—×hR5šíÕnaäDŸg²nKìÈZäà[c‹´æÝ—fÛ`È¢Œ*ZôM²T�µÝ«¤þ¶Hgâ­‡dÉevÉdØ¿ˆÛBØMíØMGì”;•2Cl%ÏÓ[¤KY[d…,²2¶ÈJCE5|å?Í»»;|åw‡¯üUØâê>éŒÓyù™z­.R°R]³5D—ÉJºÌsè{U°&X«N{ul”`½›¼aðVƒlDñskoÂôžls8�éR¦Ø2ù½[á²$CãÚü?x\-ÛDšÑÞå¤]*T1ƒÝ’Î^!I>[´r]«Ó¤¬½-ª6×é$ìŒ�v”‘Ø
ÁTY©Oc1bGn7ôu-¬¹lbÍQU}$XNÐñ»(m).iKßl�-ÜT1áç4³skjòÄ²rb>èi;IÍ Ú—E43�öñc§r�Ñ]a½ª¯Ä¼¸¶* xÞöÀs‚Ma¥‘(›`Ð¤*€Æ-Ž`º2ÏÞÕv³ý¶`³¦=žä¼=¼ïxÉ<´o¾]Ôl²˜/Q¸=hæhZ•E<¹¶j<y¯Â“÷ \�6€Ô„ˆE>-^�Ý.¥HÐðò€+£' þ�'ý‘8¨ ÂQÕòhÔW,].’W.Ã"*ý5åSlÛ¨¶Í”ÕÂ?œpÕ»ª-ÝL³|F¯yª)îš1.ÍÎ–.{ü�ë'ŒmâpTþkLlÃ€J+±›°ó²ØG„�e£<	!Éj‘¾¡lï
ÚZÿ™F\Ö.£°\"I-+Å³�9…¼R„¬ÓhËKÊX�w*†ŒÕR™ŽØ¤È¡.˜´'e�E,_¼b$ÖÃÅÊÃöÃ?ZÈOÉBBº4ý>û¨4sD6‡dYÑ5;™2¬³Û‰0B^Å±âŒXP-…H!3ï´6’ÏAÇÚÏ�çÅÒÐ%ƒê8êHç"#â™TÕ®,—xð`£!�›ŽÄyÖlîmÃˆ±Q�Ô8ç!¡­;YçEd‹6üêÚ ƒ[Úš‹¾·ÒdÒŒI&ÍÑ‘Œ ‹�˜˜›WÏi/éKO�9IÍÆeÔbF]8£>oyßÒär²)œAþ [Â­¦›I3c‰é–ÓÌhÇŒef"–GÎåF>Ã£‹^¬�‰uaC¿[d…ÄêLû•qåE»+€Aâä¯dl„(—*³›D�tf@¾sý lzÑRv0ìÂ5›‚5øwí`¨“uy) cW[�¹h¥“	îRã!ù€tÐ#†ÔCÊáé`³ˆl–‘-"²EF¶ŠÈVÙ&"Ûdd»ˆl—�¿;dd§ˆì”‘]"²KFv‹Ø†ƒÙ£‡”ae‘é
JŠCí
‹Cí%]Á«½äìi?íšîªü 8@Ì÷ˆÈ=DÈûT#Ò·äA‰Þg‚CÊèê¹‡ƒÈ›þ¸*ê¹ÃÚÉ~“¢|ï ¿�†•‹�}˜÷)#ÑGlk’'@sÌ2štËÊJ‡øir\�ý„Öù§«HÎï${¸evÃrI°ÈåÅÚ½zžQ5�J‹™àþì�æ�˜•ªz¯±\!ÕûqÝN™ë†Ýì¤:é ?`7d£åt•žÇû�…Wc‡<jP¹08­ÌìÅ• —ÅãJÆA=ç×º£~pP	»€€œÉƒhOð�ìi·é­ü	-ìufÉL¤œÑ�Õ³\Ò,jº9ÏyÈuî�É¹
àëX÷}²ÚÙ*ª=lU€î7L°
Òò^¶ìýKó9Ûû”úiïÖVIÈþeÊ$Ð¯ÎÏÏçPÁˆ¬¦Phî8Û„€dX¦£~–—é>ŽY1®aÀ0‡Œ¥ÅPï•oõGÈ€ˆŒLP½6ÅÓÄA'<ªa?K"ÐÁ£.ÙŠÝÇˆl•
Þ7–\oa”ö¸�†5žžÄ†ryNx3']RlTºþëÏ�%�„®õÈ‚uTÐºæM÷ß+žøŽ|K5Î8…»¤·¬§œë�“‡œ‹�“/8—'œ«n¡§iÒò%=¬¨{qÐÒñÖÞH_Òà—h{/)�ÀÃôÕ%PïÆÿ“~!Ö›4TñTý …÷¸MPY„O®läþri´~¤¦Êè#C °às
ì ¢Ë(ù/¡Ö¦)íšÊ±Rj<5<k
•EÚ¿VYºðà6,'XseåËŽsI%ˆKžãgƒx~ëˆ­pRÀ#ê5%MÄê÷•íšý3Y�=Ó731zfbJ<FÆuP¥²ç.'j¸ÿ"çQvB6)ÒÄ`Q“æüL±xJ%qîÉÉR™5mt>%J�£3ÅÂ˜*�/�’Î”XóQln¦huÐk%¥œŽz�oº4=7­€Š^½¤£1ò
‡îÉ ÀsŠ|Ï
;.ÈL§i'K—‡K'JW½üÜåâD.NOgl¤Êæ�B9
±4±Lçg®ë´ŠþÆB–¸C^IÎ£ë·é¹Y¡
ácb!KWäxW0ÊÅ
÷qè6l´0[€ÁÙÇ'‹3àûþÔPõÿ Ãkñ”¼VOf¼ã#bx£väCÎÛµK'yåÒäÄ(o¯ÊŽÆ(|¾4Í¡D-}vb¤0ÙW˜öÐ�ÜxI,¶X1º©ÑÂÌ™ÂµÒœ¤7=V,^ê-\c
	l
ÒÈzùaO:w°Ä¨xÇ"'ÃàËÍ›ÿ‹ó§0;3qõ<šU.ÕëšwÅ÷Ä‰ žúâ4Aõ½>ˆˆÅ@­=p¤féõ¡Jb	ÓÅ?#s3•J~ŽóÐŠžT”¯(_¢î&¶ˆn«™?„‚£aÍ·j	„8oNÉ¿Tý¤À'ÀQ×Ej²/¼û�Åì5¯Ž%�ëØ‹A2¨gÂdÐÀ"„X£Ñ¨�¹Mè6Œ#ÍÙµ:§%ûßªáÖ �“— ¯.Ž,ÍþÞü¿–‘öìŸÌÿ¹¬°Lõß‘ýþ÷¿/Ëtš‘å(pÍ‘®ìßéy¬Vrrwö¾=µ²Ìªìž!UaµÈÙ"#kxX{­‚Âº´,°>;66&#ÌÈÆì~ðÙ„ì*®ÝlæÐ–`+‡¶Û9´ƒ
C$ƒ]Án®¾'{KÏh/÷‚+º7Õ~�Û‡;äÀ9‹�.þsmf_yå>F»‡ªm7²ö½‹ª}_pØª}dQs:(6ÀË9Í^¹R’‘cÙ¿ú«¿’‘ãÙï|çdä„Yçdööí—¼ëåˆr>^À“�ÇPóEFä˜9nFN˜‘“Qs/Nè~‰ìŠ/ö¼THNj'0úªñ£Rj�ñya­JÞº	®Ý—·Þ_mÜìVíUûLð�U;ÿºj,räg­Ú/²¶½ÉYûœUûü¢Öµ;ûÍo~I®«„GB-	µÚyl‘zÓ€½é0r0ûþ�¼_FÏ.ÅÓk	>ÅïIxõŠß[ Ê¼Õn(Äm<…E­�-
vùûÆÈF«ÑÚ…Eµ¶$[#Ïó”8¹
r�èî0Ú^ü²pµf‡ã{Yä
M}t‘S¯ÓÓÛ†¨MÞãy5ÞÒÏ¿ê¥®y™+^zÜKÎxÙ/(LN�¼VñÂö–\dDÔkFô¯,pš[ÊbóX?ëæ!è"`.-L$g=RŒLh�Ídð4DjØl$›z®�|¨@-€ú¡ÑÁ6´jÈÖ"Ê� QòO\USé-Ý0
¤®f¢uy·Z=ô‡jëA½f’‘ÍŒ�ýç£âÒ«»Žú¤¢™V³ÃÇP8æ˜OÔ¹†ZX›)¿!(1Á¼äJ¦ý4Òæê ÷­~kæÔŸ½tôÐËƒŸ­rT?yÔNÕ€[1
àYÌô³É¾VÐ
lös~6˜A™±leQXfeÎÚ™«P?›2¼Š	8e¥¨Ê)^·\g�#?é'3Ÿüô>úí{Ÿ«íÃz•|íÝß;ºë¿þä6&×±Ó´t.Z-ÉzgLãþÏ.\æŠ]¦^—Q1™WgÕ÷©þU£¾Q3Y•*Z°k‚jãë™9¶�¬b>õ}v�º¸9ÐØ3$_­æ
,gÜ�¯yÜb¼µR�Ôq}Ÿ=Öº¾P¿61Ñ'C¡yˆ‘Õ¼–‘q{jõ" Zßçì
«Nhmå\e9§Ê{¨Ò>u¿£(ó^ð,½ñ>æYx©‰>¾
ÿ¾ÿ¾Ã1µZ‰é`¡ï4°Ðb%’¬ø[D^’•‘˜üÜÂ=>+‰Éï²¯I~>rNœùng¤‹£¿GÑŽ÷á�6lô€v¼/žv¬Ý÷Î7t7@Å›’÷V&ë:U:˜3Ì‡b=(ÕR}z®<«[”0®Óa2Éd“�f€äXiR#IÅ1Ëp,ð>SD»^,i�Ò7Á'DÐÓ®›¥[hôB3�’”¿L>¤Ë^oqzv\z”¾Ô3Ã$ÚñYÌ6}7‹QZ™Ç‡ax!eƒ4¯DŽâÿkÞUCIöCä)™c‘�Ô¼&(Okkõ1ae+“Ggl…�dJ2é$É*£î|{f–©¢'Q}Œþ¬ãUäjMÓMu¦#ÛÐÑª]�6Ü\áyi”TEÅj�Ÿf
^\x‹íãý0MÉ�â×„œLóMâ:~5<��êÙß¦ˆwÛ
?Åi¼e¥™Q\]¬–Í´Á¯ºÊm¡ÊKH÷¬šÊKB•—úèB¹šÊKÍÊ #—Ù³ç�ŽîÿÕAT!‡`‡i5Ü×ÑæŒg.#ñ˜$ëß×’y

¶R7ôÇ(ïØYlwAŸ¨ôP¬/ú+·…*kÐ/XyI¨²ý‚•—š•=5©�š”@E)c¥ŠÎ@}í ïÞE€0¼{Âðî]k^ÿÆ
ÿÏ	­Ï
'†°:Ûj@•R>–Š2¶DuïÈ—”~}_ÒÃˆ˜áúÐµmíu6/µ&bÆ!{S‹Ý²¯{¶J9Ã0Ùý.Þ(ËI(÷F–…Ê’_£·XEVÈ7¶m(ƒÄë
ßC²B·VLŽ¬ÀO�UÊóØO’úŽ4EIG{-UéñRˆ‰	TæA–›Z‡ÖkÅˆTëÄ#>›–ìœ.¹ÆXõ(è¥¬0RÄœþB¹->lèdlÄN7áß¼ûÓ²&�g³vo•¶(ŒabëýäÀm­F·D}êBI¶ºúp[O+§.ºâ695×í¡¹nÍu;,Gà×«Eú:¡Ú!ÅÀ¤H †Q=z‡ÜumýßX¡T;­I"êaNg—Ï¢:»�„oðè2Rö}?+7• ß¤ìef]<üµñ›,*\”|<R§ªGßo4²ÌytXøÑ¹J>:]—íÔ6g\¼dR�~]R¯Ëý8éç|¿óº”ïžíÖ»g¾ác�PóÆ»“‡"ž—Ñ�%­Öax<×ºÖ*âM%ßOçKÎSJÆN'KW¼±‰©Ñ<Hd<S˜˜„'×ŸãHY=ÊN\C•Œá9Ñ5Žv.Ë¥™ÙSsS(@¤p³Åò,¼4‹3ÏG­ajÕ9ØKì]<K“³bÊðR¼\
Œ£´Žùr´k�À¤OŠ§/Èµ !èK,™17í�BK„Úèa–zŒ|Þ–¯¦yú 
#&C
 ©ðÔÜåáâÌÀØñ¹Ùqƒ‰ËÅ3…k°�Êt4YnAS-%©A>-fƒúêÞ¥|IC„)EëÝ€Íi	Poh¦T²Twô~57ÒÝöp}_XO‰«þl9-%QÅ[20�,fr€b¡äœŸ@‰K'¹ÆO Ê¸“\ë'Ð¨Š“þ�ëÂÉõ~Bžqfr<2ÃÉð lÌÄ	m4‘½/Ðî(x‰aðXlßoÍîýÖ<x‘í¬1&{À.;Â´�8<‰qx»Y9|ÀµæñrªEe	¼I½	n«íæ&4 ¼ÙKisÞ>6{nº0Rô’Ò1ç=m’Ô)aÆÑ÷À’üØËÒ=dTþRÌÏÞþaF�Â…ÚóÈŸŠ³²Œ)Ÿ×Ù†O>¶¡ŽÅ5”†aáÌ|¤Î››%�LËÿhÀÜ)0ÀV¶7˜jz¼œÞKYÞ'�„ÑyF`—kíf�è3Ë
É#×îuí�V½Z%öt]—ÖV³X‘—
ü"²’Šª—ññý5ŠÝ˜F/jôPÍ¶Ðê¸Ïà–¡-˜	ª,ÇðÙd�ä$ak°÷Xe¹‘fê ­*õƒ±iÏ–ü`5é8ù¾\…àf�\s³þ|À®õOqr7[Ù#™¯Aÿõ�¿:l«qÐà‹)îå50¼}|>°Ag)¤$Œñ*ëWÊpú:š„?	ù^M/`©ÿ³ú�¶K±LN†¸	ýSåÙÂ”8ø†ÔöZVò[ËÎG¥uOsº>Üv’Ä%g�”³Î
ãÖ
Â‘OB‡4wØ­Ï_äW}äÉ¼>¿@mÚjdówáæQ°Ö ôzá
½Š-¶Ž£bµÎ6–@ŸÙÎ
ü{ö˜]Í
d�¨¥�oÁÈT³™‹z2j�31¶.HÉ1œ¾1ÏÆ†Mr¶5ŒÇr)²!'Wk­ëž\+'éN¬[ÙCG˜žE—s6,HÂ¾:ÊDº±è+,•=µè1uhÑ3áE¯»¹ÎòìfùÙÑ{$5ªe™Ñ‰Òéð¾³�+C[™â3æ�¾.íC§”Ý¥�ç‘ I*'ÁÊ}DPÛ¬¬2j4®ð°D þtžp‡ð'B%µç*©LÕ×ßÜ' äÕŒº<G¨88u8a–U'‡3Ì]G}`sSf*nÊmÊl»ú2ã6e–7e.´)s¼)ÅeUGàß±ŸA¦â"á|¡Ö)a!¼Šël!‚ÍÇnjÏáXõs ýš•ûunâ_Ÿ�d“éeë Û¿_‰3z2¡Åc)P«=¢dœáv÷îÜnÝlSZâ¦¿5ÛÐÃ‘zŽnÞLMQY"®eýí>lu�¢)ø§å:+õ¼û ’ð�ßÆ)ùhÐýâ™mïRÜ“‰30ªX~Eäµî×8SOÏ‹?=	4}‘ËŽr5ðÝñáû5/
f!øî¨¾µ§Ï8Úmcg€kmW­óŠƒÜ
OõÚÍ^�FØÆiòŸü0SCÔŒ²^×‘G¦]^l‰�„DÜN„9'00úòhÍ²�j}­kòk
Ø¢*ƒðyešRÝ…#é–¦Tw÷Ÿ¡ãã9 '«ïúÛöÂåè€‰ÁŸ Â/yÔÈj¢øl�¨Ÿ“Ì#>ÛöÊsý	rF!¹LnM‹Ââvèè”Í§CG'ráþí«„
¶y
ÙÄî„M§OËã,+MŸ*–Ö�q+Ç/˜ï{áUù
ï
X•'»*1pJ†à„=2¯á¤fÿ·^ÜìùÅðü£žýÞÐìGõ.‰ÅúOKÙ
¯ËÈD|à¥È10sÚ�’_	¥ðyÆ™Ðzg4ž›Œ]#|õ�(<«‘ìàe¤¼ßñÂxDZQ~Ä®«hßOº›ª·CÒÚÛ<…çC‡ý|4‚X¶‚€ÄŒ�×x	ÑÇôö%Üš�Ÿo”Ž…×g_Õ‘
ÙÄï‚NF6fŸK(ÿÃK²EOE–fÇt¤#û‡:²"ûŠŽ´gÿ•ŽìÌ~Çc!ûhÖX+Ü¢Á>Z±ý˜}`�Yc÷Ä°ÆÎUdm"“Së6#™Zâ˜Z(¨™ZÿWÔ¼ñ/2«ÄÔ²*¬,WÂ�í¬±:ðÙ¹ò8{Z�N+ÇÆŒâepš:ñ,©xù¢�‡
WÅ½Ý?5Z¼ª¸=³2A”·Ö‹`gìê¬*<Vš¹,‡9efÌ'K#àÙôÜµòlñ²œ,-�ÌEk �ˆ¢–è9ÖytFÉ¿è)PŒ™ÀŸ��„œ)>S�é¤a"…éÙ¹efí$zUV×®€.ïœTý·¬M+iÖ‚È{¦†ö¨9þ'YpÕÎ‹Ô³7Q~¨4GÞ2�O5+V˜2¤…éÑ¢jÎ1_
2œr Tì:�ÌÎ&eÛs3„¾EaŠŒ©còøäd/õ¶¯ÏgU/£’¸Çÿhzà†êVïŸ¥…È	®¥hÙ�6ªMS°€ŽË¥¥N/{%åÉK`
@Ô;é†s`˜›-ÃÚ–¦zg
EL†žAƒàÊªY‰ž­ë•‹…™‘qXž!öyê…éM“gV9"ªCc3åY°o =‰âNî/ÃF§0fcSðyˆÝE	Sb™Åž�àÐ>ÁÐº¢…B@6ÆêÀ~0í@8™°#§FÉ´ßLé²úÎ°PžM{›¥Ô2|¡/bBÒ8øp¯’MfÓß‡aJ3Žmw}BÔ<5ƒn‘Cgˆ!Š|’@55Ú*¤…ªG&'F.9&Íá˜�oaT�oÖŒÇ'fÏ‘å+Ê—ßûq¬†Á7Q8ô8cöC¥)ý©iÑl0ì®wíÅ¢ÞÐCW±+q²Ð¿\ÿÛù�ÄÙs³4P	{,‚ùŒBÙ‘W°¸äan{Œ¯à°‡`Í"ªh Æ$AøF0­‰Z§öÝÆÿÈš.x§,¶“BGÖ”ŸBV½r†Ã.Ã.ÛÉdaeDXû‚’¶—kCæÛë T«|©&±ŒýÖ´¬zê4Ûã¥KÞw]ÁAE"œ8ma”ŸS%eÓ~Æ¤ý6 NHÞ_æOl4pÇÕ:
ÈÊYl‹Ó4—…¼w°�Á­6A¾~P#áÜ„&£wÒ‡ßLI7;žÖºµ%yM«×lY¯5Þ´Z³rÞÛæØª~4J±(ÅÜfø»tÐ€W»–¥„eF‚Vo2%)©;éEöÉ„CHë”›c9Ë&‚.ñ[�mÊ�ìË¬•â×íèsÖ*ƒýHÄ”*[í'¬xSÚŽc·Èlai
lm�âR"Ö’`"XN¯¾N)…×¢=„K­—¥6 |d£;—�˜¼IvÞ3hÚ�ÞŒÍmQ0ßxs°`‰Ä½Òä(Y±MN¯P¨‰™w[á34_pÛœ­÷6Ïèg»ìØ§‰`4€¤µØÆNãû¹—;ÚaV“f¾;¯5à‚=ÚÀý^5�}4&_Žé¥ð˜öÛcª ¨q Â0ã=LU4 Ñwnÿ�:¸v†ýÝ«FzPŽ»ãcbµñìTH
‹…ýºœ[†…oÔ!ÅÖn„3%]â‹óT‰s‰ØJ^j
lÂƒu¾¤NÆB;òš!M«tGdÏðpÐ@+UMOH‚ê��e�Cx…»?„[àHØŒã«ÀÑüuÓY,$cÊ†cvóŽ“rãæ.ƒ^p"OÿžÔnòè³é´:Þ©;Fsƒé3~DY‰¤ø1ß—S¼ßùr6xU|ö§ÔÖ9nê,�àR%’R,<ð’æ—~G¸ƒãšÙÖá…N*ºŽ«Žïá=îY¼ÿÕ36U“`Àü*w×glÓ'#ÒúˆÊ§îŒ„Û˜Áf¶*¿¬�wŠŽyËå½jæÛ=¨áŠjgæ±ežÛÒ�EbWpÚ D!hÞkØœîêºú»dÅÃÎ%¹Á…_ô1"«?ps?Hl×÷xÁ´—™@”Ò×Ï®ÜèÄŒW7Y*]š›öjðAD‚¨ÿ´ö¯ÓsLX8Í7k$NC¬¯À¯
ã4A¿â€`*ŠßƒYS;y«•ü‡2Y‚ýÒh­DYöe™ü dö›¸3Q‰E%æ£¢ÏF%>l$ÖÈÄÁ®ó0Ä›¥è9>@Ïå5#ç«¯’¦Ð9L�ˆìyFd7&©ê#FóÀkc¿u6µñ„¸¯?ûª‡]òQ	BYrÃ«ˆ€Bó½Fs¶ô„LÅI<†'Ç#y‡âù&íÆï¤Æ¼Á£›¯Fé°üq£Ê¼jú~¢rß0‹¯]•…–ÎÐ³ÀžÚ<â£¦Û‚©yA=Áç¯ÕP½×N •Ê�òÁô$�·Òœž´æ´DŸ’M¨âzÉ‘<I”âÕl‡ùÍXƒ/¾·¨ËðqF6íGÅ÷ÍGEFšËÅnŸ"¿!ÁP^‹[9ï-ysE/¨‹V÷W`|.g¯wDÌOà+hŽÉ9H’'/k‹¹/bñÚì*FN‡_Y‚¾¡#+ZKcäqC´4Kílµ4gˆÈ±—ÅNÌÜTZÊýÈÍµD‚™ëmº »àôpzaÐ]Xt¢Aw¡è.TÝ…Eƒ.41t>4‚I’+a6QL†„Ép4L†+Àd¸2L†	“ˆ‰™0V0©“®ZÅ'6² LF¢a2R&#•a2òša¢&fÂdD�ÛMx†m"‘±3„Ô‘™¥Í���Q±Šæè ’l@þüo&"0õ©JL‚©³	óž	ÿ»²_Æ>ð×6†€Þ¬�å’ºdè�¡e0Å;¤@§š5¥ZØqC^R‚~ÑÞ,cõ±·‹yÃš€~œ^pïvÞ”æÕÆ/Rb’†ùp8¼çG6^ËÊýÍ¤È3;ÐÄ7°ß£®Ç—q.?x!åž|³óƒ•Aƒ³ßâ…1�¬,nCKÒ~Îã– °ÜªkÄ3Â¡å”Òð˜z7�ÝÜÆ#r=ž_’8~ZãøàøY·Q*y$•„JŠñõ²ïPdÁ¤_J}ùò±oè�¶EVC{Y±ë wŠUÉÐèP£¥Ñg{¼TÉóiôI=z�õÒÆè;=h2�¿$�1ÃM^4_°'<óí¸C
‡«¬ÆóüÔ�¸ß·qãŽÁ/û´xéD$q'my%&âŽ¤¾¦û
?\øâ Ój Tà±Ô¿’þ9©=eæåÖ~SÒ†7­±9õzè�gëSÆ�
ÕøÁAšƒ§,¶€ª�jcPZ'aõ!"`Ãž5ü$UìéA>¾
!¾s{ô·b|i<ÉRxLŠ2ð„¼Y†e`D
2p!ÅMŸ‡‘±p0:üßUJŒú‘¼³—%QRHë,?	:ëÐüŽüÀîÏÂi[Ì…*(úX½'om™²Ç³:«Þ…P½ó‘í.ß‰*–/é._’—ñÏ³Îž©rOThÔ8&ÞO7
ß+÷Ø¤5ï'Bó~L¥ô:çðË°Txˆ¥ñ“°¾�b¨¡7‡N/IÂÍr‰xBš r\º™4Æ)ÇPg¤mQiôIk-˜LKëÆ“tAŒ;mà
Ñ*¿Ï:¾
ž–Õz@­'¤ÿî@s³¾¯Ìe‡8øî�@yÈšréþ%D—ÎÙ<úº§‘Tï±Ì.‰*´mEFP×ßê�ºV£ïÒ™ Œs1}—Öá@gUÍ903‘õ’Œ¸ú®Á=¸ßP¾E­jQb§Y>…³æ‡´5oÊ1�ÊÆê˜`®‘�§0ùÂÂQá¤wŸôƒòR«%ZT‘b›iôü« ‹jÝ$˜º¤cÕ@öBÕÄÖvÛÛï?¾jÞoWœûí¿2wå-•uzóõCÿ^å¯!’bŽÌ–Jd.oþ¼Ù¤ù­=k˜àðRÔX–Ô_l{ŸF
0I¤|(�ô£yÅ„Mù>ÝúÜ%Ù^Ê,ÙÞ�%ÛËNV²u�£~†?õ#~ŠCÇÄ%Ä`{³’&Ö_ó$.Å¼Zj3³‰¹ðö°3Þð·kpÐÐI—öüŽAötÂÍyç £¤×ÄÐŸËsäªˆ¼Kyž~Þ9NVñ	µ5¯?ö+Qû»M»6E^˜œÄº~ó$­ÈµØ†<…ªû”ñš÷0súiï{1Ò°/Ð†ÿgQÙ¢�"Xˆ>Ê@²vV3^”œÔÕú5ù^ü{=$bû^ìêzdÙ‡a&Áêðäww&‹òšï|½ß)ÎÉ>È(Ò/pQ“‡6¡B%…¥íàBŠ…Þ´¾î_Ä¿’Ø@

äò%9ÈJ§”M>?¢³«ôüQ%!z¶v´AìF±·î‰“µ çþ"€ª7Ú“÷TµkiQ””2å�Ø‹nº$4eÊ2’kÓ¡«Ç]ÉÉ�(åÐP8éê`„yË(“—CCQ©®X&Ê�ZR�ŽH¤UÚó²d¾@tmx’ì(‹Žjw®†#Wr{^ ¯g¼AïÌyï¼ø{Â<á)ÑTð£dXòl!Ôj³åY
:Sð&Xf»'\Ò”ÀºÛ„®NeBÇM„¿•´iº#óñøðP~:}Ìe
Ð©¨2h53ò¬³ÏÙ“	Õ¬‰t/Ë×br]Å2õÊˆ5DÌ¤1Òª“(Ü©ÓS¸9¢pK\á–HAøe™D‘ ÆÀÂIdKüÝ`)f·«»jÙÇ³ÐÎ˜§V¹ƒoÜÍ|ãî‹5ÐA»!ªýNÕþrj­öiÞ*¯ 97Z�.Ö T	+L¼ie^iw$ƒnv:«Š®Òi9?[+�|Õ+é‰ÀÏX©¬°¬îg|Ç–¬C%çµ	*³ÆxÝA;2?Åùk£Û@ÉŸ1¡s�ÑŒPæÿ/œ¿^>{ÝqD5ÊoÚ`ƒôËªäôò8WØ(+˜3‰êaWØÔ¯Y]Ál=z7ôhd]Ô†R�ý´�kFlšÍDK‰Íßæ(*äw�ëÌ
ù+uŽÚ·[QØüñ“0
Ý£–v¨-¾“ŽÊwÅK²ÎIä�cÃnÍB�,�oD:¾”–
½`—�§cÖnås�îdï±OåKÀ“öžgUâIžt�ñ¤mˆ'ŒÃ“@œ²0=
¾áÁíø¯|¥ªßÈ&·VÂ•Â5
�šñâÈ¥~q/;•qU^EÜ»=„úLHß”å¢öS�FE#>Ñˆš2W�™�‰C¸Òêˆ4¡ÏMöHHSSº*Rª^©ü+ÔÊB¸D
Ã�bŽŠ7U\m¹E jåéÉ‰©k^$‰µç.¶0~°nñ¸‘s…¾:3´FÜPà\Yˆ;‘•j*>YIn#VI¸YÑ}ÙÕY‰:Ô1Ë¨C$áR“lAK<¤ðº3Üz}NŽ*"_�ª¢u3šªÑpx€Ì#�‘—�A-*Þ¨N×¦ðh_²F;ä-Øj|–{#/)5G	ö–ÃäuÕ4/ÛJ_ó4/|o2¢q¶6%¼„ml/É�“Œ�%Œùtq)$*<²vü»L¯Û;CX8ì ´M›‘FNé…¯æ©BX…äC‘<ÉÄ€»ƒHž&•t9RvÞƒ`Ï²["‘Ü…dÍIÏð»½ÞµT±bP²§Ù(Öm$iõÉ.†cZµ`uÛY‰ýmŸ'>H˜•%›œd±E[¾»e}BumÍlö5­6×jãÅµ:
žöÆâZkŒZ÷ÆméÈ}ÙÞJ-D;ÈnÜ¾S¤Å÷Å—!¦ü“ˆ�MäÎ¿I@†Þ$Èµ‘Ð]dàžØ;¡[®Oz-M:³ÙóÇ¼‹Qµ3é“ñe4‰qsþo1_c;Ó—Í¤+ÎÙþ„•NQÂ`7Úßr‚5ÔSøÝì®t,ø	ž!”üšŽ VQ_¨�‘ŠgÝÄJ&š^1Ë+Fiâ¬d¯ÿbÈêŽ^rdŽÝFŽÓ=Œß}uñK§7ß:ó©Ê”{�[×õ–ÎLäAÄmo ¶}üšÿ¶ÒÌÂ›¥ÒùÚÂ@e9¡Ù…Žu®&ã¦»¼Aò.Çˆ›ÄFÉÂ±Ö§wžÁ±‰0»¿�¡gõFø§1¤¬žRí·L¤	‚˜Âu…ëâ
7UG¢Â­Ñ$¥èÂ!êÌ†Ç^QxM\á•…WÆ^Qxm\áu…×ÅÞi‰d€ŸÊ=Šõ°Ù©»�ÍtùÞ¢žÃ‡ð#9Ú°Ëƒ�í�óÛ‹Wg·v ]Þù†ihâÆ«"žÄhA‚Ô€£jëg±‘8ŒáQñÓôÊ€©ã¯lØ¾©¬'Ÿ¡x®u°KSNL²qÓ¼E…|Ü›±LÎîÁ�ºtqEEç¦ÎO\.ŠÛºF´þ¶˜}´‹+³1#94²»øÍzç¼býß!DfqþØ“=Þ_Çœ¦ä^ 0®V¥îW·|Èæv`�ê«Í¼‰PÃ¾Ì
u7[$W¹4Év;Nð«²ä)ƒ:6.Ù€ö•ó$xkIÂ4EtÔÑÑú¨Žšl|¨­ÐQß’×½ð�onˆ-RŸac+æµáß%‘š¾KõµŒeâÚ`lA1ˆEs\^‰°)�5r­.güœ¼ÂéŠ“W:³XœÓÄnuPßËõz<¨ïu�&âI´Ý<‰æþ¾ªÝ8ŸÜå21|vélôPþ•ÇÉœ0-Nwðí7QÎòd‰CDQluh²øLqr§7‚ælT�þ)e]c¢Œ¥©ÃQàˆlƒ|9ž%iô!—B3Ð&GÕS£�aC,œi8$ŠîÔ‹65C•¦J³c×°Ùã1Ê*×Ê¢v1Róó&¦ž)L¢aŽt|H`áAÍLL]Ô>Ë:Ã»„4ÄîŸ/ÎLÌŠZ1WŒãRû™€Å…*½¢Ýºvž2®Õ�§ÅˆâwñE²¢>tW&~&‚¸Lzµ=^
fcèãw§PÈ(jQx™¼,[ÞÏ2s*×Ï"‚ú5Ps’ŽU~ Ôj‰/î8,—™“ñAÖ¯—/�n¸‰Rÿ*ñFgÜˆI}1/î&ºc*Q›øü¼enÚ,ÒÊDEãUwRÒõ@�1ûwÿ?‘Á6ßÏdoþ_ËH�-ýñ<F¬ŠivQ–ÍþÃ?ü*…2ÿç2d¿ùWìœÝ÷“šÛ›¦H
J½å”ÒSåÈy�›\ƒF+rA›”[Bf,j‚¥f
HN‚ée¸ÇäñOë½IêÏóNë 
Mƒ×þF,mü(:µ!˜V¶#`|Fàí½²nÛüŒc¨8a[_NpÎ[Y*®ÓXÿôÍœ¸ÂøþVê41Æ•‡Ú�¨Ÿ:d›’ívLËÖ²·³.ß¢ËÃÒ¢ì2rÅ�ëñÒåñbqðÔˆ¾´uhüQb¯IlÎFÌû×ÙÛ„-{kÎû]	sÞšã%×ZË*T�H£èwàIÅ©�”`b%´&Âkô\ù¤Ž„^SI¾àyËj†ß3a·VktÈÓo?c�¼ø7gKrÚù>øòÈ#¹e_ù	{F#díš\¼®ï—†=mø°?¿°KÚ� ?�òÓR,y™ÞØ'^Ufs6±luJo_ïù¬¾:p¤mHö.ø‰c)aÛ@2wÁw¬ÝÏê2¿Å‰í¼&–öv»)Cß¤SLÆFaÅƒ}K¾o}KúÓÚ@•ï@4‹úHÑN
Ñ4@ô¯%D—Ð
ÜÐ“0À˜R`Ìùj‡8£JØ£J£ÂãÌAãœVì}8™4.MóÐŒ½Gk™ó¢{Ñ@4îC¿úû°fáû0·ð}Xº3x!dü}füœ¾3~mô}˜ÅŠYQQÝ‡YQQÝ‡YQQÝ‡ñ5^Gãô>j·A¤¾Ý0vO_ŠÊˆäz7¹o¿ºÐ}Xoß‡,>lœJ—µ›¢ãŸg�¼×s¥\¯+·¥+ÕYÈˆ¾/‹w#‰ü-¤¤ø.]Øeš}aßé½ç¥Ò7°qÐ¸#ü ú˜T‰$kåÚ¡�,P •ã…PK™¾
s¢3!ÅÇ´bþd—-m¹ì/ðø,¿6ÔFSæ¡j!½M§çx;öÜì}_$®ŸV¬�ÈGõuvœ`en‘/îJ#"ÑµW¤9Œ,ƒå”‘NZ^yFv7>¶êA¤‘K±ßäŠhÇtÚoæ¶J‡IkØî¹ZïE7¸�éÝH7¸Ï¥\š˜*o?QšEið5I¨pãC^sÅÊz\6d'˜¡DxŒ)Im8r¶p‘Û™¥÷þ0F‡.�°dòÝöÚÂ”Â7Ôö#Iét²°FÈrT hX9¥äà}g•…Z(€VóêÑL¨è¨h<VíÆjRë0o¬µ¸±Gn¬A±%ÔæúL*Ýøqb{ìæ2Êë
Æ	,ÜÎ¶˜Õ¿˜(-3ËîB ù{(%fW±‘‡Š³3#e¯46V.Bùa+y²86ëÍ
Œd[&7¥Ü‡]ç�)
Îk° J�j"‘ç°¦«q¯<^-]ÑyFí¼NÂt¶�ä
£áU£ewéa”ïÐÈlP˜ÚZœ»í^•zÃ¾aÊÌ˜ßp6d¿5Èksn^�Ê«]èÛ¯5¼LÙh¡¢õªhƒ£ßøAî·Q¿A€^Ji¬µÞ­L
šÅMÖ"~­â×æ'Ñ
ÖI@ê�yª((ƒ+oqâ­N¼ÍˆQ¯ƒXÓ©
Ê¬ÛRCjHièÖ/‰¥
íUeƒÿòlíˆ:[½ 3XÎ§l—R [¬äPw°ŠC«ƒ5Z¬ãÐú`‡6›lu0Òeì‘èÐfG[,‡Ù[â²I>j«Î®òlß¦Îö#|¶“»�#‘g;�ã·“	çs"Aðïï€š7~�Ø{ÀC%Ï¨¤Oyãè'n÷x7n8€O‹Ö žul*ÊºÁX�„{ÃÔ8
:{c…ÉrqnšþEçÔ>B	ºSúD™øË³3sPþÁ²PE1U–ä¡^“�«8ÞA8BqÀ3…Ñ	‡ro0ÌCv³� €rí|Ï\[×Š<Ð�?Ä¨hÕûn;Óï;ù;Kcž¯åŽ KŒ#}SDZúîŒÁóœ+c§[¨ÆõD];hX�®³¯‹$š›¹â%Ç½?nƒs¢^¾ÈÓZ>¶Ò|}=HFÚdl$ÏtHñÅIkã£­
"ÏúY‘MYŠ,…Èwsi‡È?«¡È2ˆLÖS¤"�Mé„ÈŽVqµµáCVïw’·Vy(á�½}û%¶”4…kÁrN]§,EVˆ¬ð²BÌ�õ»½`¥*�}þÌÏÏ{Ù={öÐzœ1èH’ÜÕ‚bŠƒvãËµiñp·*GôŸÓý¯µúGh|ï{ßÓ•õˆP‡Cá1ø±cHÆŽ!1†VÃ;Ü‡ç¥<9.Ia£)$î&ÛM*¶›T…nþæoþFu“­¦1Ý€N\âÖöŠ»W¯`ìnÃÚ?þñ�½ì¿ûw¯T±ÛZiÑŸ\ÅV¿÷½Ï[pÿ´Rúc´ZÕŠµR»ôg±ëÐJSu+èþ—Æ;q6DÀå'?ùÉOïÛóÛíáwu‡û0æx7œâÞä½Ž3ø§t6ˆåh£a¾‘Ãîú;t­í~= �Øú?‹×Ãðç×Zµ»w¶F]kßùÎ·«½Öäð~øÃVy{ETþîwÿC•—T\Ï‹¼¤Ät_ÌëíŸß3?¿gîàÇŠ˜Ýù±þËÌÏwïÏwï?J,©Îÿ9–„°æ-ñÿï­¯çùsL¬Ú/äÞÏ&Æ’"ÝL0Ýœ8e¹f3Éûü»V
­CUš´yPb™=ëƒ4‡¢ÔóÒyÅÍIshSÐÃÂ›ÝÞÃJÝRäcKä§6²UqrŽb¯’“s4ž“c±êÿy+Ô¼±.õ`eNN$¿Ù7Ä‘A[wÊçg,Þå‚+Na²8S-›ÞäÈ“n‹Ëf�eh;iý—ÁáTiªâ³GðÖCÌtê«0âÎ›IŽ4ƒÉæ"Î«‹PgI1=úÂ,÷Œò<Ks³�k0º"¹L³âÿoXü?)
”¦ÉïÄts¹85Ç­�”.—ò¥©ûGaýÀMí©‰ÉIjZ+N�bÂkcZÍ¨­B®i«ab…%'là:€
‰9&ÇË–(—&'"Ta~Fy`¯4þy`i[ZÂöPº^ÉLˆC-Èá±æšÂÈ*ÎV
ÕdíosíZ-Ð°M[7Ý·*‘=Q˜ºCAÆ�ÈÂ0ê
SwfÊÝ
ØßïÖzHkšèLn&Q«ŠµÒ­EÂRãˆ3Á×_ì’|ø“	^.aó²Kó¬F“òüM¸ÕSE’,œ˜‰´VÈ9r'‡©d©MòXšÁ‚y­Ïf|œjVÜjËò,#Z+ËªÐÄŠ�$+ÚÊö·—‡ZnÀ–Ü–—cË
< ®PµzSYWëÊ³³”vªÕ™¢ÍºÚŠ¼‚N€ ±S­«ÕºÕVæYt«u‡ªÕ˜DºZwžåÆ�}š–û´6ÂJO"XÅ»ÛN]Í,];u�@~ÐkÄÚÔ€Zˆ—Ù÷Ìßd(i�t„†ãX+~ëÅ–ˆû
~½xwÔùµÒ%ÉÄ;‡knŒ¯Y/êÖ¡Œ¹Uó®Ù õbÐó®	¬FDÁDYö©§žbœ–oµ ¼”Â`±í¡§šFÉŒ&ð�ýT“
Ú/ršLÎY=ŽŒV|ù&.Mèp»SØl]R6«¯mÌ8ü ñMl\!Ô8§”]8|Z
³%qk�¶`Â(ØJÿ’ÍÛõ€ð¤ƒÎîØ
õ@Ç>uì/¢ã*V²;¼’¿ýÛ¿o§?°z'd›¥§ê}Q«½ÇX/ÑQ’:JVÕÑ"ÖueŠÖu®ëŸ{·–{ÁÎì_‹^©û«W¯zÙW^y%æzæ€ž4ÔÁL1a¹ž¬tü„S•úÐWg²	/îMJÞ–¤	ïÂ	 úX©bó5§'""7–ïÌ²ÓhÎl jºû»Ø™ý;¯ÒùÒb¶\5ü;äñRuecT�Æâ™Ó2vbÊ‹{ïÓÂ|”]íÖ×Îó¨h“•«³§£ŠŒOeÀFVjÀÄo	£´}
îl×WT{~@"10¦aN`Ç½YáRÎ¹›U:ÙÏù¹Š�ó}¾|Çg¼š/7²ËFv{Ù‘=^fd¯—Ùçù#û½óÉê/{ò�œsàMý1—Ã2>ó¬Z„.œêÍyÍ­Y›ÀXV*<×JC[6–q†–4‡Vý>1]–í¡}—ï»¬&šU;>?ÔjÔñ�Œ¥[:é…¾º·ŸìW¤³Béì¾(îÁ¿ñï!I:Ã÷Hpo}‹ÜM];¬¨kGâ©k^p48ÆÔµ•Áq%g}bàÖƒZoúxéÕÁûuð”×Aí¯Lñ$»_ŸA§.ÓG¸utod‹±¬oE±]ôÏn‚t@-!ð´Ä0ýn¿¤öGÂyqÀ€ØpA;¼[«<Ï6æ"ÔtÝZíEpp"’ð×%¦âÍ ÍFRq¡—Ó¢H§'îÕ‹RëŸºV«ªµ³¢ÈJÐ>ðl%Z(¤šË<OG«jõ¼(Òí‰‹Ê3­|[Æ¹ºÄ5g›ëªªå1Qd•'�oaƒi]·Öy1ÖÐªê+/Š¬'�¤µ³.˜ž™P5dÖHÈŒ”¦fgJ“åíç&.OOIRŸ c¥TÕòý¢ÈZïV³±’Ljì‚)p¸ª¦E‘õr�Ñú]°eŒxÕ[wƒw«Íž¼šöÙbõË³ÌƒÝi�²—èßeúT¬ª6ÿ_Qd�w£×Ë	>¤&'iòš€
“¿’,ËÉödÜ%&µIéÔáˆÌ¤tN‚Çš™Éâ~^,'×ÄˆW1ãc¢Àÿâªÿþÿÿþÿÿþÿ	ÿþÿiconÿþÿÿþÿiconöƒFôÈÿ¾L“ì¡sÎ¶ÿþÿÿþÿlabelÿþÿButtonÿþÿlabelE»b[cF•EÀ\G½ŒÿþÿÿþÿlabelPlacementÿþÿleftÿþÿrightÿþÿtopÿþÿbottomÿþÿlabelPlacementå•¢T åIŸÄß^æãD©ÿþÿÿþÿselectedÿþÿfalseÿþÿselectedî/Ï?ëZJ�ñ…ƒ|úìgÿþÿÿþÿtoggleÿþÿfalseÿþÿtoggleg¿¥íY˜D¾ê±Ìœ²ÿþÿÿþÿenabledÿþÿtrueÿþÿenabled!º—À­RG¸5S8ìêbmÿþÿOtherÿþÿvisibleÿþÿtrueÿþÿvisibleD*Lc³XTC¦$úv±¢ÿþÿOtherÿþÿ	minHeightÿþÿ0ÿþÿ	minHeightÃP¬»¸K¨‰u@•&ÓjÿþÿSizeÿþÿminWidthÿþÿ0ÿþÿminWidth!7“C2«I”»¼ú l/›ÿþÿSizeÿþÿÿý)<?xml version="1.0" encoding ="utf-8"?>

<componentPackage xmlns="http://www.macromedia.com/flash/swccatalog/7">

<component id="Button" class="mx.controls.Button" implementation="Button.swf" iconFile="Button.png" tooltip="Button" src="mx.controls.Button.asi" modified="1059073889">

<movieBounds xmin="0" xmax="2000" ymin="0" ymax="440" />

    <include id="BoundingBox"/>

    <include id="SimpleButton"/>

    <include id="Border"/>

    <include id="RectBorder"/>

    <include id="ButtonSkin"/>

    <exportAfter id="__Packages.mx.controls.Button"/>

<class id="mx.controls.Button" >

      <Event param1="click" />

      <TagName param1="Button" />

      <IconFile param1="Button.png" />

   <property id="_inherited_selected" type="Boolean" >

      <Bindable />

      <ChangeEvent param1="click" />

   </property>

   <method id="icon" >

      <param id="linkage"  />

      <Inspectable defaultValue="" />

   </method>

   <method id="label" >

      <param id="lbl" type="String" />

      <Inspectable defaultValue="Button" />

   </method>

   <method id="labelPlacement" >

      <param id="val" type="String" />

      <Inspectable enumeration="left,right,top,bottom" defaultValue="right" />

   </method>

</class>

<class id="mx.controls.SimpleButton" >

      <Event param1="click" />

      <TagName param1="SimpleButton" />

   <method id="selected" returnType="Boolean">

      <Inspectable defaultValue="false" />

   </method>

   <method id="toggle" returnType="Boolean">

      <Inspectable defaultValue="false" />

   </method>

</class>

<class id="mx.core.UIComponent" >

      <Event param1="focusIn" />

      <Event param1="focusOut" />

      <Event param1="keyDown" />

      <Event param1="keyUp" />

   <property id="enabled" type="Boolean" >

      <Inspectable defaultValue="true" verbose="1" category="Other" />

   </property>

</class>

<class id="mx.core.UIObject" >

      <Event param1="resize" />

      <Event param1="move" />

      <Event param1="draw" />

      <Event param1="load" />

      <Event param1="unload" />

   <method id="minHeight" returnType="Number">

      <Inspectable defaultValue="0" verbose="1" category="Size" />

   </method>

   <method id="minWidth" returnType="Number">

      <Inspectable defaultValue="0" verbose="1" category="Size" />

   </method>

   <method id="visible" returnType="Boolean">

      <Inspectable defaultValue="true" verbose="1" category="Other" />

   </method>

</class>

<asset id="BoundingBox" modified="1054593655">

</asset>

<asset id="UIComponentExtensions" modified="1058814666">

      <exportAfter id="__Packages.mx.core.ext.UIComponentExtensions"/>

</asset>

<asset id="FocusRect" modified="1055744819">

      <include id="BoundingBox"/>

      <exportAfter id="__Packages.mx.skins.halo.FocusRect"/>

</asset>

<asset id="FocusManager" modified="1055744781">

      <include id="FocusRect"/>

      <include id="UIObject"/>

      <exportAfter id="__Packages.mx.managers.FocusManager"/>

</asset>

<asset id="UIObjectExtensions" modified="1058814702">

      <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions"/>

</asset>

<asset id="Defaults" modified="1055737279">

      <exportAfter id="__Packages.mx.skins.halo.Defaults"/>

</asset>

<asset id="UIObject" modified="1058814731">

      <include id="Defaults"/>

      <include id="UIObjectExtensions"/>

      <exportAfter id="__Packages.mx.core.UIObject"/>

</asset>

<asset id="UIComponent" modified="1058814700">

      <include id="UIObject"/>

      <include id="FocusManager"/>

      <include id="UIComponentExtensions"/>

      <exportAfter id="__Packages.mx.core.UIComponent"/>

</asset>

<asset id="SimpleButtonUp" modified="1062225026">

      <include id="BrdrBlk"/>

      <include id="BrdrFace"/>

      <include id="BrdrShdw"/>

      <include id="BrdrHilght"/>

      <include id="BrdrFace"/>

</asset>

<asset id="BrdrHilght" modified="1052770908">

</asset>

<asset id="BrdrBlk" modified="1052770913">

</asset>

<asset id="SimpleButtonIn" modified="1062225020">

      <include id="BrdrBlk"/>

      <include id="BrdrHilght"/>

      <include id="BrdrShdw"/>

      <include id="BrdrFace"/>

</asset>

<asset id="BrdrFace" modified="1051767541">

</asset>

<asset id="BrdrShdw" modified="1058931521">

</asset>

<asset id="SimpleButtonDown" modified="1062225019">

      <include id="BrdrShdw"/>

      <include id="BrdrFace"/>

</asset>

<asset id="SimpleButton" modified="1055744781">

      <include id="BoundingBox"/>

      <include id="SimpleButtonDown"/>

      <include id="SimpleButtonIn"/>

      <include id="SimpleButtonUp"/>

      <include id="UIComponent"/>

      <exportAfter id="__Packages.mx.controls.SimpleButton"/>

</asset>

<asset id="Border" modified="1062224872">

      <include id="UIObject"/>

      <exportAfter id="__Packages.mx.skins.Border"/>

</asset>

<asset id="RectBorder" modified="1062224887">

      <include id="Border"/>

      <exportAfter id="__Packages.mx.skins.halo.RectBorder"/>

</asset>

<asset id="ButtonSkin" modified="1062224893">

      <exportAfter id="__Packages.mx.skins.halo.ButtonSkin"/>

</asset>

<asset id="__Packages.mx.skins.ColoredSkinElement" src="mx.skins.ColoredSkinElement.asi" modified="1062582563">

</asset>

<asset id="__Packages.mx.core.UIObject" src="mx.core.UIObject.asi" modified="1062582563">

    <include id="__Packages.mx.skins.SkinElement" />

    <include id="__Packages.mx.styles.CSSStyleDeclaration" />

    <include id="__Packages.mx.styles.StyleManager" />

</asset>

<asset id="__Packages.mx.skins.SkinElement" src="mx.skins.SkinElement.asi" modified="1062582564">

</asset>

<asset id="__Packages.mx.styles.CSSTextStyles" src="mx.styles.CSSTextStyles.asi" modified="1062582564">

</asset>

<asset id="__Packages.mx.styles.CSSStyleDeclaration" src="mx.styles.CSSStyleDeclaration.asi" modified="1062582564">

    <include id="__Packages.mx.styles.StyleManager" />

    <exportAfter id="__Packages.mx.styles.CSSTextStyles" />

</asset>

<asset id="__Packages.mx.styles.StyleManager" src="mx.styles.StyleManager.asi" modified="1062582564">

</asset>

<asset id="__Packages.mx.core.UIComponent" src="mx.core.UIComponent.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.controls.SimpleButton" src="mx.controls.SimpleButton.asi" modified="1061503691">

    <exportAfter id="__Packages.mx.core.UIComponent" />

</asset>

<asset id="__Packages.mx.controls.Button" src="mx.controls.Button.asi" modified="1061503690">

    <exportAfter id="__Packages.mx.controls.SimpleButton" />

    <exportAfter id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.events.EventDispatcher" src="mx.events.EventDispatcher.asi" modified="1062582563">

</asset>

<asset id="__Packages.mx.events.UIEventDispatcher" src="mx.events.UIEventDispatcher.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.events.EventDispatcher" />

</asset>

<asset id="__Packages.mx.core.ext.UIObjectExtensions" src="mx.core.ext.UIObjectExtensions.asi" modified="1062582563">

    <include id="__Packages.mx.skins.ColoredSkinElement" />

    <include id="__Packages.mx.styles.CSSStyleDeclaration" />

    <exportAfter id="__Packages.mx.core.UIObject" />

    <exportAfter id="__Packages.mx.skins.SkinElement" />

    <exportAfter id="__Packages.mx.styles.CSSTextStyles" />

    <exportAfter id="__Packages.mx.events.UIEventDispatcher" />

</asset>

<asset id="__Packages.mx.skins.halo.Defaults" src="mx.skins.halo.Defaults.asi" modified="1062582564">

    <include id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.core.UIObject" />

    <exportAfter id="__Packages.mx.styles.CSSStyleDeclaration" />

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

</asset>

<asset id="__Packages.mx.skins.halo.FocusRect" src="mx.skins.halo.FocusRect.asi" modified="1062582564">

    <include id="__Packages.mx.managers.DepthManager" />

    <exportAfter id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.skins.SkinElement" />

    <exportAfter id="__Packages.mx.skins.halo.Defaults" />

</asset>

<asset id="__Packages.mx.managers.DepthManager" src="mx.managers.DepthManager.asi" modified="1062582563">

    <include id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.managers.FocusManager" src="mx.managers.FocusManager.asi" modified="1062726409">

    <include id="__Packages.mx.controls.SimpleButton" />

    <include id="__Packages.mx.managers.DepthManager" />

    <include id="__Packages.mx.managers.SystemManager" />

    <exportAfter id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

</asset>

<asset id="__Packages.mx.managers.SystemManager" src="mx.managers.SystemManager.asi" modified="1062582563">

    <include id="__Packages.mx.core.UIComponent" />

    <include id="__Packages.mx.events.EventDispatcher" />

</asset>

<asset id="__Packages.mx.managers.OverlappedWindows" src="mx.managers.OverlappedWindows.asi" modified="1062582563">

    <include id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.managers.SystemManager" />

</asset>

<asset id="__Packages.mx.core.ext.UIComponentExtensions" src="mx.core.ext.UIComponentExtensions.asi" modified="1062582563">

    <include id="__Packages.mx.styles.CSSSetStyle" />

    <exportAfter id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.managers.FocusManager" />

    <exportAfter id="__Packages.mx.managers.OverlappedWindows" />

</asset>

<asset id="__Packages.mx.styles.CSSSetStyle" src="mx.styles.CSSSetStyle.asi" modified="1062582564">

    <include id="__Packages.mx.styles.StyleManager" />

    <exportAfter id="__Packages.mx.styles.CSSStyleDeclaration" />

</asset>

<asset id="__Packages.mx.skins.Border" src="mx.skins.Border.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.skins.RectBorder" src="mx.skins.RectBorder.asi" modified="1062582564">

    <exportAfter id="__Packages.mx.skins.Border" />

</asset>

<asset id="__Packages.mx.skins.halo.ButtonSkin" src="mx.skins.halo.ButtonSkin.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

    <exportAfter id="__Packages.mx.skins.RectBorder" />

</asset>

<asset id="__Packages.mx.skins.halo.RectBorder" src="mx.skins.halo.RectBorder.asi" modified="1062582564">

    <include id="__Packages.mx.styles.CSSStyleDeclaration" />

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

    <exportAfter id="__Packages.mx.skins.RectBorder" />

</asset>

</component>

</componentPackage>

Media 1ÿþÿBitmap 1ÿþÿ
Button.png·Ô±C·Ô±Cÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿ2Hxií’Ñ	@!EÛéíäNw'w*¯ øQa}Æ$K=™ÙÚÛÒEäFsW<_µ,)�œCQj>˜QYÅ§œïZqªuDÜŠSyK0þzöÏÏúÀÏÃ_Y?AžŽ÷7šÆðIsQŸ$ÅÿþÿButtonÐ¸ÿþÿButtonÿþÿ
Button.swf	ëW?+ÿþÿBorderÿþÿBorderÿþÿ
Button.swfèCP?ÿþÿUIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.Borderÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿBoundingBoxÿþÿBoundingBoxÿþÿ
Button.swfwÒÛ>ÿþÿÿþÿÿþÿBrdrBlkÿþÿBrdrBlkÿþÿ
Button.swfaÀ>ÿþÿÿþÿÿþÿBrdrFaceÿþÿBrdrFaceÿþÿ
Button.swfõ²°>ÿþÿÿþÿÿþÿ
BrdrHilghtÿþÿ
BrdrHilghtÿþÿ
Button.swf\À>ÿþÿÿþÿÿþÿBrdrShdwÿþÿBrdrShdwÿþÿ
Button.swfA?ÿþÿÿþÿÿþÿ
ButtonSkinÿþÿ
ButtonSkinÿþÿ
Button.swfýCP?ÿþÿ#__Packages.mx.skins.halo.ButtonSkinÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿDefaultsÿþÿDefaultsÿþÿ
Button.swf¿Eí>‚ýÿÿÿƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿFocusManagerÿþÿFocusManagerÿþÿ
Button.swf
cí>ÿþÿ	FocusRectÿþÿ
Button.swfÿþÿÿþÿÿþÿUIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿ	FocusRectÿþÿ	FocusRectÿþÿ
Button.swf3cí>ÿþÿBoundingBoxÿþÿ
Button.swfÿþÿÿþÿÿþÿ"__Packages.mx.skins.halo.FocusRectÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿ
RectBorderÿþÿ
RectBorderÿþÿ
Button.swf÷CP?ÿþÿBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.skins.halo.RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonÿþÿSimpleButtonÿþÿ
Button.swf
cí>ÿþÿBoundingBoxÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonDownÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonInÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonUpÿþÿ
Button.swfÿþÿÿþÿÿþÿUIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonDownÿþÿSimpleButtonDownÿþÿ
Button.swf{DP?ÿþÿBrdrShdwÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonInÿþÿSimpleButtonInÿþÿ
Button.swf|DP?ÿþÿBrdrBlkÿþÿ
Button.swfÿþÿÿþÿÿþÿ
BrdrHilghtÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrShdwÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonUpÿþÿSimpleButtonUpÿþÿ
Button.swf‚DP?ÿþÿBrdrBlkÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrShdwÿþÿ
Button.swfÿþÿÿþÿÿþÿ
BrdrHilghtÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIComponentÿþÿUIComponentÿþÿ
Button.swfì:?ÿþÿUIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿFocusManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿUIComponentExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIComponentExtensionsÿþÿUIComponentExtensionsÿþÿ
Button.swfÊ:?ÿþÿ,__Packages.mx.core.ext.UIComponentExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIObjectÿþÿUIObjectÿþÿ
Button.swf;?ÿþÿDefaultsÿþÿ
Button.swfÿþÿÿþÿÿþÿUIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIObjectExtensionsÿþÿUIObjectExtensionsÿþÿ
Button.swfî:?ÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿ__Packages.mx.controls.Buttonÿþÿ__Packages.mx.controls.Buttonÿþÿ
Button.swfÊBE?ÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.controls.Buttonÿþÿÿqimport mx.core.UIObject;

import mx.controls.SimpleButton;

import mx.core.UIComponent;



[Event("click")] 

[TagName("Button")] 

[IconFile("Button.png")] 

intrinsic class mx.controls.Button extends mx.controls.SimpleButton

{

   public function Button();

   public var __get__icon:Function;

   public var __get__label:Function;

   public var __get__labelPlacement:Function;

   public var __label:String;

   public var __labelPlacement:String;

   public var _color;

   public function _getIcon(Void):String;

   public var _iconLinkageName:String;

   [Bindable] [ChangeEvent("click")] public var _inherited_selected:Boolean;

   public function _setIcon(linkage):Void;

   public var borderW:Number;

   public var btnOffset:Number;

   public function calcSize(tag:Number, ref:Object):Void;

   public var centerContent:Boolean;

   public var className:String;

   public var clipParameters:Object;

   public function createChildren(Void):Void;

   public function draw();

   public var falseDisabledIcon:String;

   public var falseDisabledSkin:String;

   public var falseDownIcon:String;

   public var falseDownSkin:String;

   public var falseOverIcon:String;

   public var falseOverSkin:String;

   public var falseUpIcon:String;

   public var falseUpSkin:String;

   public function getBtnOffset(Void):Number;

   public function getLabel(Void):String;

   public function getLabelPlacement(Void):String;

   public var hitArea_mc:MovieClip;

   function get icon():String;

   [Inspectable(defaultValue="")] function set icon(linkage);

   public function init(Void):Void;

   public var initIcon;

   public function invalidateStyle(c:String):Void;

   [Inspectable(defaultValue="Button")] function set label(lbl:String);

   function get label():String;

   public var labelPath:Object;

   [Inspectable(enumeration="left,right,top,bottom"defaultValue="right")] function set labelPlacement(val:String);

   function get labelPlacement():String;

   static var mergedClipParameters:Boolean;

   public function onRelease(Void):Void;

   public function setColor(c:Number):Void;

   public function setEnabled(enable:Boolean):Void;

   public function setHitArea(w:Number, h:Number);

   public function setLabel(label:String):Void;

   public function setLabelPlacement(val:String):Void;

   public function setSkin(tag:Number, linkageName:String, initobj:Object):MovieClip;

   public function setView(offset:Number):Void;

   public function size(Void):Void;

   static var symbolName:String;

   static var symbolOwner;

   public var trueDisabledIcon:String;

   public var trueDisabledSkin:String;

   public var trueDownIcon:String;

   public var trueDownSkin:String;

   public var trueOverIcon:String;

   public var trueOverSkin:String;

   public var trueUpIcon:String;

   public var trueUpSkin:String;

   static var version:String;

   public function viewSkin(varName:String):Void;

};

ÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfËBE?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.controls.SimpleButtonÿþÿÿimport mx.core.UIComponent;



[Event("click")] 

[TagName("SimpleButton")] 

intrinsic class mx.controls.SimpleButton extends mx.core.UIComponent

{

   public function SimpleButton();

   public var __emphasized:Boolean;

   public var __emphatic:Boolean;

   public var __emphaticStyleName:String;

   public var __get__emphasized:Function;

   public var __get__selected:Function;

   public var __get__toggle:Function;

   public var __get__value:Function;

   public var __state:Boolean;

   public var __toggle:Boolean;

   public var autoRepeat:Boolean;

   public var boundingBox_mc:MovieClip;

   public var btnOffset:Number;

   public var buttonDownHandler:Function;

   public function calcSize(Void):Void;

   public function changeIcon(tag:Number, linkageName:String):Void;

   public function changeSkin(tag:Number, linkageName:String):Void;

   public var className:String;

   public var clickHandler:Function;

   public function createChildren(Void):Void;

   public var detail:Number;

   public var dfi;

   public var dfs;

   public var disabledIcon:Object;

   public var disabledSkin:Object;

   public var downIcon:Object;

   public var downSkin:Object;

   public function draw(Void):Void;

   public var dti;

   public var dts;

   function get emphasized():Boolean;

   function set emphasized(val:Boolean);

   static var emphasizedStyleDeclaration;

   static var falseDisabled:Number;

   public var falseDisabledIcon:String;

   public var falseDisabledIconEmphasized:String;

   public var falseDisabledSkin:String;

   public var falseDisabledSkinEmphasized:String;

   static var falseDown:Number;

   public var falseDownIcon:String;

   public var falseDownIconEmphasized:String;

   public var falseDownSkin:String;

   public var falseDownSkinEmphasized:String;

   static var falseOver:Number;

   public var falseOverIcon:String;

   public var falseOverIconEmphasized:String;

   public var falseOverSkin:String;

   public var falseOverSkinEmphasized:String;

   static var falseUp:Number;

   public var falseUpIcon:String;

   public var falseUpIconEmphasized:String;

   public var falseUpSkin:String;

   public var falseUpSkinEmphasized:String;

   public var fdi;

   public var fds;

   public var fri;

   public var frs;

   public var fui;

   public var fus;

   public function getLabel(Void):String;

   public function getSelected():Boolean;

   public function getState(Void):Boolean;

   public function getToggle(Void):Boolean;

   public var iconName:Object;

   public var idNames;

   public function init(Void):Void;

   public var initializing:Boolean;

   public var interval;

   public function keyDown(e:Object):Void;

   public function keyUp(e:Object):Void;

   public var linkLength:Number;

   public function onDragOut(Void):Void;

   public function onDragOver(Void):Void;

   public function onKillFocus(newFocus:Object):Void;

   public function onPress(Void):Void;

   public function onPressDelay(Void):Void;

   public function onPressRepeat(Void):Void;

   public function onRelease(Void):Void;

   public function onReleaseOutside(Void):Void;

   public function onRollOut(Void):Void;

   public function onRollOver(Void):Void;

   public var phase:String;

   public var preset:Boolean;

   public var refNames;

   public function refresh(Void):Void;

   public function removeIcons();

   public var rolloverIcon:Object;

   public var rolloverSkin:Object;

   function set selected(val:Boolean);

   [Inspectable(defaultValue=false)] function get selected():Boolean;

   public function setEnabled(val:Boolean):Void;

   public function setIcon(tag:Number, linkageName:String):Object;

   public function setLabel(val:String):Void;

   public function setSelected(val:Boolean);

   public function setSkin(tag:Number, linkageName:String, initobj:Object):MovieClip;

   public function setState(state:Boolean):Void;

   public function setStateVar(state:Boolean):Void;

   public function setToggle(val:Boolean);

   public function setView(offset:Boolean):Void;

   public function showEmphasized(e:Boolean):Void;

   public function size(Void):Void;

   public var skinName:Object;

   public var stateNames;

   public var style3dInset:Number;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tagMap;

   public var tdi;

   public var tds;

   function set toggle(val:Boolean);

   [Inspectable(defaultValue=false)] function get toggle():Boolean;

   public var tri;

   public var trs;

   static var trueDisabled:Number;

   public var trueDisabledIcon:String;

   public var trueDisabledIconEmphasized:String;

   public var trueDisabledSkin:String;

   public var trueDisabledSkinEmphasized:String;

   static var trueDown:Number;

   public var trueDownIcon:String;

   public var trueDownIconEmphasized:String;

   public var trueDownSkin:String;

   public var trueDownSkinEmphasized:String;

   static var trueOver:Number;

   public var trueOverIcon:String;

   public var trueOverIconEmphasized:String;

   public var trueOverSkin:String;

   public var trueOverSkinEmphasized:String;

   static var trueUp:Number;

   public var trueUpIcon:String;

   public var trueUpIconEmphasized:String;

   public var trueUpSkin:String;

   public var trueUpSkinEmphasized:String;

   public var tui;

   public var tus;

   public var upIcon:Object;

   public var upSkin:Object;

   function set value(val:Boolean);

   function get value():Boolean;

   static var version:String;

   public function viewIcon(varName:String):Void;

   public function viewSkin(varName:String, initObj:Object):Void;

};

ÿþÿ__Packages.mx.core.UIComponentÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.core.UIComponentÿþÿÿþimport mx.core.UIObject;

import mx.skins.SkinElement;



[Event("focusIn")] 

[Event("focusOut")] 

[Event("keyDown")] 

[Event("keyUp")] 

intrinsic class mx.core.UIComponent extends mx.core.UIObject

{

   public function UIComponent();

   public var clipParameters:Object;

   public function dispatchValueChangedEvent(value):Void;

   public var drawFocus:Function;

   [Inspectable(defaultValue=true, verbose=1, category="Other")] public var enabled:Boolean;

   public function enabledChanged(id:String, oldValue:Boolean, newValue:Boolean):Boolean;

   public function findFocusFromObject(o:Object):Object;

   public function findFocusInChildren(o:Object):Object;

   public var focusEnabled:Boolean;

   public var focusManager:MovieClip;

   public var focusTextField:Object;

   public function getFocus():Object;

   public function getFocusManager():Object;

   public var groupName:String;

   function get height():Number;

   public function init():Void;

   public function isParent(o:Object):Boolean;

   static var kStretch:Number;

   static var mergedClipParameters:Boolean;

   public function onKillFocus(newFocus:Object):Void;

   public function onSetFocus(oldFocus:Object):Void;

   public var origBorderStyles:Object;

   public var origBorderValues:Object;

   public var popUp:Boolean;

   public function pressFocus():Void;

   public function releaseFocus():Void;

   public function setEnabled(enabled:Boolean):Void;

   public function setFocus():Void;

   public function setVisible(x:Boolean, noEvent:Boolean):Void;

   public function size():Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tabEnabled:Boolean;

   public var tabIndex:Number;

   static var version:String;

   function get width():Number;

};

ÿþÿ__Packages.mx.core.UIObjectÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.core.UIObjectÿþÿÿÃimport mx.styles.StyleManager;

import mx.styles.CSSStyleDeclaration;

import mx.skins.SkinElement;



[Event("resize")] 

[Event("move")] 

[Event("draw")] 

[Event("load")] 

[Event("unload")] 

intrinsic class mx.core.UIObject extends MovieClip

{

   public function UIObject();

   public function __getTextFormat(tf:TextFormat, bAll:Boolean):Boolean;

   public var __get__minHeight:Function;

   public var __get__minWidth:Function;

   public var __get__scaleX:Function;

   public var __get__scaleY:Function;

   public var __get__visible:Function;

   public var __height:Number;

   private var __onUnload:Function;

   public var __width:Number;

   public var _color;

   public function _createChildren(Void):Void;

   private var _endInit:Function;

   public function _getTextFormat(Void):TextFormat;

   private var _id:String;

   private var _maxHeight:Number;

   private var _maxWidth:Number;

   private var _minHeight:Number;

   private var _minWidth:Number;

   private var _preferredHeight:Number;

   private var _preferredWidth:Number;

   private var _tf:TextFormat;

   public var _topmost:Boolean;

   public var addEventListener:Function;

   function get bottom():Number;

   public var buildDepthTable:Function;

   public function cancelAllDoLaters(Void):Void;

   public var changeColorStyleInChildren:Function;

   public var changeTextStyleInChildren:Function;

   public var childrenCreated:Boolean;

   public var className:String;

   public var clipParameters:Object;

   public var color:Number;

   public function constructObject(Void):Void;

   public var createAccessibilityImplementation:Function;

   public var createChildAtDepth:Function;

   public function createChildren(Void):Void;

   public var createClassChildAtDepth:Function;

   public function createClassObject(className:Function, id:String, depth:Number, initobj:Object):mx.core.UIObject;

   public function createEmptyObject(id:String, depth:Number):mx.core.UIObject;

   public var createEvent:Function;

   public function createLabel(name:String, depth:Number, text):TextField;

   public function createObject(linkageName:String, id:String, depth:Number, initobj:Object):MovieClip;

   public function createSkin(tag:Number):mx.core.UIObject;

   public function destroyObject(id:String):Void;

   public var dispatchEvent:Function;

   public function doLater(obj:Object, fn:String):Void;

   public function doLaterDispatcher(Void):Void;

   public function draw(Void):Void;

   public function drawRect(x1:Number, y1:Number, x2:Number, y2:Number):Void;

   public var embedFonts:Boolean;

   public var findNextAvailableDepth:Function;

   public var fontFamily:String;

   public var fontSize:Number;

   public var fontStyle:String;

   public var fontWeight:String;

   public function getClassStyleDeclaration(Void):mx.styles.CSSStyleDeclaration;

   public function getMinHeight(Void):Number;

   public function getMinWidth(Void):Number;

   public function getSkinIDName(tag:Number):String;

   public function getStyle(styleProp:String);

   public function getStyleName(Void):String;

   public var handleEvent:Function;

   function get height():Number;

   public var idNames:Array;

   public var ignoreClassStyleDeclaration:Object;

   public function init(Void):Void;

   public function initFromClipParameters(Void):Void;

   public var initProperties:Function;

   public function invalidate(Void):Void;

   private var invalidateFlag:Boolean;

   public function invalidateStyle(Void):Void;

   function get left():Number;

   private var lineColor:Number;

   private var lineWidth:Number;

   public var marginLeft:Number;

   public var marginRight:Number;

   static function mergeClipParameters(o, p):Boolean;

   public var methodTable:Array;

   [Inspectable(defaultValue=0, verbose=1, category="Size")] function get minHeight():Number;

   function set minHeight(h:Number):Void;

   [Inspectable(defaultValue=0, verbose=1, category="Size")] function get minWidth():Number;

   function set minWidth(w:Number):Void;

   public function move(x:Number, y:Number, noEvent:Boolean):Void;

   public var notifyStyleChangeInChildren:Function;

   public function redraw(bAlways:Boolean):Void;

   public var removeEventListener:Function;

   function get right():Number;

   function get scaleX():Number;

   function set scaleX(x:Number):Void;

   function get scaleY():Number;

   function set scaleY(y:Number):Void;

   public function setColor(color:Number):Void;

   public function setMinHeight(h:Number):Void;

   public function setMinWidth(w:Number):Void;

   public function setSize(w:Number, h:Number, noEvent:Boolean):Void;

   public function setSkin(tag:Number, linkageName:String, initObj:Object):MovieClip;

   public var setStyle:Function;

   public function setVisible(x:Boolean, noEvent:Boolean):Void;

   public function size(Void):Void;

   public var styleName:String;

   public var stylecache:Object;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tabEnabled:Boolean;

   public var textAlign:String;

   static var textColorList;

   public var textDecoration:String;

   public var textIndent:Number;

   private var tfList:Object;

   function get top():Number;

   public var validateNow:Boolean;

   static var version:String;

   [Inspectable(defaultValue=true, verbose=1, category="Other")] function get visible():Boolean;

   function set visible(x:Boolean):Void;

   function get width():Number;

   function get x():Number;

   function get y():Number;

};

ÿþÿ,__Packages.mx.core.ext.UIComponentExtensionsÿþÿ,__Packages.mx.core.ext.UIComponentExtensionsÿþÿ
Button.swf#¹U?ÿþÿ __Packages.mx.styles.CSSSetStyleÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.managers.OverlappedWindowsÿþÿ
Button.swfÿþÿÿþÿÿþÿ!mx.core.ext.UIComponentExtensionsÿþÿÿ:import mx.core.UIComponent;



intrinsic class mx.core.ext.UIComponentExtensions

{

   static function Extensions():Boolean;

   static var FocusManagerDependency;

   static var OverlappedWindowsDependency;

   static var UIComponentDependency;

   static var UIComponentExtended;

   static var bExtended;

};

ÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swf#¹U?ÿþÿ&__Packages.mx.skins.ColoredSkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ
Button.swfÿþÿÿþÿÿþÿ&__Packages.mx.events.UIEventDispatcherÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.core.ext.UIObjectExtensionsÿþÿÿûimport mx.core.UIObject;

import mx.styles.CSSStyleDeclaration;

import mx.skins.SkinElement;

import mx.events.UIEventDispatcher;



intrinsic class mx.core.ext.UIObjectExtensions

{

   static var CSSTextStylesDependency;

   static function Extensions():Boolean;

   static var SkinElementDependency;

   static var UIEventDispatcherDependency;

   static var UIObjectDependency;

   static var UIObjectExtended;

   static function addGeometry(tf:Object, ui:Object):Void;

   static var bExtended;

};

ÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ
Button.swf#¹U?ÿþÿmx.events.EventDispatcherÿþÿÿ

intrinsic class mx.events.EventDispatcher

{

   static var _fEventDispatcher:mx.events.EventDispatcher;

   static function _removeEventListener(queue:Object, event:String, handler):Void;

   public function addEventListener(event:String, handler):Void;

   public function dispatchEvent(eventObj:Object):Void;

   public function dispatchQueue(queueObj:Object, eventObj:Object):Void;

   static function initialize(object:Object):Void;

   public function removeEventListener(event:String, handler):Void;

};

ÿþÿ&__Packages.mx.events.UIEventDispatcherÿþÿ&__Packages.mx.events.UIEventDispatcherÿþÿ
Button.swf#¹U?ÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.events.UIEventDispatcherÿþÿÿimport mx.core.UIObject;

import mx.events.EventDispatcher;



intrinsic class mx.events.UIEventDispatcher extends mx.events.EventDispatcher

{

   public function __addEventListener(event:String, handler):Void;

   public var __origAddEventListener:Function;

   public var __sentLoadEvent;

   static var _fEventDispatcher:mx.events.UIEventDispatcher;

   static function addKeyEvents(obj:Object):Void;

   static function addLoadEvents(obj:Object):Void;

   public function dispatchEvent(eventObj:Object):Void;

   static function initialize(obj:Object):Void;

   static var keyEvents:Object;

   static var loadEvents:Object;

   static var lowLevelEvents:Object;

   public function onKeyDown(Void):Void;

   public function onKeyUp(Void):Void;

   public function onLoad(Void):Void;

   public function onUnload(Void):Void;

   public var owner:Object;

   public function removeEventListener(event:String, handler):Void;

   static function removeKeyEvents(obj:Object):Void;

   static function removeLoadEvents(obj:Object):Void;

};

ÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.DepthManagerÿþÿÿoimport mx.core.UIObject;



intrinsic class mx.managers.DepthManager

{

   public function DepthManager();

   static var __depthManager:mx.managers.DepthManager;

   public var _childCounter:Number;

   public var _parent:MovieClip;

   public var _topmost:Boolean;

   public function buildDepthTable(Void):Array;

   public function createChildAtDepth(linkageName:String, depthFlag:Number, initObj:Object):MovieClip;

   public function createClassChildAtDepth(className:Function, depthFlag:Number, initObj:Object):mx.core.UIObject;

   public var createClassObject:Function;

   static function createClassObjectAtDepth(className:Object, depthSpace:Number, initObj:Object):mx.core.UIObject;

   public var createObject:Function;

   static function createObjectAtDepth(linkageName:String, depthSpace:Number, initObj:Object):MovieClip;

   public function findNextAvailableDepth(targetDepth:Number, depthTable:Array, direction:String):Number;

   public var getDepth:Function;

   public function getDepthByFlag(depthFlag:Number, depthTable:Array):Number;

   static var highestDepth:Number;

   static private var holder:MovieClip;

   static var kBottom:Number;

   static var kCursor:Number;

   static var kNotopmost:Number;

   static var kTooltip:Number;

   static var kTop:Number;

   static var kTopmost:Number;

   static var lowestDepth:Number;

   static var numberOfAuthortimeLayers:Number;

   static var reservedDepth:Number;

   public function setDepthAbove(targetInstance:MovieClip):Void;

   public function setDepthBelow(targetInstance:MovieClip):Void;

   public function setDepthTo(depthFlag:Number):Void;

   public function shuffleDepths(subject:MovieClip, targetDepth:Number, depthTable:Array, direction:String):Void;

   static function sortFunction(a:MovieClip, b:MovieClip):Number;

   public var swapDepths:Function;

   static function test(depth:Number):Boolean;

};

ÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ
Button.swf	ëW?ÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.FocusManagerÿþÿÿêimport mx.core.UIObject;

import mx.managers.SystemManager;

import mx.controls.SimpleButton;

import mx.core.UIComponent;



intrinsic class mx.managers.FocusManager extends mx.core.UIComponent

{

   public function FocusManager();

   static var UIObjectExtensionsDependency;

   public var __defaultPushButton:mx.controls.SimpleButton;

   public var __get__defaultPushButton:Function;

   private var _firstNode:Object;

   private var _firstObj:Object;

   private var _foundList:Object;

   private var _lastNode:Object;

   private var _lastObj:Object;

   private var _lastTarget:Object;

   private var _lastx:Object;

   private var _needPrev:Boolean;

   private var _nextIsNext:Boolean;

   private var _nextNode:Object;

   private var _nextObj:Object;

   public function _onMouseDown(Void):Void;

   private var _prevNode:Object;

   private var _prevObj:Object;

   private var _searchKey:Number;

   public function activate(Void):Void;

   private var activated:Boolean;

   public var bDrawFocus:Boolean;

   public var bNeedFocus:Boolean;

   public var className:String;

   public function deactivate(Void):Void;

   public var defPushButton:mx.controls.SimpleButton;

   function get defaultPushButton():mx.controls.SimpleButton;

   function set defaultPushButton(x:mx.controls.SimpleButton);

   public var defaultPushButtonEnabled:Boolean;

   static function enableFocusManagement():Void;

   public function enabledChanged(id:String, oldValue:Boolean, newValue:Boolean):Boolean;

   public var form;

   public function getActualFocus(o:Object):Object;

   public function getFocus(Void):Object;

   public function getFocusManagerFromObject(o:Object):Object;

   public function getMaxTabIndex(o:mx.core.UIComponent):Number;

   public function getMousedComponentFromChildren(x:Number, y:Number, o:Object):Object;

   public function getNextTabIndex(Void):Number;

   public function getSelectionFocus():Object;

   public function getTabCandidate(o:MovieClip, index:Number, groupName:String, dir:Boolean, firstChild:Boolean):Void;

   public function getTabCandidateFromChildren(o:MovieClip, index:Number, groupName:String, dir:Boolean, firstChild:Boolean):Void;

   public function handleEvent(e:Object);

   public function init(Void):Void;

   static var initialized:Boolean;

   public function isOurFocus(o:Object):Boolean;

   public var lastFocus:Object;

   public var lastSelFocus:Object;

   public var lastTabFocus:Object;

   public var lastXMouse:Number;

   public var lastYMouse:Number;

   public function mouseActivate(Void):Void;

   function get nextTabIndex():Number;

   public function onKeyDown(Void):Void;

   public function onMouseUp(Void):Void;

   public function onSetFocus(o:Object, n:Object):Void;

   public function onUnload(Void):Void;

   public function relocate(Void):Void;

   public function restoreFocus(Void):Void;

   public function sendDefaultPushButtonEvent(Void):Void;

   public function setFocus(o:Object):Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   private var tabCapture:MovieClip;

   public function tabHandler(Void):Void;

   static var version:String;

   public function walkTree(p:MovieClip, index:Number, groupName:String, dir:Boolean, lookup:Boolean, firstChild:Boolean):Void;

};

ÿþÿ(__Packages.mx.managers.OverlappedWindowsÿþÿ(__Packages.mx.managers.OverlappedWindowsÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.OverlappedWindowsÿþÿÿ(import mx.managers.SystemManager;

import mx.core.UIComponent;



intrinsic class mx.managers.OverlappedWindows

{

   static var SystemManagerDependency;

   static function __addEventListener(e:String, o:Object, l:Function):Void;

   static function __removeEventListener(e:String, o:Object, l:Function):Void;

   static function activate(f:MovieClip):Void;

   static function addFocusManager(f:mx.core.UIComponent):Void;

   static function checkIdle(Void):Void;

   static function deactivate(f:MovieClip):Void;

   static function enableOverlappedWindows():Void;

   static var initialized:Boolean;

   static function onMouseDown(Void):Void;

   static function onMouseMove(Void):Void;

   static function onMouseUp(Void):Void;

   static function removeFocusManager(f:mx.core.UIComponent):Void;

};

ÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.SystemManagerÿþÿÿ�import mx.events.EventDispatcher;

import mx.core.UIComponent;



[Event("idle")] 

[Event("resize")] 

intrinsic class mx.managers.SystemManager

{

   static var __addEventListener:Function;

   static var __removeEventListener:Function;

   static var __screen:Object;

   static private var _initialized:Boolean;

   static var _xAddEventListener:Function;

   static var _xRemoveEventListener:Function;

   static var activate:Function;

   static var addEventListener:Function;

   static function addFocusManager(f:mx.core.UIComponent):Void;

   static var checkIdle:Function;

   static var deactivate:Function;

   static var dispatchEvent:Function;

   static var form:MovieClip;

   static var forms:Array;

   static var idleFrames:Number;

   static function init(Void):Void;

   static var interval:Number;

   static var isMouseDown;

   static function onMouseDown(Void):Void;

   static var onMouseMove:Function;

   static var onMouseUp:Function;

   static function onResize(Void):Void;

   static var removeEventListener:Function;

   static function removeFocusManager(f:mx.core.UIComponent):Void;

   static function get screen():Object;

};

ÿþÿ__Packages.mx.skins.Borderÿþÿ__Packages.mx.skins.Borderÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.Borderÿþÿÿhimport mx.core.UIObject;



intrinsic class mx.skins.Border extends mx.core.UIObject

{

   public function Border();

   public var borderStyle:String;

   public var className:String;

   public var idNames:Array;

   public function init(Void):Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tagBorder:Number;

};

ÿþÿ&__Packages.mx.skins.ColoredSkinElementÿþÿ&__Packages.mx.skins.ColoredSkinElementÿþÿ
Button.swf#¹U?ÿþÿmx.skins.ColoredSkinElementÿþÿÿ�

intrinsic class mx.skins.ColoredSkinElement

{

   public var _color;

   public function draw(Void):Void;

   public var getStyle:Function;

   public function invalidateStyle(Void):Void;

   static var mixins:mx.skins.ColoredSkinElement;

   public var onEnterFrame:Function;

   public function setColor(c:Number):Void;

   static function setColorStyle(p:Object, colorStyle:String):Void;

};

ÿþÿ__Packages.mx.skins.RectBorderÿþÿ__Packages.mx.skins.RectBorderÿþÿ
Button.swf$¹U?ÿþÿ__Packages.mx.skins.Borderÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.RectBorderÿþÿÿÅimport mx.skins.Border;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.skins.RectBorder extends mx.skins.Border

{

   public function RectBorder();

   public var __borderMetrics:Object;

   public var backgroundColorName:String;

   public var borderColorName:String;

   function get borderMetrics():Object;

   public var borderStyleName:String;

   public var buttonColorName:String;

   public var className:String;

   public function draw(Void):Void;

   public function drawBorder(Void):Void;

   public function getBorderMetrics(Void):Object;

   function get height():Number;

   public var highlightColorName:String;

   public function init(Void):Void;

   public var offset:Number;

   public function setColor(Void):Void;

   public var shadowColorName:String;

   public function size(Void):Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   static var version:String;

   function get width():Number;

};

ÿþÿ__Packages.mx.skins.SkinElementÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swf$¹U?ÿþÿmx.skins.SkinElementÿþÿÿ¥

intrinsic class mx.skins.SkinElement extends MovieClip

{

   public function __set__visible(visible:Boolean):Void;

   public var height:Number;

   public function move(x:Number, y:Number):Void;

   static function registerElement(name:String, className:Function):Void;

   public function setSize(w:Number, h:Number):Void;

   public var top:Number;

   public var visible:Boolean;

   public var width:Number;

};

ÿþÿ#__Packages.mx.skins.halo.ButtonSkinÿþÿ#__Packages.mx.skins.halo.ButtonSkinÿþÿ
Button.swf#¹U?ÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.ButtonSkinÿþÿÿimport mx.skins.RectBorder;

import mx.core.ext.UIObjectExtensions;

import mx.skins.SkinElement;



intrinsic class mx.skins.halo.ButtonSkin extends mx.skins.RectBorder

{

   public function ButtonSkin();

   static var UIObjectExtensionsDependency;

   public var backgroundColorName;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   public var className;

   public function drawHaloRect(w:Number, h:Number):Void;

   public var drawRoundRect:Function;

   public function init():Void;

   public function size():Void;

   static var symbolName:String;

   static var symbolOwner:Object;

};

ÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ
Button.swf$¹U?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.Defaultsÿþÿÿ·import mx.core.UIObject;

import mx.core.ext.UIObjectExtensions;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.skins.halo.Defaults

{

   static var CSSStyleDeclarationDependency;

   static var UIObjectDependency;

   static var UIObjectExtensionsDependency;

   public var beginFill:Function;

   public var beginGradientFill:Function;

   static function classConstruct():Boolean;

   static var classConstructed;

   public var curveTo:Function;

   public function drawRoundRect(x, y, w, h, r, c, alpha, rot, gradient, ratios);

   public var endFill:Function;

   public var lineTo:Function;

   public var moveTo:Function;

   static function setThemeDefaults():Void;

};

ÿþÿ"__Packages.mx.skins.halo.FocusRectÿþÿ"__Packages.mx.skins.halo.FocusRectÿþÿ
Button.swf$¹U?ÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.FocusRectÿþÿÿÎimport mx.core.UIObject;

import mx.skins.halo.Defaults;

import mx.managers.DepthManager;

import mx.skins.SkinElement;

import mx.core.UIComponent;



intrinsic class mx.skins.halo.FocusRect extends mx.skins.SkinElement

{

   static var DefaultsDependency:mx.skins.halo.Defaults;

   public function FocusRect();

   static var UIComponentDependency:mx.core.UIComponent;

   public var boundingBox_mc:MovieClip;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   public function draw(o:Object):Void;

   public var drawRoundRect:Function;

   public function handleEvent(e:Object):Void;

   public function setSize(w:Number, h:Number, r, a:Number, rectCol:Number):Void;

};

ÿþÿ#__Packages.mx.skins.halo.RectBorderÿþÿ#__Packages.mx.skins.halo.RectBorderÿþÿ
Button.swf$¹U?ÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.RectBorderÿþÿÿoimport mx.core.ext.UIObjectExtensions;

import mx.skins.Border;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.skins.halo.RectBorder extends mx.skins.RectBorder

{

   public function RectBorder();

   static var UIObjectExtensionsDependency;

   public var borderCapColorName:String;

   private var borderWidths:Object;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   private var colorList:Object;

   public function draw3dBorder(c1:Number, c2:Number, c3:Number, c4:Number, c5:Number, c6:Number):Void;

   public function drawBorder(Void):Void;

   public var drawRoundRect:Function;

   public function getBorderMetrics(Void):Object;

   public function init(Void):Void;

   public var shadowCapColorName:String;

   static var symbolName:String;

   static var symbolOwner:Object;

   static var version:String;

};

ÿþÿ __Packages.mx.styles.CSSSetStyleÿþÿ __Packages.mx.styles.CSSSetStyleÿþÿ
Button.swf$¹U?ÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.styles.CSSSetStyleÿþÿÿbimport mx.styles.StyleManager;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.styles.CSSSetStyle

{

   static var CSSStyleDeclarationDependency;

   public var _color:Number;

   public function _setStyle(styleProp:String, newValue):Void;

   public function changeColorStyleInChildren(sheetName:String, colorStyle:String, newValue):Void;

   public function changeTextStyleInChildren(styleProp:String):Void;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   static function enableRunTimeCSS():Void;

   public var invalidateStyle:Function;

   public function notifyStyleChangeInChildren(sheetName:String, styleProp:String, newValue):Void;

   public var setColor:Function;

   public function setStyle(styleProp:String, newValue):Void;

   public var styleName:String;

   public var stylecache:Object;

};

ÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swf$¹U?ÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.styles.CSSStyleDeclarationÿþÿÿ%import mx.styles.StyleManager;

import mx.styles.CSSTextStyles;



intrinsic class mx.styles.CSSStyleDeclaration

{

   static var CSSTextStylesDependency;

   public function __getTextFormat(tf:TextFormat, bAll:Boolean):Boolean;

   public var _tf:TextFormat;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   public var color:Number;

   public var embedFonts:Boolean;

   public var fontFamily:String;

   public var fontSize:Number;

   public var fontStyle:String;

   public var fontWeight:String;

   public function getStyle(styleProp:String);

   public var marginLeft:Number;

   public var marginRight:Number;

   public var styleName:String;

   public var textAlign:String;

   public var textDecoration:String;

   public var textIndent:Number;

};

ÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ
Button.swf$¹U?ÿþÿmx.styles.CSSTextStylesÿþÿt

intrinsic class mx.styles.CSSTextStyles

{

   static function addTextStyles(o:Object, bColor:Boolean):Void;

};

ÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swf$¹U?ÿþÿmx.styles.StyleManagerÿþÿÿµ

intrinsic class mx.styles.StyleManager

{

   static var TextFormatStyleProps:Object;

   static var TextStyleMap:Object;

   static var colorNames:Object;

   static var colorStyles:Object;

   static function getColorName(colorName:String):Number;

   static var inheritingStyles:Object;

   static function isColorName(colorName:String):Boolean;

   static function isColorStyle(styleName:String):Boolean;

   static function isInheritingStyle(styleName:String):Boolean;

   static function registerColorName(colorName:String, colorValue:Number):Void;

   static function registerColorStyle(styleName:String):Void;

   static function registerInheritingStyle(styleName:String):Void;

};

ÿþÿBoundingBoxÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿ
RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿ
ButtonSkinÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.controls.Buttonÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.controls.Buttonÿþÿÿqimport mx.core.UIObject;

import mx.controls.SimpleButton;

import mx.core.UIComponent;



[Event("click")] 

[TagName("Button")] 

[IconFile("Button.png")] 

intrinsic class mx.controls.Button extends mx.controls.SimpleButton

{

   public function Button();

   public var __get__icon:Function;

   public var __get__label:Function;

   public var __get__labelPlacement:Function;

   public var __label:String;

   public var __labelPlacement:String;

   public var _color;

   public function _getIcon(Void):String;

   public var _iconLinkageName:String;

   [Bindable] [ChangeEvent("click")] public var _inherited_selected:Boolean;

   public function _setIcon(linkage):Void;

   public var borderW:Number;

   public var btnOffset:Number;

   public function calcSize(tag:Number, ref:Object):Void;

   public var centerContent:Boolean;

   public var className:String;

   public var clipParameters:Object;

   public function createChildren(Void):Void;

   public function draw();

   public var falseDisabledIcon:String;

   public var falseDisabledSkin:String;

   public var falseDownIcon:String;

   public var falseDownSkin:String;

   public var falseOverIcon:String;

   public var falseOverSkin:String;

   public var falseUpIcon:String;

   public var falseUpSkin:String;

   public function getBtnOffset(Void):Number;

   public function getLabel(Void):String;

   public function getLabelPlacement(Void):String;

   public var hitArea_mc:MovieClip;

   function get icon():String;

   [Inspectable(defaultValue="")] function set icon(linkage);

   public function init(Void):Void;

   public var initIcon;

   public function invalidateStyle(c:String):Void;

   [Inspectable(defaultValue="Button")] function set label(lbl:String);

   function get label():String;

   public var labelPath:Object;

   [Inspectable(enumeration="left,right,top,bottom"defaultValue="right")] function set labelPlacement(val:String);

   function get labelPlacement():String;

   static var mergedClipParameters:Boolean;

   public function onRelease(Void):Void;

   public function setColor(c:Number):Void;

   public function setEnabled(enable:Boolean):Void;

   public function setHitArea(w:Number, h:Number);

   public function setLabel(label:String):Void;

   public function setLabelPlacement(val:String):Void;

   public function setSkin(tag:Number, linkageName:String, initobj:Object):MovieClip;

   public function setView(offset:Number):Void;

   public function size(Void):Void;

   static var symbolName:String;

   static var symbolOwner;

   public var trueDisabledIcon:String;

   public var trueDisabledSkin:String;

   public var trueDownIcon:String;

   public var trueDownSkin:String;

   public var trueOverIcon:String;

   public var trueOverSkin:String;

   public var trueUpIcon:String;

   public var trueUpSkin:String;

   static var version:String;

   public function viewSkin(varName:String):Void;

};

ÌÈ
h�hhhhÿÿÿÿÀÀÀÿ´ÿþÿPropSheet::ActiveTabÿþÿ7641”ÿþÿ!PublishGifProperties::PaletteNameÿþÿÿþÿ PublishRNWKProperties::speed256Kÿþÿ0ÿþÿ"PublishHtmlProperties::StartPausedÿþÿ0ÿþÿ%PublishFormatProperties::htmlFileNameÿþÿstorage_dialog.htmlÿþÿ PublishQTProperties::LayerOptionÿþÿÿþÿ PublishQTProperties::AlphaOptionÿþÿÿþÿ"PublishQTProperties::MatchMovieDimÿþÿ1ÿþÿVector::Debugging Permittedÿþÿ0ÿþÿPublishProfileProperties::nameÿþÿDefaultÿþÿPublishHtmlProperties::Loopÿþÿ1ÿþÿPublishFormatProperties::jpegÿþÿ0ÿþÿPublishQTProperties::Widthÿþÿ215ÿþÿ$PublishPNGProperties::OptimizeColorsÿþÿ1ÿþÿ&PublishRNWKProperties::speedSingleISDNÿþÿ0ÿþÿ&PublishRNWKProperties::singleRateAudioÿþÿ0ÿþÿVector::External Playerÿþÿÿþÿ%PublishHtmlProperties::showTagWarnMsgÿþÿ1ÿþÿPublishHtmlProperties::Unitsÿþÿ0ÿþÿ4PublishHtmlProperties::UsingDefaultAlternateFilenameÿþÿ1ÿþÿPublishGifProperties::Smoothÿþÿ1ÿþÿ%PublishRNWKProperties::mediaCopyrightÿþÿ(c) 2000ÿþÿ#PublishRNWKProperties::flashBitRateÿþÿ1200ÿþÿVector::Compress Movieÿþÿ1ÿþÿVector::Package Pathsÿþÿÿþÿ&PublishFormatProperties::flashFileNameÿþÿ..\..\storage_dialog.swfÿþÿ'PublishFormatProperties::gifDefaultNameÿþÿ1ÿþÿ%PublishFormatProperties::projectorMacÿþÿ0ÿþÿ"PublishGifProperties::DitherOptionÿþÿÿþÿ!PublishRNWKProperties::exportSMILÿþÿ1ÿþÿ PublishRNWKProperties::speed384Kÿþÿ0ÿþÿ"PublishRNWKProperties::exportAudioÿþÿ1ÿþÿVector::FireFoxÿþÿ0ÿþÿPublishHtmlProperties::Qualityÿþÿ4ÿþÿ(PublishHtmlProperties::VerticalAlignmentÿþÿ1ÿþÿ$PublishFormatProperties::pngFileNameÿþÿstorage_dialog.pngÿþÿPublishFormatProperties::htmlÿþÿ0ÿþÿ"PublishPNGProperties::FilterOptionÿþÿÿþÿ'PublishRNWKProperties::mediaDescriptionÿþÿÿþÿVector::Override Soundsÿþÿ0ÿþÿ!PublishHtmlProperties::DeviceFontÿþÿ0ÿþÿ-PublishFormatProperties::generatorDefaultNameÿþÿ1ÿþÿPublishQTProperties::Flattenÿþÿ1ÿþÿPublishPNGProperties::BitDepthÿþÿ24-bit with AlphaÿþÿPublishPNGProperties::Smoothÿþÿ1ÿþÿ"PublishGifProperties::DitherSolidsÿþÿ0ÿþÿPublishGifProperties::Interlaceÿþÿ0ÿþÿPublishJpegProperties::DPIÿþÿ4718592ÿþÿVector::Qualityÿþÿ80ÿþÿVector::Protectÿþÿ0ÿþÿ"PublishHtmlProperties::DisplayMenuÿþÿ1ÿþÿ*PublishHtmlProperties::HorizontalAlignmentÿþÿ1ÿþÿ2PublishHtmlProperties::VersionDetectionIfAvailableÿþÿ0ÿþÿVector::Templateÿþÿ0ÿþÿ*PublishFormatProperties::generatorFileNameÿþÿstorage_dialog.swtÿþÿ(PublishFormatProperties::rnwkDefaultNameÿþÿ1ÿþÿ(PublishFormatProperties::jpegDefaultNameÿþÿ1ÿþÿPublishFormatProperties::gifÿþÿ0ÿþÿPublishGifProperties::Loopÿþÿ1ÿþÿPublishGifProperties::Widthÿþÿ215ÿþÿ$PublishRNWKProperties::mediaKeywordsÿþÿÿþÿ!PublishRNWKProperties::mediaTitleÿþÿÿþÿPublishRNWKProperties::speed28Kÿþÿ1ÿþÿ#PublishFormatProperties::qtFileNameÿþÿstorage_dialog.movÿþÿ"PublishPNGProperties::DitherOptionÿþÿÿþÿ#PublishGifProperties::PaletteOptionÿþÿÿþÿ#PublishGifProperties::MatchMovieDimÿþÿ1ÿþÿ$PublishRNWKProperties::speedDualISDNÿþÿ0ÿþÿ$PublishRNWKProperties::realVideoRateÿþÿ100000ÿþÿPublishJpegProperties::Qualityÿþÿ80ÿþÿPublishFormatProperties::flashÿþÿ1ÿþÿ#PublishPNGProperties::PaletteOptionÿþÿÿþÿ#PublishPNGProperties::MatchMovieDimÿþÿ1ÿþÿ$PublishJpegProperties::MatchMovieDimÿþÿ1ÿþÿVector::Package Export Frameÿþÿ1ÿþÿ!PublishProfileProperties::versionÿþÿ1ÿþÿPublishHtmlProperties::Alignÿþÿ0ÿþÿ-PublishFormatProperties::projectorWinFileNameÿþÿstorage_dialog.exeÿþÿ'PublishFormatProperties::pngDefaultNameÿþÿ1ÿþÿ0PublishFormatProperties::projectorMacDefaultNameÿþÿ1ÿþÿ#PublishQTProperties::PlayEveryFrameÿþÿ0ÿþÿ"PublishPNGProperties::DitherSolidsÿþÿ0ÿþÿ"PublishJpegProperties::Progressiveÿþÿ0ÿþÿVector::Debugging PasswordÿþÿÿþÿVector::Omit Trace Actionsÿþÿ0ÿþÿPublishHtmlProperties::Heightÿþÿ138ÿþÿPublishHtmlProperties::Widthÿþÿ215ÿþÿ%PublishFormatProperties::jpegFileNameÿþÿstorage_dialog.jpgÿþÿ)PublishFormatProperties::flashDefaultNameÿþÿ0ÿþÿPublishPNGProperties::Interlaceÿþÿ0ÿþÿPublishGifProperties::Heightÿþÿ138ÿþÿPublishJpegProperties::Sizeÿþÿ0ÿþÿVector::DeviceSoundÿþÿ0ÿþÿVector::TopDownÿþÿ0ÿþÿ'PublishHtmlProperties::TemplateFileNameÿþÿ�C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Html\Default.htmlÿþÿ!PublishHtmlProperties::WindowModeÿþÿ0ÿþÿ2PublishHtmlProperties::UsingDefaultContentFilenameÿþÿ1ÿþÿ-PublishFormatProperties::projectorMacFileNameÿþÿstorage_dialog.hqxÿþÿ(PublishFormatProperties::htmlDefaultNameÿþÿ1ÿþÿPublishFormatProperties::rnwkÿþÿ0ÿþÿPublishFormatProperties::pngÿþÿ0ÿþÿPublishQTProperties::Heightÿþÿ138ÿþÿ%PublishPNGProperties::RemoveGradientsÿþÿ0ÿþÿPublishGifProperties::MaxColorsÿþÿ255ÿþÿ'PublishGifProperties::TransparentOptionÿþÿÿþÿPublishGifProperties::LoopCountÿþÿÿþÿPublishRNWKProperties::speed56Kÿþÿ1ÿþÿVector::Reportÿþÿ0ÿþÿ+PublishHtmlProperties::OwnAlternateFilenameÿþÿÿþÿ(PublishHtmlProperties::AlternateFilenameÿþÿÿþÿ&PublishHtmlProperties::ContentFilenameÿþÿÿþÿ"PublishFormatProperties::generatorÿþÿ0ÿþÿ$PublishGifProperties::OptimizeColorsÿþÿ1ÿþÿ"PublishRNWKProperties::audioFormatÿþÿ0ÿþÿVector::Versionÿþÿ7ÿþÿVector::Event Formatÿþÿ0ÿþÿVector::Stream Compressÿþÿ7ÿþÿPublishFormatProperties::qtÿþÿ0ÿþÿPublishPNGProperties::Heightÿþÿ138ÿþÿPublishPNGProperties::Widthÿþÿ215ÿþÿ%PublishGifProperties::ªZ|o4’ºÜçaIÀm>€�d´bÎ)#Áäì2®ïOª$M,çðŒ…R0´÷½QH)\µˆÒ™¦4¶ýÉã>~¨¼žˆ´µýMašÎMñXtV×ÙoKÀ~[’<÷ß@“­‘ôß‹ß”¿hˆV`O§¼,NÝFünaý½�ÐsP©|M:H“
5K�ÐbxN®‰]O“{š†ó1Ùd
ÃÈ'kJl“Ï“E’Y--:Ô¥µ·§C2)µ!•þH°ÃóÞR0½Q0^þ;’4ÔZ�Vn{áñÎCÏãqo–&™€Áœ!9ú=9b“t#†™BŒ§ýn-dûzü®tb±Ë?Õ ×œ‡T¤þŒ!S¢àô‡ÄîR§Ã9on¶#ú¾é0ì@ž6£,Ö‡BÚ¬þ_µÉfaè!‰¶za&pQ1ÿ2fà/k!jA³¼K˜%žÈÐ ‡ã‡S~ëHü(–ø1äÈJ3âÇü³˜8Ê�
*c<nœ|^`áïñÅ8Àûy8dÚ'&Z·ôwJÈ»¢eðÝ!_Š¦t‘LOOwßöÌ•Ÿ®]åþÑ“#ïºxIÞ¶«ÛÁeê^„ „+Ís˜Q+Í_zO¨°«
®Dà‰'ž€®ÞW‡Þzùèé¾};�>�a;ùbçaüZZPÍ›¹ÒÜ/èf§CIÐÁ¼vÂ±J®2™ÏÍIF—KFðý £>ôæËãoD÷�•Œv…�â«Ñ_£ËÃŒv1£ãt˜¯µÞ† n^�uâ×Vãº\E–¶‚`:ŽxûUXcõLÓ0AM\huÃ¤](;–¸Ü-Í¥ø=R|úÅ�¼5yì�µûz¥ø+Ââ—*9«ò¿G‰ßÎ¯`ñ�9�Ï
é
/tõ=sÖ}þÍw?Ñù…]ï~�_:n÷1¿âw%@ÞžÉ;tGõþ³ü4±Ü_;þÒC×ç}Ìö	Û¡›±&6×tu§´2¸º+à¯kµ?‘«Û-V·Þ¾)\]ÛE0¹ÞÖ(Ò~ûjíëžQ¦ÐB¦ðkµ_©ý÷À±KSXÁS¯™ÂD±‰Ê›pÙT–È�–&Á.WJó-M) Ûï5ò(9Jl–ïUüa±=m´�6®�kØQr·‰KŽ ™Ü‰�Ü÷–‘/
Å«°+èw«`Ôš61«J„ÕB‚VÃ½âRclÞµŠU»T$ÔØ¹44?2®òéØJ"×óÎ.4Zlè8´·ÿ•+áùÖxäÐÒ7"h-dþsô{ï�ëB/ÝŽwïý§‘/¾T}öG•¿;‚h›±£¿­¶·Ö}[¾xÉÑƒp5~ˆöNŠúZB4Úûù
ÙŒ†ímÊ7Pw®9uÂ,æ«B†Þ<Æ×ZºŽ—´O,i;Å#SÈJ);yø:/eg«i³‰äµÖq­¨O®t„¸GŽFÌ²;[¡¥Ã0kv¬úÊÇº"èŠ¨Ù5Ðõ\E)¶›É¯Sž6‹æÊ"sƒ·˜kiò0R*”KEôõÐzÞŽý×s
ôüVR¬g§èýÙ¥kÜhER+wß“�„öË�AòH”òûM!)×(íýÁñß~æ±F’¸OÓÄÝÐýÐOå¼+!qæ£ïr£íº÷[µ+ÜHà„+ÿcä¥°"6…¿¹ú×!h0$íÓBÚ®ÊsŠÚ26ˆ†@Û@#@PÙÜHeçÛ‘PœÜd
Þ@Zš-FÙ"_")#Ê÷IQÍU÷:&½—šªîjì)àôpò°‰]Eÿ‚·Shw�+QL2ÛÐØJ33ã£œr‚U4§êŒpS=KP³`å#H Q]ÁpñTâƒù—h5j£÷µ�oàõZ‹zè}í«¢1€‹FPÝ[¥Po=ì�LßÆ¯/S¿,ù2}™dB]ÚôxK¼ &sÊBY%•�¥„�q0@òaàƒÖ‰éíÛÀ.«µæMŒt¸ófÖÃM�Éœ1³Ð—«;ó;yÓÞÙd¿®u&tüÔ‹è2êÑ·ziêb³o2®\)¹%w¡ly›½À¢fúø1ÈUÌ9Èd4c¹"(Ç�çÊxÅ,Ð+ÙEÓ±éd&:ÃICÁž§™�NNZî™J©<î˜3UÎö�“÷ˆ8×¯R <iDü,^;’JqÅù€G¬¡qúÏ'N<ú_ø´	8Œç£b0¬øÞÏÉÀÍhlq¿°�ž¥‹Ž§0];7ñ}¥¸‚�·ñž tu@ŒÓ�…©´.vr½ÁÀ}%;;äq¨Í¿òŠÄ—¥�žª¢üx¥§$‘Ž:" nWÚi‚dJrß¹˜ ÷Ð·C¤ZÖ_“ý9ñ<É°6àç«x›¡¥ÄW,¬þ]žg0‰Òq]”…Òz]ä3ðJÓ(s
½…Xî/jˆÒ$](1ºÖdŠ(Ÿùö¥‚Â³†¤gm`Ïªó¬,zÆNkè|y�F<õû-¿ÛÄ�ÙßGÐƒ«ne6ëÊ¶ïSþ+m&ƒÞ“ÉˆrõGÀäã¹÷W@kÚåw`Ñô>ÜR™Þ†eËûÁ,S6+äÕ!úS%Œ�õF� Ó^ÄÊøÁ«‚‹‘… 2"Àe¼PW
B=ª]
µ±uŸzîV!••–·sT¬‹ª<gWË¦›Í�]$±$Iï•\Pô›ÜË¯Û êøC!)hçê±çäJ§0˜U `¹ùRî,Å~›´íLEéA(Ê!£’[ìGEŠx(RYéPÍÛ¸¸Yª&pŽ:Î¨]
jˆªî4=É‹pLÅxZÈ=@?ç¼Ïº”%ñ}E<Ô#¦P;~È%$Zœ™†‹DÃ)Þ?Å÷YkÞ·-'§6—žåé‹yB›Ä6T‰Ï$iCŒRÅ®kfóì²cÄ1«Uµ/-¦J�Ÿ©9ª:¨X3T€PaÔ`e…–³ÐáJª…K:j•Q¶©YÛÉñ§XµÙ2LÛÅ\Ù;zÑ´
ÌêœYæ¯*ÎEòûžJ»n�£Ì•�£?UV2ed´‘¦™»Ê‚ÜUƒÛ©b\µë<R
ŸGÑGQ•ávV~Œ0U]›«­ˆÍf­*ZºíØîÂe¶4ƒébâ«˜› Te4ÉÒ�¯”
$Õ“ì”�,næÍ*êœ¶f«â.ˆ*)!6Êž5Ñ3(ÇdS¬Š•ÎâªZ¤,^#îµ²fŽ²œ)b´lŽU3™™ŒŸ„°£²á•*ÓEû­Î5~ƒ‰[¤ƒXÓ˜NñÏ¸Y°�þd÷¦Kaõ´Y™Á)ðŸSg9z†ÀivÛE}f
vC´Ð7ï>$jjÈþ�ò•"áü˜ŸT*U!×b 
_’²[…)+7^¢ÌO–;±6 NðÀ§ÊC1(òÇH8+S¬uÕÁã3»:QÄ¸d»jLÓ¬ÊŒUg(ñ‡Ý³sþoï�!D¡/1=žRÇ$_*û»„ìæ¼™óT®XÓV£ìðÚ¢[îZf.çÙ¦ã-Èp.#6í‰ó°ðÿ.Ë,­mÈ2Å=¸Nç!<x^øô†gÈh:!rÑzÌGÌçƒ3ÎˆÌ
ãò¦}Zeš×š–}m
}Ë¼¾ö†¾¯¯ó}Ëúº¼¾îôõx}Ûeß
–®7©f¨SG<}|™Üw�Á+“jšºÁm�Á‰ºìYñ¶ÊãmµHõõ!Ðò^j¼
ScÙ¿Æ›¾ê&J¤‘µA"ƒJvW7,öšô°:"ô_‡¿�¿u>é9�¿Ÿ¿õ×ç¯ßãoC�Hëø[ïó·q±—ÎQ8F±$r³G@Uªl’/ÊwKÆ6Ñ™GQùJ·‡«A
M<¨x‚ë]èk½ #�ãÀVïø´­Á¢6yZ¹Éh¶�àQIlli›/ÒPÙíÙ›ƒd¤LÛI¦ºªŸÜŽr·xävúä<r·4’Ûá“»u±›Ž'O�2PSÐs’î.ÿ×tbB�vá§»=T0€‡Q­N­»Øgö¥eUÈmü–¯lh¿°BCYáoÊo»Cž‡$E½KßUÄ.ùˆÝŒ)®k¹=|Z�‘%T¢@KKÔ½ßÁO¬BXÂÜu{ä“ëÞdšj{®Ö¤wÖyÓ@@Ž&¬ÉQwÕ�JÈ…:àU2„µu¨¿A-wy&|�V3BîcLuæÌ…*|	”JOq¥�x0'1ŸðæÅ}ÀS
#'CoÀ·xoÀZ½¡'¹î‰Wû0kçOku(¦:²Áøá8ßáçÛˆsTmÈºeÐ!>-ó[€¨
�y[…WßD�Ù«6À£E^t1&U!ãQ7±s$~ÿº±~]¶F|æ –÷9¨HF“µ�%½âDìñ8#Â:–ÜÀÓñø	´³	t¨ëó4^gkä
M+³#Mh³£Lèäâ*z¢ˆ
�>¿ƒÃnˆÎïca<(Ê¦¤#êÝËU�Sb4�èu-‘“Ÿ^\K:¤ÉùÜÍñ1Éà“Ý÷`iw“’¥Æ#Š´c‚vRÆ¯òŒë–RM.kÎˆË"-¾‰Œœ¿î1Œ”²ò†7ÊÀ<4ƒXRuaáPCØ¿KÕP¥
®P04š'‡ä
˜ßÒÍ§Ò®ŸÔ‡N'#ŠÁ+Ép¾(ªÓàZÖÛ[ï]ÜF”Ð$5ÿ E:-‚NLÑù’,m½Oˆé×wÈkEÞRµøý¬¨ûüjQñŠÒF9ˆ±ZA±4™ö
p˜äMr¾û“Þßë¦¤ä9·¸Bí@(„.„Øªh¨nM[ÅÕéÁÓÈƒ‹íä-C({žžiÄ’�ñJ‹?ª¹ájúT}<}X
¶â�†_F''~4í—÷ø•ôê:6ÓP^÷˜²ÖØÊ%ÌÅµQ»æŒ(8Fð”¦J°ìâ ðœˆAhzÐr¢´Ì)\æ¢T{Žë¾Mï?»·XÓ¤?é¢õø;“æm‹êª
vÌ´�Î[sÅ[^ˆ@WÖÄÛ­Ð
SÊ§ET1áœÒ„/¢Ý,îŸ¯‹pýõ+d§e�½€{¦­ô9©TÇ×H”S€á:b…7>ß)6@J*)s®ÒGòG#Jþƒ¼Þ`§~\pUÜ¾!Jp…á…7ãJx3>ÜŒƒ‰u5Ý£êµ¢AˆuäÚq¥ö”ü¸ƒØ{©æåIh:×�à\1¹Ë)ä9�â?Uƒ}S%H!¥>$Wø—åV5jðc‚hŒÑv%9‹Ïú«•¨×ÞãÍ•:«ê�/&YôP@Ÿt9É¼R¾dëSâÿ)#tÆÿÛÞ›@Çu]‚¿ª~UýÂ¾‘ @�àN‚ûN‘wˆ $ª@�”dI¶ÀP  ‚(ˆ¤¼È²%“^ÂX^˜flyë8Þí8Nœ3Ó9™¤“žvÔîé%�ÌØŸô™Lwr<Óé>>í8‹#Ì»Ë[ÿÿ…‚D¹™±uTàÛ—ûÞï¾»^Ï±À zÖýÎzø|›•¡t
Œºöƒ·çUO¾ìILì%	µw|Ñx"*©�â�7[àœ¬…Ã`ÌË
ünÒÛœ¦¼+øý>—'ÙM1è€Gð1O+©Ã‡¼ÿ>o/ø�Zpº+²gP¾<¶2Í‹‘fQ
b��` ’ac|dþ–4O³€f5£úoÉ×:ªo$C£úd’`ön.F‡¹€YZ¯Ë6¦aÌSIzR¼‡„ð¥ðÿÆB·¨™B:Ôº‡k�rj½SëE¬•äZïuj½7¦Ö{Iø2Aµ®;µnÄÔº�µnq­÷9µÞSëýXë×ú€SëƒF­eF­”û¡î:®ûNÝ›1uouÿÒ£º¿èÔýPÌh?„£ýu®õ’SëÃ1µ>ŒµÞÎµ>âÔúhÌ8?jŒó×ý˜S÷c1=~{¬Q‡vN‚ä?@ƒ(û>>uaŸæpŸæ¸™)üVs(êz‹’VÐ©—Nˆ±•\ðÎAÙêë4ÊZçV3
‰Æ¹	5¦ûÜø*¨ÁÁÕhøØMÖ„š‘ãy&Ïbº’Ø¦ÆÕÅ„_"­‘ãYþ/…
J„ãŸ8´‰&G¨ÖŽÓêqÉ#–ðíc¿½*üæ�'¸‚Ò÷Ï1q*ü2ÞL$â½0…àãòÖþÄ z3&ƒ÷‚B›ùlxY^ <ÚçÍí`�s'�ÓÜí.!ãåÁ#·�…¾Â]Y8Ucì‰Gö	@ÛÅu#®£²ä’xK“úº	 ÃOÂ/–ÑßèŠ©W"íˆ1¥N)ÃeÎá@3æ”:Ïdô4#¡'F·ÑÚÝˆügÛ�²YiãN'H„0BÜÏY,™å’õØ|V7¾c7ÿJmP×WÔ§Ïà•Ù^±Ô§¡û„Ú ¡›ŠèMé¸¦5\Íõí6¡'WWÃ°•aˆ_�9UÙ!áy¬xI“f@¼WK±ÔÈg`7'Qñ¹‚#û	ïŠÑÞà=Ç$£‚èCâ¾äÅÓ2ð9ô˜óLääÏÿtàV;„Îï%(ÓwGäÊƒþ26Á¯`&ê:%‚ÏÊOXîW¡Ü!Ä’ƒÏSk_ ¾Hÿ|‰þù2ýóúç«Ôa;”r@´2Kòp|M¾+¿>hg×`öÒ¸ì:Ìþ5�MÉË™MÑ‰Ù_p³Wqv7f1®ñÌþ†[{‹ÖPÙ¿îfoçì­˜ýÍ¸Æ1û7ÜÚ›¸öFÌþ|\í³Ûâ²0û7ã²›1û[FßD}2ZÔç·”¨ÏflíhH'D,JˆÎ–žûrjÝøšøBâ¤ç¢Åæ´à€Ëû·…,ÁWrEqNA²ƒŒ?(©ê`™Ž»�ÅYÒ1ó£Ók¶Yœ‰TE†fZ÷šÑM/ÈÞì )‘DÒdJSÔÎH)<ÉHòSôøw�“¬ ¦p
È%LÓ(jˆ>t¹,’ÅV«Ylu|Lµ89mž¤i§ø(jÐ…uá+À
”…›Táf,\�D[‹Úæ[x›oÄm¾ÅÝæ(\±ýä¹s CÀ²ó
ŸÎBÅ=‰UQ;�JÙuôf/ŒŽé naˆ'¸²&ëå&¦JSESx‚Ï®ÀFX„"$…±8!”Rb ÕÈcÜmÙI‡vteiUñ	iŠmÉK
“¬ÆÛÒ&/ó·Ù0‰=«H;i«æÄFUÜÍFÝJtþÔHü¾v°ÝìîÐ¢»ËxA�h§®_÷x¿Õc�n*‡ˆïm$š[%�¹^ñ˜ëpœ
Æ8oIúxÉ{ÝjŒ‡P#A¨1B¯©»¦øîš¨»æ;Ù]K|w-Ô]ë�\ÿ6ÑN[ìú·-¸þmQëß†ã\r'Á²4,K	,íw²»eñÝ-£î:îdw�ñÝuRwËïä¢w�i”ØEïZpÑ»¢½Ç¹âN‚ee<XVXVÝU{½w«ë}+_ïÛðzß{½‡Ä*ç¾�‚ê7þR C•.ùPM}Õ»˜CUI`šÂˆxç�@0`l'¥”¼ƒ]Ø8…]´8jî-N'¹ûdýM.òŽ�äd{<àd�[ð_�)ÝnoIèä÷ù§·€ï`ë¡þA“7$—QÞ®Œ4'$Ž<Ä¬‚¤þ ™;\d„ˆ,’(Ï&M0MáblÞI»…›ÖÝ*¥b4©ê!EºÎ–Ž¤Q ðàk-Ê‘õ H3-�× ŽÖI›éDìÇ˜tû©Ç¿
ˆ- �£¢‚
¡ƒLåhrZªö0hV‡Á6>6àa°-ú0°>Ðù†Ïd¡Þ�RÆŸVýùËÇkHjØŽ—#‹Õ»W‹kå£²-wl•¥³B†TI)Ïì”ñF'fÄ<àÔŠ÷Ö¯ãÅ¡'Æób¸ÀÊý³3¢4uþMó [ºXPy,MN<£R,áì±‰ÉI
9Zùå‘Qí¼îQª ö‚R¥ö!@Ýá’LGE‰¢æÅPþŒNíµÆáæž�)–Ëv¦¶+HgK£…kn`ƒ²4c�³0m�NFÇ@™s&EÿÞ•ñ‰YXøQïâL±8%RçŠâ½v”¼kÅÉÉÒoäZaÊ/L–ú°„N@1Ì¦.£¯|Kâ{Ïx"šïB~Jâs´`Jìëg¡ñTÏC…iyW2ìêÑi>4�åÝvC}$õÚ^‘dTS«÷¬Š¢¯ˆ¿Y¢
JJŠ8˜£j¯�¯
tf�gun1¨qP»˜ÔD îf7+Q&ÕÉä%0øh¶dÜ`ê‰®ä'´:¦Œn)n0õr0xùÊÁ4F5Ñ½@¢rÒÑ‚&qÛ5‹_‹øµŠ_›ø-¿¥â×žNd•=9pkJ×ËDj‡øuŠßrñƒÚ]â·BüVŠ_·ø­¿Õâ·FüÖŠß:ñ[/~Äo£øm¿ñÛ,~[Äo«øm¿í¢·eÔÛÐ[}°Coä�`{ÑveÁD°;f’ƒ=ÙyÈÛ+þ‰ûD¢øg¿()dšØlúÑ�¶xÁÁ¬÷Ïç½l-5¿š?Ü+:½�'q8íGÄï¨¿ãâwBüNŠ´Þ´ªyjÞ�ÀYÂ5[P¸Sâ×'~§˜ýâ×+¦UGµ«»ÞP×ûv¾Þ×âõ¾=Z9Õ°©ÐÐ\•ndR§âõSuy}±+­U[#5Z%Uij]MVB:9§ð(äHõC{ÑÐ˜­hmRÀG�sxÙ¡˜Ì“…$*2fF¤^kiêAq¡R…KÅkhÐ‡ô÷PâWY-y�L“6)¶307ë¨’‚ò#µSš:'Ç ž"v;X¹_ÜQ½ª8(ž¢d¥»‡Å´–¤¡¥Jƒ"ìzÈšÓpSÃ3&…r‘"å³4c¼ÌPP)´J¥UìP oŽ«¡6§Ô»“U³ÆÃŠ� ðŒ‘B‘8mÌ°"Ø¥s³3EhÇ '[7-Ù¶`TÏ@­CÔ7=‘è¤ñ4iÉ´Sï¶Ûõùlè~ýŒ33sÎÐòÊ†4L%®™åÕ¨¼ZÒÝñ;‘m!å[\óZ%Ywsˆ·‚pH
¼‰®½äTñ
…ØªCõ!)ÌÉj!Åÿ¦Cí·Lñ‰zâ·€L¨Üº!ñÁ5žfBYB‰ ECª•
·Þÿ´tÁxL¬J�Gñ.°ŒÏbÙm›‚R›i½�ÚiSý±¦™˜ÿ%€hËtì`–úÒƒ?‰´?´ÓVŒâ÷çM	�e@ ÙPúöQÖYäuÈÕè$Á}q
›)`º8XR×X‰Ö®Ó*Þ­¦²J÷%–‘Od·¯Õ¡¾VË¾ÖDöe/Ô´…»VŠÒ(Ã|ZêV�gà›)�¼&®‹Ÿˆ4“Ø`�’DGâˆ	Í�š¤Wò¾Âk *A­—¤)é°À±Lã7ûiñÜ|È3ËnÊ³Ð†LÓàY7(«tFeoTV#õÇÀŠh~�÷Ó~<N¹à–†'}á¦)özÆú'Þ‹\£”±F›Õö?1ž$Ê¢'í)ù9[¬IR[ÌU:ä™ßÒ�‘æ�ds¾ÃªRÛN¾b8¾�aØ‘x›;ˆm¸—A
"K¢ìÙÁ”tÞ)æ¿‹a#Ï@”GØ-?ˆ=ò<ÛmHŒ5yÖWW¯f»÷f#Ë²%é’íÆ£«+Øìg–´óI1Éè€’œ¹'Zræ`p'à÷fo´*˜û@E
C Ô¡ÃÁÄ¦éfá™£ÚŽ.·xÌ¾p$¶*þÍG?2TnÁŒ8>èˆÔäœ'¤xÇIGú#‹Ù½:»J\ú~…KïÀÖŽ6€)¥„ˆ¹¸ôÔìLi²¼Ý26ßpß¨ycsö[‘5U²mŠi¬:„p#ÊØ]qÖµn¦Å>lÑ�Å�º“s3e@˜lóÒÅLqŒ
R\š˜BL
�–ý	­L°… .•dÚ ­²z8’Ù››ÀáNìýY°C04TžE,ˆù"ðhÍAaaicGL�—3lØŠÓø0ë"·ÀÅ±&þ/"Ô™>*^ž/¶;êÝ¯ƒ³…‹@{±½�®šÀäB�^�Vv¬ƒÈÄ:Œ›J
“#Ñ&S }²ó1^ºbŒƒÇ7;1âé�†¸'º”6Äàmð 6XŒ¹2EÏ*1¡áÙ©�±1Ø*$ûÎhÔŠÎŠÕ›�)«Dœ÷¬X39onË@kTx´¬z¢œÙ²(„u U�P…(gvÂ]Œ‰Ç …1†BcjXÏ;€š¢‘[Y”:O6ÓÀB.Ie²\Ä±‹VŒ$¡èý!ú’–Ø¤­Ì¸he�±§ Š/ÒÒÒ9ÍW~­ÃÚ¬ý*,ÌÍ–‹ÓâËÓïÑ»Ø>ï-N®™Ð°eJ…oC–FG?ýv]åZÜÃš³>>"cÏÐëv�Þ€ö[P~¬ð†¹DÝ/Â‹vnZÎ„8eU["½•DÓ©ep-ç�¡²à#c¦	 ‡
È1´9»›ßb¶åª¢ùÙ”�”Ë .�Á�…#ùžÇDô€7ŸûU¿Mµx~ð{Fû§àËÂP´‰ÿbGêHä4ù�Â‡Ôñ–“¥ÈRÜi¶…UÕE(³Êî‹¾YìOUE³;:Ç©K:´eFÌü¤©QT%ÍF1ÁXó‘­>'þNé;¼ÛÝ7:ß°G7[7Ýúw° ÿÓ.zi
ÊçÅ½ZR(ÒÊ§B
Ë7IâzÕ�¥/1ºQÉ”$4t
Ž%ì¡ÇÏ³¢šAáÜ¼¡wï£„­ÌÀçwÔ¢”!”-×ø½45¸Dü–J…Àö…J/ƒ'¦´	ØI^dÀ,7[Ž†f*¾ÙµsGÇÄÅWÜì”òr!5ÞåH YØ[¦Ç’•JÕ¶›ê§YÕÖR ¿Ä=®ò}1 iE!O[pMŸ±:IŸð~^@tö…ýÊ¥²_skM»‰]Æã:~<oòÂCX_a²PÕ�o ’N¶'‘y¦@\Š]¸Q34UÖà´ôP�„\ÝüŸÄ¹7d è‘½‹7v*èé‹XÝ‹ZJ\WV'xŠ{Áxûc)zóâ\Óyc�WXÂgˆ8¡<Ü°šG›lÕŠèNM8ªdÐUŸlÆÍQòÈÛIà×,ç'ÔnVêŠ£šüÛ=0ŸPns“Ù&™+ˆ›X€ÃX»ƒêlX�§jÐJ-oOø»“´ž”÷¤Ï�Ç³³R1¥ìÚÙ¥öÃJÒ‘:<Ô‘Ï†täÁÂ 'µXˆ|�Ã5tœTBixºfµÙJE7æ]ë´ˆxŒ5Ž½ø¸7ºÔæoðû£"r+mþå¸—³ôÍè=¦©9Æ^þ${¢7½³—“îå$íå¤RË_`/WDÙ’±ß-»
+�Ó ¥n…g×¶„rÔ®= ‰<E°r@8CêI‡{è
Kûò q£mæõ:„Dî|wd%Î¼GŒDÌw½§ú2NþÝÐ”.©.×]Îåú%—½V“ÛÁ½õg=êÞ'¿¦
HƒÕñýx�IS¿‡Ío¿D¬Ô
Fª˜Ö‘~#ï¨ÌÛ†Ä½89…£7›¤Å‡½(?«,P…(žð‰ˆh³u¬Ü|‹ª3íæPoÇá«É«”$HX×Â™_^=®rß€Yá|YV…úpeø¬Qî"@|+�`ÌÄc:·ý[$ 5ÑL´à~yížZ¨> }V}H9-O‰~ß0àó€ø=(#gÄï!ÉS+¿³2ò°j”Ðþÿ¶^Óbã5Î”Î-ˆé´Ø˜Ž3¥óæ”–šSzÄœÒ£æ”:Ì)=fNéMò{Z®Õ^w×s¯²·<¯,g›Ì£®±ú	u‰<¹�‰-}ß¼Ù)úCº3Ï§‰ÂCÍÓë-é„u¿…|¬™]<©ºXc¤o¹bµ=¥íÇÀÛ;÷:¤ÎÌ¡xòñãªŸ1ý©~
v?Ž%¿§BÖ†å†ãí^Ôn*µ?j¿¨Û/Æ·?¦Ú¿¸ÈöÇuûãÕ´?j·PP=8to�ãA½T¿LrK2â¯êEŸ`‹;^
:“bå÷mîyeŒh¢ÂžÚ¹‘žu§yIÙ9q7ë.bÜM—CŒ»)y‡”
kYÔ}:x«,16…‚²À�¸>{X~ÔegH¼*;‘°˜ÖþÎæ·ËŽŸ±;¾îøŠÓñ–Š›†®–ð¼æ´ñ-žÏjx¾m@�×Ô½�š¥r×ñÂ ã.Ñbï«(ƒ9jñÞ5=i„Æ™ÎOþ�±›á¹
í½Ë9lÒ‹¸aÞi|p-1>qó*ìFîåùp/±‹ðÎÅ/×xwØ>•^Ø¸¡½'¶R@¹ÒN%©	Ò�P{Q�
ï¥³žäp6ü©*f<ŽØ"üR‡'\—_R^L¸ÍþŸUâ‹ð‚´‡H¸Á–Òô™ãï3Ù¥i÷~ô_	Ü8‰ÄQ^½Èû€™‡×þ6FÂgåQ›†ÎÊM
¿ ­“<	‚õ&˜ˆýÎ•/Yh_²/x6yB>eVËR42
“oòï›ï-^t™pskúœ÷ï¥y9!cæäJYð£5¿Jù ¾Ö>d¾�¤åª—þ«<�Û…¾B®þá×Rýšªþé0DRNº”Î�Ø}4Tü\�ÉüQÅ×þX4_ûVðKŒKþ(Š,úÛhÜŽ#ÇØáSê5º\…6©¼î€8à¿l˜Š@¦ùÇ¹Œ|ß#y¿;Ž|R÷ìŸÂ€#ŸFÍ0Ž|­Gp¯hÓC¿|ŽC­@@!*÷ó*÷*÷¤
}Qå~I¥}Y…ÚUè+*ôUúš
�R¡¯«®†:‚/qhiðY=|™C�¿Â¡sA+‡ÎízSð=ü*‡ú‚¯r¨7ø<‡Î_ãÐƒÁ¤¹Õ@Zö8œâÐCÁ94|�CKbeÎÉÇ²Ø"çe‘þØ"Ke‘b‹<"‹œ‰-ò¨,’�-¢¨ßQP©Èc²ÈÃ±EÞ¤iè	ëç–€Öiã>±çÅÚu8Þ/ Ý+VåœXÁ¥Hÿ;1p«O´à3Á§ƒOŸ^>|<øe<ïDn3ä6‹9. èÇ=/RŸ‡ÔÍÁg5.õ+,&GÒ¿JHÚç±|ðü:‚“ø]_Ä/"ø’®ËFWÚ©îW¨îW©î×¨î)ªûuò“#?)o>“?h›Tù&¹ÈÙã¶Õ™]àìaÛê‰Ìáì¢mõäÕÊžü¦’=Ù‰S=Ú°ÆƒCtgœì‰’:™]un4§ßQIê$$ob‰¡ ¬	²ã!„\½!)¯¡yÊŽ@‰äPJV™‰È(Œ^Ð’ÃZÜ7ÄÐ%krõCRÀZŠ‡k°êãE2¤!:PÒ"pzbö¸˜“ÁRfv³ãè-”`H2HgKvÉ×)åPŠ(sB‰mhK®CI§{�ÜZ@ˆµˆv�ÅÊî.(^±›âjË¡Ë8–¹\¸Š0ÌÙk^¾9C�Åd´¨º”�19þÊÈ(	h†¶ÌêŒAÁçÐûž%GdÊäòB<N,?NkbQa/?(Ká
/NL�š˜œÔ‹ŠS£˜`¨%Äˆha€° ;32Õû$œFÉê*âz›¬~Ã9£Íæ·Å°Çå×²>‹dù+y Å	h1"WÀÓw?¬CJ@€ )Ðo»I‹ï7Eî6á‚ï6¾aÂ‘ýôŠìŒ#of†('2÷/(�Yª/õ›¤F•TOæÚ…†`ª,P´N­'æ_º“8ë'ZÙS'c)P——o½¢à50;¹ÃSìä·¿ÆAeó¡IÙ|hV¼W0ãÙ¢ÍB´\Ž¶|Ÿä!¥]yÊ/æ±“†Û�ß,›&µ—áº¶ÚæÆÛU]íXÆñvÙ¹¡gî´­)Å!|4‡Rìf9q9õ‹ôw¥qâ.æ‰!Ò
Î–q€hÄ%5`�P³îW�M%!.`Ñ—öØh�\¼î0[	ç�•sXoÂt‚ŠÊf$§1¬R=¯fƒÏRºæß„—ØØ¾kõŒV™¼©]Q¬rÛ§Oà–41¬Å�B°®ŸEÒãÇ�æ2EÑUÌpVÌð—æ�sµšçz›½ƒßÌÂÒCD‚MšH°)DYÙ�×ZÑL]b³=ˆ®ŠƒPrû6µq,¼@ZaÊ}y@}i«mýÑ¥š#>S5b;mê–¯™Y›S>h®ÄÂÄæ›\0öù«ÎÝ"Y7!ã&äÜ„ÀMH»	’ë¿Ìô‚²C3VSä'§‘#» ÒÐ®6þ»;_«×Ñˆ¯µó�ìZ:ð‚=ðD4t+¤Ê^6»Š‘}lÐUDê‚ýøi³`K]pê#	ÓÄÇy:ï‚½~#Ñ¡h�Ÿ­U
÷àw œ£C&Øç7páœç×†Šfý(+�5„I
4kZãçj±„æ"÷Qa4f{¯(’­P¦”uñP‹M	ä0¥Þi"×‡d£dpŸµ˜fý­•¿Ï¯õ3z4X¦ÖtŠ±
jqPU?\ÆÀlâV“ÞC&¸öÁÌÖ.°$Ê5U,3¹r´$;c@5&øyùŽàò�ôÔôÁÞL­=wuß„ƒÂ÷œ^/YÕìfó2ºqk˜
ejä'%› ¿óS¸¼õDÃNaaŽÀ¼’Ì©SI¼@”¤d,ÔÙ99bXÚÇõ¡}L)¥mþ6‹«�èW÷½Y•ð‰“¡&{™å¢.uy?ÊüƒoÃ‚.“¨ÔýLîÇ)í¿�1_â·ËLE[×§HTs�…=ô…9
½ê’8Ã¡™ô©èxÈp–[¢?æ{@•xPµ!Ñ›3ySo0'õ0< 6KÌˆñPï­ºk¬‘(
^Ž92ktÛ*r€ñ�\š6QÈL¢W¤&‰x…ý¨Ä´“HäÊJk0 -˜ÊI:›´&´£Ô›t-Y+SLW¼Ô¸÷iÐY½Í–xbl¨5œ•8×Ã#;éÔgPd7xZM$�IÝˆõ«‚`>•9rÕóˆ¥àšUœ…ÇgáMQœ…Dð¸*ðDð$kÁi‘M.ôæà-z*’štÁ]
V¡U¡¢
�©ÐEW¡‰à‡žV¡K*4©B—UhJ…J*4
¡­zk0CTÖ2ý3ËRú‡¸ì¸¥¤Îß•X�¿·VÔù{««ów“¯áßgy`‡	A¦Ínf·ÐeÔåA¤·–å9õ6&Çåìã˜ýŒ›½>¯8o"{ÆÈ®ŽZûvE­Ý…´\Ã'DÌ¦ÖA+§¼•s×Þó
�¨z£.ÑA´¥Zž[Ë°¬e±BzŸžœ)j2˜yp[
Y©ˆjÏ±vÁ±‡çŠs@°{ë)B•˜2£(¨ã…©ÑÉ"+CMOO^óf3®}3fØºCªA‡èÿÃé5/ø¡ýº°}£ntÞµÙK½AC«ç¥Çyº7<Õz–�þ,¿É_ÂÅùò‰M²^™òéOúé~FÉ›ä‹–ŽÑRp¤tfâ,¶&.�¯Î+ƒHMJižïÏâíÉãzgTÝšhº”Ž¿ÞÚ83Iè
‹ÔÅ©“Eêc‹ÔË"
±E”hkÃÍ.”ÈÞìep­@;‰Ë¡¿älïMHÏ¡NÆ—K%VQÊ_ý¶4¢H&}Ëbâ§”ÅDz,ø¾Ü0°½ê—
šÍ×R*hAHs<¤ÐgP¯¯^ Šü4ÙWr+&.÷ˆ|‰'TôçEþ¹yEUkQL~	ƒÓüÂ[¢;'ËåI l
„†ð]Ú'½B&dOšÔU.)“èÛÎù.>]	pûŽš…c<ÕÀ€‚öc7¥þS,Þ%†±ŒÜÏ‚¿
lAÒ–þ‰¬––S ¼ƒ&¹Lª¼Ðh}9Ú<ÚTŸÂƒÑ³ˆvTìo@ Ä`+U­A§eêjÙÍWË¼ZvG_-�ô‡/—ÿT•oœNî‹¿\Âõôõq]<X¼v?U¼T¼&Oò2HJS²Þeø¢Á¼G¦=ñZqîÝ(ÅU6-F9³4ñÏ#S“¾ÙµÙbù|iVÌLÆ ðKg
³ª£ãB]CCI`‹èøë½(ùîC°J°Yjªh•Rü[(�LL@ì8Êãc³µ‰2•��™„(iµÿK@NÎC°Ìt&KWÎˆ5žäiãM]	_¸¤aRënc¤´?=F
ø‹ çùfò–ý)>}8Íàá$’Ì9È^}¾ÁùÉ'U#k"¾ûZ¾§*\…µê*”ƒ�"‹õXVžµ`Û¯Þ¸Ø™Z—×hR5šíÕnaäDŸg²nKìÈZäà[c‹´æÝ—fÛ`È¢Œ*ZôM²T�µÝ«¤þ¶Hgâ­‡dÉevÉdØ¿ˆÛBØMíØMGì”;•2Cl%ÏÓ[¤KY[d…,²2¶ÈJCE5|å?Í»»;|åw‡¯üUØâê>éŒÓyù™z­.R°R]³5D—ÉJºÌsè{U°&X«N{ul”`½›¼aðVƒlDñskoÂôžls8�éR¦Ø2ù½[á²$CãÚü?x\-ÛDšÑÞå¤]*T1ƒÝ’Î^!I>[´r]«Ó¤¬½-ª6×é$ìŒ�v”‘Ø
ÁTY©Oc1bGn7ôu-¬¹lbÍQU}$XNÐñ»(m).iKßl�-ÜT1áç4³skjòÄ²rb>èi;IÍ Ú—E43�öñc§r�Ñ]a½ª¯Ä¼¸¶* xÞöÀs‚Ma¥‘(›`Ð¤*€Æ-Ž`º2ÏÞÕv³ý¶`³¦=žä¼=¼ïxÉ<´o¾]Ôl²˜/Q¸=hæhZ•E<¹¶j<y¯Â“÷ \�6€Ô„ˆE>-^�Ý.¥HÐðò€+£' þ�'ý‘8¨ ÂQÕòhÔW,].’W.Ã"*ý5åSlÛ¨¶Í”ÕÂ?œpÕ»ª-ÝL³|F¯yª)îš1.ÍÎ–.{ü�ë'ŒmâpTþkLlÃ€J+±›°ó²ØG„�e£<	!Éj‘¾¡lï
ÚZÿ™F\Ö.£°\"I-+Å³�9…¼R„¬ÓhËKÊX�w*†ŒÕR™ŽØ¤È¡.˜´'e�E,_¼b$ÖÃÅÊÃöÃ?ZÈOÉBBº4ý>û¨4sD6‡dYÑ5;™2¬³Û‰0B^Å±âŒXP-…H!3ï´6’ÏAÇÚÏ�çÅÒÐ%ƒê8êHç"#â™TÕ®,—xð`£!�›ŽÄyÖlîmÃˆ±Q�Ô8ç!¡­;YçEd‹6üêÚ ƒ[Úš‹¾·ÒdÒŒI&ÍÑ‘Œ ‹�˜˜›WÏi/éKO�9IÍÆeÔbF]8£>oyßÒär²)œAþ [Â­¦›I3c‰é–ÓÌhÇŒef"–GÎåF>Ã£‹^¬�‰uaC¿[d…ÄêLû•qåE»+€Aâä¯dl„(—*³›D�tf@¾sý lzÑRv0ìÂ5›‚5øwí`¨“uy) cW[�¹h¥“	îRã!ù€tÐ#†ÔCÊáé`³ˆl–‘-"²EF¶ŠÈVÙ&"Ûdd»ˆl—�¿;dd§ˆì”‘]"²KFv‹Ø†ƒÙ£‡”ae‘é
JŠCí
‹Cí%]Á«½äìi?íšîªü 8@Ì÷ˆÈ=DÈûT#Ò·äA‰Þg‚CÊèê¹‡ƒÈ›þ¸*ê¹ÃÚÉ~“¢|ï ¿�†•‹�}˜÷)#ÑGlk’'@sÌ2štËÊJ‡øir\�ý„Öù§«HÎï${¸evÃrI°ÈåÅÚ½zžQ5�J‹™àþì�æ�˜•ªz¯±\!ÕûqÝN™ë†Ýì¤:é ?`7d£åt•žÇû�…Wc‡<jP¹08­ÌìÅ• —ÅãJÆA=ç×º£~pP	»€€œÉƒhOð�ìi·é­ü	-ìufÉL¤œÑ�Õ³\Ò,jº9ÏyÈuî�É¹
àëX÷}²ÚÙ*ª=lU€î7L°
Òò^¶ìýKó9Ûû”úiïÖVIÈþeÊ$Ð¯ÎÏÏçPÁˆ¬¦Phî8Û„€dX¦£~–—é>ŽY1®aÀ0‡Œ¥ÅPï•oõGÈ€ˆŒLP½6ÅÓÄA'<ªa?K"ÐÁ£.ÙŠÝÇˆl•
Þ7–\oa”ö¸�†5žžÄ†ryNx3']RlTºþëÏ�%�„®õÈ‚uTÐºæM÷ß+žøŽ|K5Î8…»¤·¬§œë�“‡œ‹�“/8—'œ«n¡§iÒò%=¬¨{qÐÒñÖÞH_Òà—h{/)�ÀÃôÕ%PïÆÿ“~!Ö›4TñTý …÷¸MPY„O®läþri´~¤¦Êè#C °às
ì ¢Ë(ù/¡Ö¦)íšÊ±Rj<5<k
•EÚ¿VYºðà6,'XseåËŽsI%ˆKžãgƒx~ëˆ­pRÀ#ê5%MÄê÷•íšý3Y�=Ó731zfbJ<FÆuP¥²ç.'j¸ÿ"çQvB6)ÒÄ`Q“æüL±xJ%qîÉÉR™5mt>%J�£3ÅÂ˜*�/�’Î”XóQln¦huÐk%¥œŽz�oº4=7­€Š^½¤£1ò
‡îÉ ÀsŠ|Ï
;.ÈL§i'K—‡K'JW½üÜåâD.NOgl¤Êæ�B9
±4±Lçg®ë´ŠþÆB–¸C^IÎ£ë·é¹Y¡
ácb!KWäxW0ÊÅ
÷qè6l´0[€ÁÙÇ'‹3àûþÔPõÿ Ãkñ”¼VOf¼ã#bx£väCÎÛµK'yåÒäÄ(o¯ÊŽÆ(|¾4Í¡D-}vb¤0ÙW˜öÐ�ÜxI,¶X1º©ÑÂÌ™ÂµÒœ¤7=V,^ê-\c
	l
ÒÈzùaO:w°Ä¨xÇ"'ÃàËÍ›ÿ‹ó§0;3qõ<šU.ÕëšwÅ÷Ä‰ žúâ4Aõ½>ˆˆÅ@­=p¤féõ¡Jb	ÓÅ?#s3•J~ŽóÐŠžT”¯(_¢î&¶ˆn«™?„‚£aÍ·j	„8oNÉ¿Tý¤À'ÀQ×Ej²/¼û�Åì5¯Ž%�ëØ‹A2¨gÂdÐÀ"„X£Ñ¨�¹Mè6Œ#ÍÙµ:§%ûßªáÖ �“— ¯.Ž,ÍþÞü¿–‘öìŸÌÿ¹¬°Lõß‘ýþ÷¿/Ëtš‘å(pÍ‘®ìßéy¬Vrrwö¾=µ²Ìªìž!UaµÈÙ"#kxX{­‚Âº´,°>;66&#ÌÈÆì~ðÙ„ì*®ÝlæÐ–`+‡¶Û9´ƒ
C$ƒ]Án®¾'{KÏh/÷‚+º7Õ~�Û‡;äÀ9‹�.þsmf_yå>F»‡ªm7²ö½‹ª}_pØª}dQs:(6ÀË9Í^¹R’‘cÙ¿ú«¿’‘ãÙï|çdä„Yçdööí—¼ëåˆr>^À“�ÇPóEFä˜9nFN˜‘“Qs/Nè~‰ìŠ/ö¼THNj'0úªñ£Rj�ñya­JÞº	®Ý—·Þ_mÜìVíUûLð�U;ÿºj,räg­Ú/²¶½ÉYûœUûü¢Öµ;ûÍo~I®«„GB-	µÚyl‘zÓ€½é0r0ûþ�¼_FÏ.ÅÓk	>ÅïIxõŠß[ Ê¼Õn(Äm<…E­�-
vùûÆÈF«ÑÚ…Eµ¶$[#Ïó”8¹
r�èî0Ú^ü²pµf‡ã{Yä
M}t‘S¯ÓÓÛ†¨MÞãy5ÞÒÏ¿ê¥®y™+^zÜKÎxÙ/(LN�¼VñÂö–\dDÔkFô¯,pš[ÊbóX?ëæ!è"`.-L$g=RŒLh�Ídð4DjØl$›z®�|¨@-€ú¡ÑÁ6´jÈÖ"Ê� QòO\USé-Ý0
¤®f¢uy·Z=ô‡jëA½f’‘ÍŒ�ýç£âÒ«»Žú¤¢™V³ÃÇP8æ˜OÔ¹†ZX›)¿!(1Á¼äJ¦ý4Òæê ÷­~kæÔŸ½tôÐËƒŸ­rT?yÔNÕ€[1
àYÌô³É¾VÐ
lös~6˜A™±leQXfeÎÚ™«P?›2¼Š	8e¥¨Ê)^·\g�#?é'3Ÿüô>úí{Ÿ«íÃz•|íÝß;ºë¿þä6&×±Ó´t.Z-ÉzgLãþÏ.\æŠ]¦^—Q1™WgÕ÷©þU£¾Q3Y•*Z°k‚jãë™9¶�¬b>õ}v�º¸9ÐØ3$_­æ
,gÜ�¯yÜb¼µR�Ôq}Ÿ=Öº¾P¿61Ñ'C¡yˆ‘Õ¼–‘q{jõ" Zßçì
«Nhmå\e9§Ê{¨Ò>u¿£(ó^ð,½ñ>æYx©‰>¾
ÿ¾ÿ¾Ã1µZ‰é`¡ï4°Ðb%’¬ø[D^’•‘˜üÜÂ=>+‰Éï²¯I~>rNœùng¤‹£¿GÑŽ÷á�6lô€v¼/žv¬Ý÷Î7t7@Å›’÷V&ë:U:˜3Ì‡b=(ÕR}z®<«[”0®Óa2Éd“�f€äXiR#IÅ1Ëp,ð>SD»^,i�Ò7Á'DÐÓ®›¥[hôB3�’”¿L>¤Ë^oqzv\z”¾Ô3Ã$ÚñYÌ6}7‹QZ™Ç‡ax!eƒ4¯DŽâÿkÞUCIöCä)™c‘�Ô¼&(Okkõ1ae+“Ggl…�dJ2é$É*£î|{f–©¢'Q}Œþ¬ãUäjMÓMu¦#ÛÐÑª]�6Ü\áyi”TEÅj�Ÿf
^\x‹íãý0MÉ�â×„œLóMâ:~5<��êÙß¦ˆwÛ
?Åi¼e¥™Q\]¬–Í´Á¯ºÊm¡ÊKH÷¬šÊKB•—úèB¹šÊKÍÊ #—Ù³ç�ŽîÿÕAT!‡`‡i5Ü×ÑæŒg.#ñ˜$ëß×’y

¶R7ôÇ(ïØYlwAŸ¨ôP¬/ú+·…*kÐ/XyI¨²ý‚•—š•=5©�š”@E)c¥ŠÎ@}í ïÞE€0¼{Âðî]k^ÿÆ
ÿÏ	­Ï
'†°:Ûj@•R>–Š2¶DuïÈ—”~}_ÒÃˆ˜áúÐµmíu6/µ&bÆ!{S‹Ý²¯{¶J9Ã0Ùý.Þ(ËI(÷F–…Ê’_£·XEVÈ7¶m(ƒÄë
ßC²B·VLŽ¬ÀO�UÊóØO’úŽ4EIG{-UéñRˆ‰	TæA–›Z‡ÖkÅˆTëÄ#>›–ìœ.¹ÆXõ(è¥¬0RÄœþB¹->lèdlÄN7áß¼ûÓ²&�g³vo•¶(ŒabëýäÀm­F·D}êBI¶ºúp[O+§.ºâ695×í¡¹nÍu;,Gà×«Eú:¡Ú!ÅÀ¤H †Q=z‡ÜumýßX¡T;­I"êaNg—Ï¢:»�„oðè2Rö}?+7• ß¤ìef]<üµñ›,*\”|<R§ªGßo4²ÌytXøÑ¹J>:]—íÔ6g\¼dR�~]R¯Ëý8éç|¿óº”ïžíÖ»g¾ác�PóÆ»“‡"ž—Ñ�%­Öax<×ºÖ*âM%ßOçKÎSJÆN'KW¼±‰©Ñ<Hd<S˜˜„'×ŸãHY=ÊN\C•Œá9Ñ5Žv.Ë¥™ÙSsS(@¤p³Åò,¼4‹3ÏG­ajÕ9ØKì]<K“³bÊðR¼\
Œ£´Žùr´k�À¤OŠ§/Èµ !èK,™17í�BK„Úèa–zŒ|Þ–¯¦yú 
#&C
 ©ðÔÜåáâÌÀØñ¹Ùqƒ‰ËÅ3…k°�Êt4YnAS-%©A>-fƒúêÞ¥|IC„)EëÝ€Íi	Poh¦T²Twô~57ÒÝöp}_XO‰«þl9-%QÅ[20�,fr€b¡äœŸ@‰K'¹ÆO Ê¸“\ë'Ð¨Š“þ�ëÂÉõ~Bžqfr<2ÃÉð lÌÄ	m4‘½/Ðî(x‰aðXlßoÍîýÖ<x‘í¬1&{À.;Â´�8<‰qx»Y9|ÀµæñrªEe	¼I½	n«íæ&4 ¼ÙKisÞ>6{nº0Rô’Ò1ç=m’Ô)aÆÑ÷À’üØËÒ=dTþRÌÏÞþaF�Â…ÚóÈŸŠ³²Œ)Ÿ×Ù†O>¶¡ŽÅ5”†aáÌ|¤Î››%�LËÿhÀÜ)0ÀV¶7˜jz¼œÞKYÞ'�„ÑyF`—kíf�è3Ë
É#×îuí�V½Z%öt]—ÖV³X‘—
ü"²’Šª—ññý5ŠÝ˜F/jôPÍ¶Ðê¸Ïà–¡-˜	ª,ÇðÙd�ä$ak°÷Xe¹‘fê ­*õƒ±iÏ–ü`5é8ù¾\…àf�\s³þ|À®õOqr7[Ù#™¯Aÿõ�¿:l«qÐà‹)îå50¼}|>°Ag)¤$Œñ*ëWÊpú:š„?	ù^M/`©ÿ³ú�¶K±LN†¸	ýSåÙÂ”8ø†ÔöZVò[ËÎG¥uOsº>Üv’Ä%g�”³Î
ãÖ
Â‘OB‡4wØ­Ï_äW}äÉ¼>¿@mÚjdówáæQ°Ö ôzá
½Š-¶Ž£bµÎ6–@ŸÙÎ
ü{ö˜]Í
d�¨¥�oÁÈT³™‹z2j�31¶.HÉ1œ¾1ÏÆ†Mr¶5ŒÇr)²!'Wk­ëž\+'éN¬[ÙCG˜žE—s6,HÂ¾:ÊDº±è+,•=µè1uhÑ3áE¯»¹ÎòìfùÙÑ{$5ªe™Ñ‰Òéð¾³�+C[™â3æ�¾.íC§”Ý¥�ç‘ I*'ÁÊ}DPÛ¬¬2j4®ð°D þtžp‡ð'B%µç*©LÕ×ßÜ' äÕŒº<G¨88u8a–U'‡3Ì]G}`sSf*nÊmÊl»ú2ã6e–7e.´)s¼)ÅeUGàß±ŸA¦â"á|¡Ö)a!¼Šël!‚ÍÇnjÏáXõs ýš•ûunâ_Ÿ�d“éeë Û¿_‰3z2¡Åc)P«=¢dœáv÷îÜnÝlSZâ¦¿5ÛÐÃ‘zŽnÞLMQY"®eýí>lu�¢)ø§å:+õ¼û ’ð�ßÆ)ùhÐýâ™mïRÜ“‰30ªX~Eäµî×8SOÏ‹?=	4}‘ËŽr5ðÝñáû5/
f!øî¨¾µ§Ï8Úmcg€kmW­óŠƒÜ
OõÚÍ^�FØÆiòŸü0SCÔŒ²^×‘G¦]^l‰�„DÜN„9'00úòhÍ²�j}­kòk
Ø¢*ƒðyešRÝ…#é–¦Tw÷Ÿ¡ãã9 '«ïúÛöÂåè€‰ÁŸ Â/yÔÈj¢øl�¨Ÿ“Ì#>ÛöÊsý	rF!¹LnM‹Ââvèè”Í§CG'ráþí«„
¶y
ÙÄî„M§OËã,+MŸ*–Ö�q+Ç/˜ï{áUù
ï
X•'»*1pJ†à„=2¯á¤fÿ·^ÜìùÅðü£žýÞÐìGõ.‰ÅúOKÙ
¯ËÈD|à¥È10sÚ�’_	¥ðyÆ™Ðzg4ž›Œ]#|õ�(<«‘ìàe¤¼ßñÂxDZQ~Ä®«hßOº›ª·CÒÚÛ<…çC‡ý|4‚X¶‚€ÄŒ�×x	ÑÇôö%Üš�Ÿo”Ž…×g_Õ‘
ÙÄï‚NF6fŸK(ÿÃK²EOE–fÇt¤#û‡:²"ûŠŽ´gÿ•ŽìÌ~Çc!ûhÖX+Ü¢Á>Z±ý˜}`�Yc÷Ä°ÆÎUdm"“Së6#™Zâ˜Z(¨™ZÿWÔ¼ñ/2«ÄÔ²*¬,WÂ�í¬±:ðÙ¹ò8{Z�N+ÇÆŒâepš:ñ,©xù¢�‡
WÅ½Ý?5Z¼ª¸=³2A”·Ö‹`gìê¬*<Vš¹,‡9efÌ'K#àÙôÜµòlñ²œ,-�ÌEk �ˆ¢–è9ÖytFÉ¿è)PŒ™ÀŸ��„œ)>S�é¤a"…éÙ¹efí$zUV×®€.ïœTý·¬M+iÖ‚È{¦†ö¨9þ'YpÕÎ‹Ô³7Q~¨4GÞ2�O5+V˜2¤…éÑ¢jÎ1_
2œr Tì:�ÌÎ&eÛs3„¾EaŠŒ©còøäd/õ¶¯ÏgU/£’¸Çÿhzà†êVïŸ¥…È	®¥hÙ�6ªMS°€ŽË¥¥N/{%åÉK`
@Ô;é†s`˜›-ÃÚ–¦zg
EL†žAƒàÊªY‰ž­ë•‹…™‘qXž!öyê…éM“gV9"ªCc3åY°o =‰âNî/ÃF§0fcSðyˆÝE	Sb™Åž�àÐ>ÁÐº¢…B@6ÆêÀ~0í@8™°#§FÉ´ßLé²úÎ°PžM{›¥Ô2|¡/bBÒ8øp¯’MfÓß‡aJ3Žmw}BÔ<5ƒn‘Cgˆ!Š|’@55Ú*¤…ªG&'F.9&Íá˜�oaT�oÖŒÇ'fÏ‘å+Ê—ßûq¬†Á7Q8ô8cöC¥)ý©iÑl0ì®wíÅ¢ÞÐCW±+q²Ð¿\ÿÛù�ÄÙs³4P	{,‚ùŒBÙ‘W°¸äan{Œ¯à°‡`Í"ªh Æ$AøF0­‰Z§öÝÆÿÈš.x§,¶“BGÖ”ŸBV½r†Ã.Ã.ÛÉdaeDXû‚’¶—kCæÛë T«|©&±ŒýÖ´¬zê4Ûã¥KÞw]ÁAE"œ8ma”ŸS%eÓ~Æ¤ý6 NHÞ_æOl4pÇÕ:
ÈÊYl‹Ó4—…¼w°�Á­6A¾~P#áÜ„&£wÒ‡ßLI7;žÖºµ%yM«×lY¯5Þ´Z³rÞÛæØª~4J±(ÅÜfø»tÐ€W»–¥„eF‚Vo2%)©;éEöÉ„CHë”›c9Ë&‚.ñ[�mÊ�ìË¬•â×íèsÖ*ƒýHÄ”*[í'¬xSÚŽc·Èlai
lm�âR"Ö’`"XN¯¾N)…×¢=„K­—¥6 |d£;—�˜¼IvÞ3hÚ�ÞŒÍmQ0ßxs°`‰Ä½Òä(Y±MN¯P¨‰™w[á34_pÛœ­÷6Ïèg»ìØ§‰`4€¤µØÆNãû¹—;ÚaV“f¾;¯5à‚=ÚÀý^5�}4&_Žé¥ð˜öÛcª ¨q Â0ã=LU4 Ñwnÿ�:¸v†ýÝ«FzPŽ»ãcbµñìTH
‹…ýºœ[†…oÔ!ÅÖn„3%]â‹óT‰s‰ØJ^j
lÂƒu¾¤NÆB;òš!M«tGdÏðpÐ@+UMOH‚ê��e�Cx…»?„[àHØŒã«ÀÑüuÓY,$cÊ†cvóŽ“rãæ.ƒ^p"OÿžÔnòè³é´:Þ©;Fsƒé3~DY‰¤ø1ß—S¼ßùr6xU|ö§ÔÖ9nê,�àR%’R,<ð’æ—~G¸ƒãšÙÖá…N*ºŽ«Žïá=îY¼ÿÕ36U“`Àü*w×glÓ'#ÒúˆÊ§îŒ„Û˜Áf¶*¿¬�wŠŽyËå½jæÛ=¨áŠjgæ±ežÛÒ�EbWpÚ D!hÞkØœîêºú»dÅÃÎ%¹Á…_ô1"«?ps?Hl×÷xÁ´—™@”Ò×Ï®ÜèÄŒW7Y*]š›öjðAD‚¨ÿ´ö¯ÓsLX8Í7k$NC¬¯À¯
ã4A¿â€`*ŠßƒYS;y«•ü‡2Y‚ýÒh­DYöe™ü dö›¸3Q‰E%æ£¢ÏF%>l$ÖÈÄÁ®ó0Ä›¥è9>@Ïå5#ç«¯’¦Ð9L�ˆìyFd7&©ê#FóÀkc¿u6µñ„¸¯?ûª‡]òQ	BYrÃ«ˆ€Bó½Fs¶ô„LÅI<†'Ç#y‡âù&íÆï¤Æ¼Á£›¯Fé°üq£Ê¼jú~¢rß0‹¯]•…–ÎÐ³ÀžÚ<â£¦Û‚©yA=Áç¯ÕP½×N •Ê�òÁô$�·Òœž´æ´DŸ’M¨âzÉ‘<I”âÕl‡ùÍXƒ/¾·¨ËðqF6íGÅ÷ÍGEFšËÅnŸ"¿!ÁP^‹[9ï-ysE/¨‹V÷W`|.g¯wDÌOà+hŽÉ9H’'/k‹¹/bñÚì*FN‡_Y‚¾¡#+ZKcäqC´4Kílµ4gˆÈ±—ÅNÌÜTZÊýÈÍµD‚™ëmº »àôpzaÐ]Xt¢Aw¡è.TÝ…Eƒ.41t>4‚I’+a6QL†„Ép4L†+Àd¸2L†	“ˆ‰™0V0©“®ZÅ'6² LF¢a2R&#•a2òša¢&fÂdD�ÛMx†m"‘±3„Ô‘™¥Í���Q±Šæè ’l@þüo&"0õ©JL‚©³	óž	ÿ»²_Æ>ð×6†€Þ¬�å’ºdè�¡e0Å;¤@§š5¥ZØqC^R‚~ÑÞ,cõ±·‹yÃš€~œ^pïvÞ”æÕÆ/Rb’†ùp8¼çG6^ËÊýÍ¤È3;ÐÄ7°ß£®Ç—q.?x!åž|³óƒ•Aƒ³ßâ…1�¬,nCKÒ~Îã– °ÜªkÄ3Â¡å”Òð˜z7�ÝÜÆ#r=ž_’8~ZãøàøY·Q*y$•„JŠñõ²ïPdÁ¤_J}ùò±oè�¶EVC{Y±ë wŠUÉÐèP£¥Ñg{¼TÉóiôI=z�õÒÆè;=h2�¿$�1ÃM^4_°'<óí¸C
‡«¬ÆóüÔ�¸ß·qãŽÁ/û´xéD$q'my%&âŽ¤¾¦û
?\øâ Ój Tà±Ô¿’þ9©=eæåÖ~SÒ†7­±9õzè�gëSÆ�
ÕøÁAšƒ§,¶€ª�jcPZ'aõ!"`Ãž5ü$UìéA>¾
!¾s{ô·b|i<ÉRxLŠ2ð„¼Y†e`D
2p!ÅMŸ‡‘±p0:üßUJŒú‘¼³—%QRHë,?	:ëÐüŽüÀîÏÂi[Ì…*(úX½'om™²Ç³:«Þ…P½ó‘í.ß‰*–/é._’—ñÏ³Îž©rOThÔ8&ÞO7
ß+÷Ø¤5ï'Bó~L¥ô:çðË°Txˆ¥ñ“°¾�b¨¡7‡N/IÂÍr‰xBš r\º™4Æ)ÇPg¤mQiôIk-˜LKëÆ“tAŒ;mà
Ñ*¿Ï:¾
ž–Õz@­'¤ÿî@s³¾¯Ìe‡8øî�@yÈšréþ%D—ÎÙ<úº§‘Tï±Ì.‰*´mEFP×ßê�ºV£ïÒ™ Œs1}—Öá@gUÍ903‘õ’Œ¸ú®Á=¸ßP¾E­jQb§Y>…³æ‡´5oÊ1�ÊÆê˜`®‘�§0ùÂÂQá¤wŸôƒòR«%ZT‘b›iôü« ‹jÝ$˜º¤cÕ@öBÕÄÖvÛÛï?¾jÞoWœûí¿2wå-•uzóõCÿ^å¯!’bŽÌ–Jd.oþ¼Ù¤ù­=k˜àðRÔX–Ô_l{ŸF
0I¤|(�ô£yÅ„Mù>ÝúÜ%Ù^Ê,ÙÞ�%ÛËNV²u�£~†?õ#~ŠCÇÄ%Ä`{³’&Ö_ó$.Å¼Zj3³‰¹ðö°3Þð·kpÐÐI—öüŽAötÂÍyç £¤×ÄÐŸËsäªˆ¼Kyž~Þ9NVñ	µ5¯?ö+Qû»M»6E^˜œÄº~ó$­ÈµØ†<…ªû”ñš÷0súiï{1Ò°/Ð†ÿgQÙ¢�"Xˆ>Ê@²vV3^”œÔÕú5ù^ü{=$bû^ìêzdÙ‡a&Áêðäww&‹òšï|½ß)ÎÉ>È(Ò/pQ“‡6¡B%…¥íàBŠ…Þ´¾î_Ä¿’Ø@

äò%9ÈJ§”M>?¢³«ôüQ%!z¶v´AìF±·î‰“µ çþ"€ª7Ú“÷TµkiQ””2å�Ø‹nº$4eÊ2’kÓ¡«Ç]ÉÉ�(åÐP8éê`„yË(“—CCQ©®X&Ê�ZR�ŽH¤UÚó²d¾@tmx’ì(‹Žjw®†#Wr{^ ¯g¼AïÌyï¼ø{Â<á)ÑTð£dXòl!Ôj³åY
:Sð&Xf»'\Ò”ÀºÛ„®NeBÇM„¿•´iº#óñøðP~:}Ìe
Ð©¨2h53ò¬³ÏÙ“	Õ¬‰t/Ë×br]Å2õÊˆ5DÌ¤1Òª“(Ü©ÓS¸9¢pK\á–HAøe™D‘ ÆÀÂIdKüÝ`)f·«»jÙÇ³ÐÎ˜§V¹ƒoÜÍ|ãî‹5ÐA»!ªýNÕþrj­öiÞ*¯ 97Z�.Ö T	+L¼ie^iw$ƒnv:«Š®Òi9?[+�|Õ+é‰ÀÏX©¬°¬îg|Ç–¬C%çµ	*³ÆxÝA;2?Åùk£Û@ÉŸ1¡s�ÑŒPæÿ/œ¿^>{ÝqD5ÊoÚ`ƒôËªäôò8WØ(+˜3‰êaWØÔ¯Y]Ál=z7ôhd]Ô†R�ý´�kFlšÍDK‰Íßæ(*äw�ëÌ
ù+uŽÚ·[QØüñ“0
Ý£–v¨-¾“ŽÊwÅK²ÎIä�cÃnÍB�,�oD:¾”–
½`—�§cÖnås�îdï±OåKÀ“öžgUâIžt�ñ¤mˆ'ŒÃ“@œ²0=
¾áÁíø¯|¥ªßÈ&·VÂ•Â5
�šñâÈ¥~q/;•qU^EÜ»=„úLHß”å¢öS�FE#>Ñˆš2W�™�‰C¸Òêˆ4¡ÏMöHHSSº*Rª^©ü+ÔÊB¸D
Ã�bŽŠ7U\m¹E jåéÉ‰©k^$‰µç.¶0~°nñ¸‘s…¾:3´FÜPà\Yˆ;‘•j*>YIn#VI¸YÑ}ÙÕY‰:Ô1Ë¨C$áR“lAK<¤ðº3Üz}NŽ*"_�ª¢u3šªÑpx€Ì#�‘—�A-*Þ¨N×¦ðh_²F;ä-Øj|–{#/)5G	ö–ÃäuÕ4/ÛJ_ó4/|o2¢q¶6%¼„ml/É�“Œ�%Œùtq)$*<²vü»L¯Û;CX8ì ´M›‘FNé…¯æ©BX…äC‘<ÉÄ€»ƒHž&•t9RvÞƒ`Ï²["‘Ü…dÍIÏð»½ÞµT±bP²§Ù(Öm$iõÉ.†cZµ`uÛY‰ýmŸ'>H˜•%›œd±E[¾»e}BumÍlö5­6×jãÅµ:
žöÆâZkŒZ÷ÆméÈ}ÙÞJ-D;ÈnÜ¾S¤Å÷Å—!¦ü“ˆ�MäÎ¿I@†Þ$Èµ‘Ð]dàžØ;¡[®Oz-M:³ÙóÇ¼‹Qµ3é“ñe4‰qsþo1_c;Ó—Í¤+ÎÙþ„•NQÂ`7Úßr‚5ÔSøÝì®t,ø	ž!”üšŽ VQ_¨�‘ŠgÝÄJ&š^1Ë+Fiâ¬d¯ÿbÈêŽ^rdŽÝFŽÓ=Œß}uñK§7ß:ó©Ê”{�[×õ–ÎLäAÄmo ¶}üšÿ¶ÒÌÂ›¥ÒùÚÂ@e9¡Ù…Žu®&ã¦»¼Aò.Çˆ›ÄFÉÂ±Ö§wžÁ±‰0»¿�¡gõFø§1¤¬žRí·L¤	‚˜Âu…ëâ
7UG¢Â­Ñ$¥èÂ!êÌ†Ç^QxM\á•…WÆ^Qxm\áu…×ÅÞi‰d€ŸÊ=Šõ°Ù©»�ÍtùÞ¢žÃ‡ð#9Ú°Ëƒ�í�óÛ‹Wg·v ]Þù†ihâÆ«"žÄhA‚Ô€£jëg±‘8ŒáQñÓôÊ€©ã¯lØ¾©¬'Ÿ¡x®u°KSNL²qÓ¼E…|Ü›±LÎîÁ�ºtqEEç¦ÎO\.ŠÛºF´þ¶˜}´‹+³1#94²»øÍzç¼býß!DfqþØ“=Þ_Çœ¦ä^ 0®V¥îW·|Èæv`�ê«Í¼‰PÃ¾Ì
u7[$W¹4Év;Nð«²ä)ƒ:6.Ù€ö•ó$xkIÂ4EtÔÑÑú¨Žšl|¨­ÐQß’×½ð�onˆ-RŸac+æµáß%‘š¾KõµŒeâÚ`lA1ˆEs\^‰°)�5r­.güœ¼ÂéŠ“W:³XœÓÄnuPßËõz<¨ïu�&âI´Ý<‰æþ¾ªÝ8ŸÜå21|vélôPþ•ÇÉœ0-Nwðí7QÎòd‰CDQluh²øLqr§7‚ælT�þ)e]c¢Œ¥©ÃQàˆlƒ|9ž%iô!—B3Ð&GÕS£�aC,œi8$ŠîÔ‹65C•¦J³c×°Ùã1Ê*×Ê¢v1Róó&¦ž)L¢aŽt|H`áAÍLL]Ô>Ë:Ã»„4ÄîŸ/ÎLÌŠZ1WŒãRû™€Å…*½¢Ýºvž2®Õ�§ÅˆâwñE²¢>tW&~&‚¸Lzµ=^
fcèãw§PÈ(jQx™¼,[ÞÏ2s*×Ï"‚ú5Ps’ŽU~ Ôj‰/î8,—™“ñAÖ¯—/�n¸‰Rÿ*ñFgÜˆI}1/î&ºc*Q›øü¼enÚ,ÒÊDEãUwRÒõ@�1ûwÿ?‘Á6ßÏdoþ_ËH�-ýñ<F¬ŠivQ–ÍþÃ?ü*…2ÿç2d¿ùWìœÝ÷“šÛ›¦H
J½å”ÒSåÈy�›\ƒF+rA›”[Bf,j‚¥f
HN‚ée¸ÇäñOë½IêÏóNë 
Mƒ×þF,mü(:µ!˜V¶#`|Fàí½²nÛüŒc¨8a[_NpÎ[Y*®ÓXÿôÍœ¸ÂøþVê41Æ•‡Ú�¨Ÿ:d›’ívLËÖ²·³.ß¢ËÃÒ¢ì2rÅ�ëñÒåñbqðÔˆ¾´uhüQb¯IlÎFÌû×ÙÛ„-{kÎû]	sÞšã%×ZË*T�H£èwàIÅ©�”`b%´&Âkô\ù¤Ž„^SI¾àyËj†ß3a·VktÈÓo?c�¼ø7gKrÚù>øòÈ#¹e_ù	{F#díš\¼®ï—†=mø°?¿°KÚ� ?�òÓR,y™ÞØ'^Ufs6±luJo_ïù¬¾:p¤mHö.ø‰c)aÛ@2wÁw¬ÝÏê2¿Å‰í¼&–öv»)Cß¤SLÆFaÅƒ}K¾o}KúÓÚ@•ï@4‹úHÑN
Ñ4@ô¯%D—Ð
ÜÐ“0À˜R`Ìùj‡8£JØ£J£ÂãÌAãœVì}8™4.MóÐŒ½Gk™ó¢{Ñ@4îC¿úû°fáû0·ð}Xº3x!dü}füœ¾3~mô}˜ÅŠYQQÝ‡YQQÝ‡YQQÝ‡ñ5^Gãô>j·A¤¾Ý0vO_ŠÊˆäz7¹o¿ºÐ}Xoß‡,>lœJ—µ›¢ãŸg�¼×s¥\¯+·¥+ÕYÈˆ¾/‹w#‰ü-¤¤ø.]Øeš}aßé½ç¥Ò7°qÐ¸#ü ú˜T‰$kåÚ¡�,P •ã…PK™¾
s¢3!ÅÇ´bþd—-m¹ì/ðø,¿6ÔFSæ¡j!½M§çx;öÜì}_$®ŸV¬�ÈGõuvœ`en‘/îJ#"ÑµW¤9Œ,ƒå”‘NZ^yFv7>¶êA¤‘K±ßäŠhÇtÚoæ¶J‡IkØî¹ZïE7¸�éÝH7¸Ï¥\š˜*o?QšEið5I¨pãC^sÅÊz\6d'˜¡DxŒ)Im8r¶p‘Û™¥÷þ0F‡.�°dòÝöÚÂ”Â7Ôö#Iét²°FÈrT hX9¥äà}g•…Z(€VóêÑL¨è¨h<VíÆjRë0o¬µ¸±Gn¬A±%ÔæúL*Ýøqb{ìæ2Êë
Æ	,ÜÎ¶˜Õ¿˜(-3ËîB ù{(%fW±‘‡Š³3#e¯46V.Bùa+y²86ëÍ
Œd[&7¥Ü‡]ç�)
Îk° J�j"‘ç°¦«q¯<^-]ÑyFí¼NÂt¶�ä
£áU£ewéa”ïÐÈlP˜ÚZœ»í^•zÃ¾aÊÌ˜ßp6d¿5Èksn^�Ê«]èÛ¯5¼LÙh¡¢õªhƒ£ßøAî·Q¿A€^Ji¬µÞ­L
šÅMÖ"~­â×æ'Ñ
ÖI@ê�yª((ƒ+oqâ­N¼ÍˆQ¯ƒXÓ©
Ê¬ÛRCjHièÖ/‰¥
íUeƒÿòlíˆ:[½ 3XÎ§l—R [¬äPw°ŠC«ƒ5Z¬ãÐú`‡6›lu0Òeì‘èÐfG[,‡Ù[â²I>j«Î®òlß¦Îö#|¶“»�#‘g;�ã·“	çs"Aðïï€š7~�Ø{ÀC%Ï¨¤Oyãè'n÷x7n8€O‹Ö žul*ÊºÁX�„{ÃÔ8
:{c…ÉrqnšþEçÔ>B	ºSúD™øË³3sPþÁ²PE1U–ä¡^“�«8ÞA8BqÀ3…Ñ	‡ro0ÌCv³� €rí|Ï\[×Š<Ð�?Ä¨hÕûn;Óï;ù;Kcž¯åŽ KŒ#}SDZúîŒÁóœ+c§[¨ÆõD];hX�®³¯‹$š›¹â%Ç½?nƒs¢^¾ÈÓZ>¶Ò|}=HFÚdl$ÏtHñÅIkã£­
"ÏúY‘MYŠ,…Èwsi‡È?«¡È2ˆLÖS¤"�Mé„ÈŽVqµµáCVïw’·Vy(á�½}û%¶”4…kÁrN]§,EVˆ¬ð²BÌ�õ»½`¥*�}þÌÏÏ{Ù={öÐzœ1èH’ÜÕ‚bŠƒvãËµiñp·*GôŸÓý¯µúGh|ï{ßÓ•õˆP‡Cá1ø±cHÆŽ!1†VÃ;Ü‡ç¥<9.Ia£)$î&ÛM*¶›T…nþæoþFu“­¦1Ý€N\âÖöŠ»W¯`ìnÃÚ?þñ�½ì¿ûw¯T±ÛZiÑŸ\ÅV¿÷½Ï[pÿ´Rúc´ZÕŠµR»ôg±ëÐJSu+èþ—Æ;q6DÀå'?ùÉOïÛóÛíáwu‡û0æx7œâÞä½Ž3ø§t6ˆåh£a¾‘Ãîú;t­í~= �Øú?‹×Ãðç×Zµ»w¶F]kßùÎ·«½Öäð~øÃVy{ETþîwÿC•—T\Ï‹¼¤Ät_ÌëíŸß3?¿gîàÇŠ˜Ýù±þËÌÏwïÏwï?J,©Îÿ9–„°æ-ñÿï­¯çùsL¬Ú/äÞÏ&Æ’"ÝL0Ýœ8e¹f3Éûü»V
­CUš´yPb™=ëƒ4‡¢ÔóÒyÅÍIshSÐÃÂ›ÝÞÃJÝRäcKä§6²UqrŽb¯’“s4ž“c±êÿy+Ô¼±.õ`eNN$¿Ù7Ä‘A[wÊçg,Þå‚+Na²8S-›ÞäÈ“n‹Ëf�eh;iý—ÁáTiªâ³GðÖCÌtê«0âÎ›IŽ4ƒÉæ"Î«‹PgI1=úÂ,÷Œò<Ks³�k0º"¹L³âÿoXü?)
”¦ÉïÄts¹85Ç­�”.—ò¥©ûGaýÀMí©‰ÉIjZ+N�bÂkcZÍ¨­B®i«ab…%'là:€
‰9&ÇË–(—&'"Ta~Fy`¯4þy`i[ZÂöPº^ÉLˆC-Èá±æšÂÈ*ÎV
ÕdíosíZ-Ð°M[7Ý·*‘=Q˜ºCAÆ�ÈÂ0ê
SwfÊÝ
ØßïÖzHkšèLn&Q«ŠµÒ­EÂRãˆ3Á×_ì’|ø“	^.aó²Kó¬F“òüM¸ÕSE’,œ˜‰´VÈ9r'‡©d©MòXšÁ‚y­Ïf|œjVÜjËò,#Z+ËªÐÄŠ�$+ÚÊö·—‡ZnÀ–Ü–—cË
< ®PµzSYWëÊ³³”vªÕ™¢ÍºÚŠ¼‚N€ ±S­«ÕºÕVæYt«u‡ªÕ˜DºZwžåÆ�}š–û´6ÂJO"XÅ»ÛN]Í,];u�@~ÐkÄÚÔ€Zˆ—Ù÷Ìßd(i�t„†ãX+~ëÅ–ˆû
~½xwÔùµÒ%ÉÄ;‡knŒ¯Y/êÖ¡Œ¹Uó®Ù õbÐó®	¬FDÁDYö©§žbœ–oµ ¼”Â`±í¡§šFÉŒ&ð�ýT“
Ú/ršLÎY=ŽŒV|ù&.Mèp»SØl]R6«¯mÌ8ü ñMl\!Ô8§”]8|Z
³%qk�¶`Â(ØJÿ’ÍÛõ€ð¤ƒÎîØ
õ@Ç>uì/¢ã*V²;¼’¿ýÛ¿o§?°z'd›¥§ê}Q«½ÇX/ÑQ’:JVÕÑ"ÖueŠÖu®ëŸ{·–{ÁÎì_‹^©û«W¯zÙW^y%æzæ€ž4ÔÁL1a¹ž¬tü„S•úÐWg²	/îMJÞ–¤	ïÂ	 úX©bó5§'""7–ïÌ²ÓhÎl jºû»Ø™ý;¯ÒùÒb¶\5ü;äñRuecT�Æâ™Ó2vbÊ‹{ïÓÂ|”]íÖ×Îó¨h“•«³§£ŠŒOeÀFVjÀÄo	£´}
îl×WT{~@"10¦aN`Ç½YáRÎ¹›U:ÙÏù¹Š�ó}¾|Çg¼š/7²ËFv{Ù‘=^fd¯—Ùçù#û½óÉê/{ò�œsàMý1—Ã2>ó¬Z„.œêÍyÍ­Y›ÀXV*<×JC[6–q†–4‡Vý>1]–í¡}—ï»¬&šU;>?ÔjÔñ�Œ¥[:é…¾º·ŸìW¤³Béì¾(îÁ¿ñï!I:Ã÷Hpo}‹ÜM];¬¨kGâ©k^p48ÆÔµ•Áq%g}bàÖƒZoúxéÕÁûuð”×Aí¯Lñ$»_ŸA§.ÓG¸utod‹±¬oE±]ôÏn‚t@-!ð´Ä0ýn¿¤öGÂyqÀ€ØpA;¼[«<Ï6æ"ÔtÝZíEpp"’ð×%¦âÍ ÍFRq¡—Ó¢H§'îÕ‹RëŸºV«ªµ³¢ÈJÐ>ðl%Z(¤šË<OG«jõ¼(Òí‰‹Ê3­|[Æ¹ºÄ5g›ëªªå1Qd•'�oaƒi]·Öy1ÖÐªê+/Š¬'�¤µ³.˜ž™P5dÖHÈŒ”¦fgJ“åíç&.OOIRŸ c¥TÕòý¢ÈZïV³±’Ljì‚)p¸ª¦E‘õr�Ñú]°eŒxÕ[wƒw«Íž¼šöÙbõË³ÌƒÝi�²—èßeúT¬ª6ÿ_Qd�w£×Ë	>¤&'iòš€
“¿’,ËÉödÜ%&µIéÔáˆÌ¤tN‚Çš™Éâ~^,'×ÄˆW1ãc¢Àÿâªÿþÿÿþÿÿþÿ	ÿþÿiconÿþÿÿþÿiconöƒFôÈÿ¾L“ì¡sÎ¶ÿþÿÿþÿlabelÿþÿButtonÿþÿlabelE»b[cF•EÀ\G½ŒÿþÿÿþÿlabelPlacementÿþÿleftÿþÿrightÿþÿtopÿþÿbottomÿþÿlabelPlacementå•¢T åIŸÄß^æãD©ÿþÿÿþÿselectedÿþÿfalseÿþÿselectedî/Ï?ëZJ�ñ…ƒ|úìgÿþÿÿþÿtoggleÿþÿfalseÿþÿtoggleg¿¥íY˜D¾ê±Ìœ²ÿþÿÿþÿenabledÿþÿtrueÿþÿenabled!º—À­RG¸5S8ìêbmÿþÿOtherÿþÿvisibleÿþÿtrueÿþÿvisibleD*Lc³XTC¦$úv±¢ÿþÿOtherÿþÿ	minHeightÿþÿ0ÿþÿ	minHeightÃP¬»¸K¨‰u@•&ÓjÿþÿSizeÿþÿminWidthÿþÿ0ÿþÿminWidth!7“C2«I”»¼ú l/›ÿþÿSizeÿþÿÿý)<?xml version="1.0" encoding ="utf-8"?>

<componentPackage xmlns="http://www.macromedia.com/flash/swccatalog/7">

<component id="Button" class="mx.controls.Button" implementation="Button.swf" iconFile="Button.png" tooltip="Button" src="mx.controls.Button.asi" modified="1059073889">

<movieBounds xmin="0" xmax="2000" ymin="0" ymax="440" />

    <include id="BoundingBox"/>

    <include id="SimpleButton"/>

    <include id="Border"/>

    <include id="RectBorder"/>

    <include id="ButtonSkin"/>

    <exportAfter id="__Packages.mx.controls.Button"/>

<class id="mx.controls.Button" >

      <Event param1="click" />

      <TagName param1="Button" />

      <IconFile param1="Button.png" />

   <property id="_inherited_selected" type="Boolean" >

      <Bindable />

      <ChangeEvent param1="click" />

   </property>

   <method id="icon" >

      <param id="linkage"  />

      <Inspectable defaultValue="" />

   </method>

   <method id="label" >

      <param id="lbl" type="String" />

      <Inspectable defaultValue="Button" />

   </method>

   <method id="labelPlacement" >

      <param id="val" type="String" />

      <Inspectable enumeration="left,right,top,bottom" defaultValue="right" />

   </method>

</class>

<class id="mx.controls.SimpleButton" >

      <Event param1="click" />

      <TagName param1="SimpleButton" />

   <method id="selected" returnType="Boolean">

      <Inspectable defaultValue="false" />

   </method>

   <method id="toggle" returnType="Boolean">

      <Inspectable defaultValue="false" />

   </method>

</class>

<class id="mx.core.UIComponent" >

      <Event param1="focusIn" />

      <Event param1="focusOut" />

      <Event param1="keyDown" />

      <Event param1="keyUp" />

   <property id="enabled" type="Boolean" >

      <Inspectable defaultValue="true" verbose="1" category="Other" />

   </property>

</class>

<class id="mx.core.UIObject" >

      <Event param1="resize" />

      <Event param1="move" />

      <Event param1="draw" />

      <Event param1="load" />

      <Event param1="unload" />

   <method id="minHeight" returnType="Number">

      <Inspectable defaultValue="0" verbose="1" category="Size" />

   </method>

   <method id="minWidth" returnType="Number">

      <In‚ýÿÿÿƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿspectable defaultValue="0" verbose="1" category="Size" />

   </method>

   <method id="visible" returnType="Boolean">

      <Inspectable defaultValue="true" verbose="1" category="Other" />

   </method>

</class>

<asset id="BoundingBox" modified="1054593655">

</asset>

<asset id="UIComponentExtensions" modified="1058814666">

      <exportAfter id="__Packages.mx.core.ext.UIComponentExtensions"/>

</asset>

<asset id="FocusRect" modified="1055744819">

      <include id="BoundingBox"/>

      <exportAfter id="__Packages.mx.skins.halo.FocusRect"/>

</asset>

<asset id="FocusManager" modified="1055744781">

      <include id="FocusRect"/>

      <include id="UIObject"/>

      <exportAfter id="__Packages.mx.managers.FocusManager"/>

</asset>

<asset id="UIObjectExtensions" modified="1058814702">

      <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions"/>

</asset>

<asset id="Defaults" modified="1055737279">

      <exportAfter id="__Packages.mx.skins.halo.Defaults"/>

</asset>

<asset id="UIObject" modified="1058814731">

      <include id="Defaults"/>

      <include id="UIObjectExtensions"/>

      <exportAfter id="__Packages.mx.core.UIObject"/>

</asset>

<asset id="UIComponent" modified="1058814700">

      <include id="UIObject"/>

      <include id="FocusManager"/>

      <include id="UIComponentExtensions"/>

      <exportAfter id="__Packages.mx.core.UIComponent"/>

</asset>

<asset id="SimpleButtonUp" modified="1062225026">

      <include id="BrdrBlk"/>

      <include id="BrdrFace"/>

      <include id="BrdrShdw"/>

      <include id="BrdrHilght"/>

      <include id="BrdrFace"/>

</asset>

<asset id="BrdrHilght" modified="1052770908">

</asset>

<asset id="BrdrBlk" modified="1052770913">

</asset>

<asset id="SimpleButtonIn" modified="1062225020">

      <include id="BrdrBlk"/>

      <include id="BrdrHilght"/>

      <include id="BrdrShdw"/>

      <include id="BrdrFace"/>

</asset>

<asset id="BrdrFace" modified="1051767541">

</asset>

<asset id="BrdrShdw" modified="1058931521">

</asset>

<asset id="SimpleButtonDown" modified="1062225019">

      <include id="BrdrShdw"/>

      <include id="BrdrFace"/>

</asset>

<asset id="SimpleButton" modified="1055744781">

      <include id="BoundingBox"/>

      <include id="SimpleButtonDown"/>

      <include id="SimpleButtonIn"/>

      <include id="SimpleButtonUp"/>

      <include id="UIComponent"/>

      <exportAfter id="__Packages.mx.controls.SimpleButton"/>

</asset>

<asset id="Border" modified="1062224872">

      <include id="UIObject"/>

      <exportAfter id="__Packages.mx.skins.Border"/>

</asset>

<asset id="RectBorder" modified="1062224887">

      <include id="Border"/>

      <exportAfter id="__Packages.mx.skins.halo.RectBorder"/>

</asset>

<asset id="ButtonSkin" modified="1062224893">

      <exportAfter id="__Packages.mx.skins.halo.ButtonSkin"/>

</asset>

<asset id="__Packages.mx.skins.ColoredSkinElement" src="mx.skins.ColoredSkinElement.asi" modified="1062582563">

</asset>

<asset id="__Packages.mx.core.UIObject" src="mx.core.UIObject.asi" modified="1062582563">

    <include id="__Packages.mx.skins.SkinElement" />

    <include id="__Packages.mx.styles.CSSStyleDeclaration" />

    <include id="__Packages.mx.styles.StyleManager" />

</asset>

<asset id="__Packages.mx.skins.SkinElement" src="mx.skins.SkinElement.asi" modified="1062582564">

</asset>

<asset id="__Packages.mx.styles.CSSTextStyles" src="mx.styles.CSSTextStyles.asi" modified="1062582564">

</asset>

<asset id="__Packages.mx.styles.CSSStyleDeclaration" src="mx.styles.CSSStyleDeclaration.asi" modified="1062582564">

    <include id="__Packages.mx.styles.StyleManager" />

    <exportAfter id="__Packages.mx.styles.CSSTextStyles" />

</asset>

<asset id="__Packages.mx.styles.StyleManager" src="mx.styles.StyleManager.asi" modified="1062582564">

</asset>

<asset id="__Packages.mx.core.UIComponent" src="mx.core.UIComponent.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.controls.SimpleButton" src="mx.controls.SimpleButton.asi" modified="1061503691">

    <exportAfter id="__Packages.mx.core.UIComponent" />

</asset>

<asset id="__Packages.mx.controls.Button" src="mx.controls.Button.asi" modified="1061503690">

    <exportAfter id="__Packages.mx.controls.SimpleButton" />

    <exportAfter id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.events.EventDispatcher" src="mx.events.EventDispatcher.asi" modified="1062582563">

</asset>

<asset id="__Packages.mx.events.UIEventDispatcher" src="mx.events.UIEventDispatcher.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.events.EventDispatcher" />

</asset>

<asset id="__Packages.mx.core.ext.UIObjectExtensions" src="mx.core.ext.UIObjectExtensions.asi" modified="1062582563">

    <include id="__Packages.mx.skins.ColoredSkinElement" />

    <include id="__Packages.mx.styles.CSSStyleDeclaration" />

    <exportAfter id="__Packages.mx.core.UIObject" />

    <exportAfter id="__Packages.mx.skins.SkinElement" />

    <exportAfter id="__Packages.mx.styles.CSSTextStyles" />

    <exportAfter id="__Packages.mx.events.UIEventDispatcher" />

</asset>

<asset id="__Packages.mx.skins.halo.Defaults" src="mx.skins.halo.Defaults.asi" modified="1062582564">

    <include id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.core.UIObject" />

    <exportAfter id="__Packages.mx.styles.CSSStyleDeclaration" />

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

</asset>

<asset id="__Packages.mx.skins.halo.FocusRect" src="mx.skins.halo.FocusRect.asi" modified="1062582564">

    <include id="__Packages.mx.managers.DepthManager" />

    <exportAfter id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.skins.SkinElement" />

    <exportAfter id="__Packages.mx.skins.halo.Defaults" />

</asset>

<asset id="__Packages.mx.managers.DepthManager" src="mx.managers.DepthManager.asi" modified="1062582563">

    <include id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.managers.FocusManager" src="mx.managers.FocusManager.asi" modified="1062726409">

    <include id="__Packages.mx.controls.SimpleButton" />

    <include id="__Packages.mx.managers.DepthManager" />

    <include id="__Packages.mx.managers.SystemManager" />

    <exportAfter id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

</asset>

<asset id="__Packages.mx.managers.SystemManager" src="mx.managers.SystemManager.asi" modified="1062582563">

    <include id="__Packages.mx.core.UIComponent" />

    <include id="__Packages.mx.events.EventDispatcher" />

</asset>

<asset id="__Packages.mx.managers.OverlappedWindows" src="mx.managers.OverlappedWindows.asi" modified="1062582563">

    <include id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.managers.SystemManager" />

</asset>

<asset id="__Packages.mx.core.ext.UIComponentExtensions" src="mx.core.ext.UIComponentExtensions.asi" modified="1062582563">

    <include id="__Packages.mx.styles.CSSSetStyle" />

    <exportAfter id="__Packages.mx.core.UIComponent" />

    <exportAfter id="__Packages.mx.managers.FocusManager" />

    <exportAfter id="__Packages.mx.managers.OverlappedWindows" />

</asset>

<asset id="__Packages.mx.styles.CSSSetStyle" src="mx.styles.CSSSetStyle.asi" modified="1062582564">

    <include id="__Packages.mx.styles.StyleManager" />

    <exportAfter id="__Packages.mx.styles.CSSStyleDeclaration" />

</asset>

<asset id="__Packages.mx.skins.Border" src="mx.skins.Border.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.core.UIObject" />

</asset>

<asset id="__Packages.mx.skins.RectBorder" src="mx.skins.RectBorder.asi" modified="1062582564">

    <exportAfter id="__Packages.mx.skins.Border" />

</asset>

<asset id="__Packages.mx.skins.halo.ButtonSkin" src="mx.skins.halo.ButtonSkin.asi" modified="1062582563">

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

    <exportAfter id="__Packages.mx.skins.RectBorder" />

</asset>

<asset id="__Packages.mx.skins.halo.RectBorder" src="mx.skins.halo.RectBorder.asi" modified="1062582564">

    <include id="__Packages.mx.styles.CSSStyleDeclaration" />

    <exportAfter id="__Packages.mx.core.ext.UIObjectExtensions" />

    <exportAfter id="__Packages.mx.skins.RectBorder" />

</asset>

</component>

</componentPackage>

Media 1ÿþÿBitmap 1ÿþÿ
Button.png·Ô±C·Ô±Cÿþÿÿþÿÿþÿÿþÿÿþÿÿÿÿÿ2Hxií’Ñ	@!EÛéíäNw'w*¯ øQa}Æ$K=™ÙÚÛÒEäFsW<_µ,)�œCQj>˜QYÅ§œïZqªuDÜŠSyK0þzöÏÏúÀÏÃ_Y?AžŽ÷7šÆðIsQŸ$ÅÿþÿButtonÐ¸ÿþÿButtonÿþÿ
Button.swf	ëW?+ÿþÿBorderÿþÿBorderÿþÿ
Button.swfèCP?ÿþÿUIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.Borderÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿBoundingBoxÿþÿBoundingBoxÿþÿ
Button.swfwÒÛ>ÿþÿÿþÿÿþÿBrdrBlkÿþÿBrdrBlkÿþÿ
Button.swfaÀ>ÿþÿÿþÿÿþÿBrdrFaceÿþÿBrdrFaceÿþÿ
Button.swfõ²°>ÿþÿÿþÿÿþÿ
BrdrHilghtÿþÿ
BrdrHilghtÿþÿ
Button.swf\À>ÿþÿÿþÿÿþÿBrdrShdwÿþÿBrdrShdwÿþÿ
Button.swfA?ÿþÿÿþÿÿþÿ
ButtonSkinÿþÿ
ButtonSkinÿþÿ
Button.swfýCP?ÿþÿ#__Packages.mx.skins.halo.ButtonSkinÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿDefaultsÿþÿDefaultsÿþÿ
Button.swf¿Eí>ÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿFocusManagerÿþÿFocusManagerÿþÿ
Button.swf
cí>ÿþÿ	FocusRectÿþÿ
Button.swfÿþÿÿþÿÿþÿUIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿ	FocusRectÿþÿ	FocusRectÿþÿ
Button.swf3cí>ÿþÿBoundingBoxÿþÿ
Button.swfÿþÿÿþÿÿþÿ"__Packages.mx.skins.halo.FocusRectÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿ
RectBorderÿþÿ
RectBorderÿþÿ
Button.swf÷CP?ÿþÿBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.skins.halo.RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonÿþÿSimpleButtonÿþÿ
Button.swf
cí>ÿþÿBoundingBoxÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonDownÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonInÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonUpÿþÿ
Button.swfÿþÿÿþÿÿþÿUIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonDownÿþÿSimpleButtonDownÿþÿ
Button.swf{DP?ÿþÿBrdrShdwÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonInÿþÿSimpleButtonInÿþÿ
Button.swf|DP?ÿþÿBrdrBlkÿþÿ
Button.swfÿþÿÿþÿÿþÿ
BrdrHilghtÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrShdwÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿSimpleButtonUpÿþÿSimpleButtonUpÿþÿ
Button.swf‚DP?ÿþÿBrdrBlkÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrShdwÿþÿ
Button.swfÿþÿÿþÿÿþÿ
BrdrHilghtÿþÿ
Button.swfÿþÿÿþÿÿþÿBrdrFaceÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIComponentÿþÿUIComponentÿþÿ
Button.swfì:?ÿþÿUIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿFocusManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿUIComponentExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIComponentExtensionsÿþÿUIComponentExtensionsÿþÿ
Button.swfÊ:?ÿþÿ,__Packages.mx.core.ext.UIComponentExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIObjectÿþÿUIObjectÿþÿ
Button.swf;?ÿþÿDefaultsÿþÿ
Button.swfÿþÿÿþÿÿþÿUIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿUIObjectExtensionsÿþÿUIObjectExtensionsÿþÿ
Button.swfî:?ÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿÿþÿÿþÿ__Packages.mx.controls.Buttonÿþÿ__Packages.mx.controls.Buttonÿþÿ
Button.swfÊBE?ÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.controls.Buttonÿþÿÿqimport mx.core.UIObject;

import mx.controls.SimpleButton;

import mx.core.UIComponent;



[Event("click")] 

[TagName("Button")] 

[IconFile("Button.png")] 

intrinsic class mx.controls.Button extends mx.controls.SimpleButton

{

   public function Button();

   public var __get__icon:Function;

   public var __get__label:Function;

   public var __get__labelPlacement:Function;

   public var __label:String;

   public var __labelPlacement:String;

   public var _color;

   public function _getIcon(Void):String;

   public var _iconLinkageName:String;

   [Bindable] [ChangeEvent("click")] public var _inherited_selected:Boolean;

   public function _setIcon(linkage):Void;

   public var borderW:Number;

   public var btnOffset:Number;

   public function calcSize(tag:Number, ref:Object):Void;

   public var centerContent:Boolean;

   public var className:String;

   public var clipParameters:Object;

   public function createChildren(Void):Void;

   public function draw();

   public var falseDisabledIcon:String;

   public var falseDisabledSkin:String;

   public var falseDownIcon:String;

   public var falseDownSkin:String;

   public var falseOverIcon:String;

   public var falseOverSkin:String;

   public var falseUpIcon:String;

   public var falseUpSkin:String;

   public function getBtnOffset(Void):Number;

   public function getLabel(Void):String;

   public function getLabelPlacement(Void):String;

   public var hitArea_mc:MovieClip;

   function get icon():String;

   [Inspectable(defaultValue="")] function set icon(linkage);

   public function init(Void):Void;

   public var initIcon;

   public function invalidateStyle(c:String):Void;

   [Inspectable(defaultValue="Button")] function set label(lbl:String);

   function get label():String;

   public var labelPath:Object;

   [Inspectable(enumeration="left,right,top,bottom"defaultValue="right")] function set labelPlacement(val:String);

   function get labelPlacement():String;

   static var mergedClipParameters:Boolean;

   public function onRelease(Void):Void;

   public function setColor(c:Number):Void;

   public function setEnabled(enable:Boolean):Void;

   public function setHitArea(w:Number, h:Number);

   public function setLabel(label:String):Void;

   public function setLabelPlacement(val:String):Void;

   public function setSkin(tag:Number, linkageName:String, initobj:Object):MovieClip;

   public function setView(offset:Number):Void;

   public function size(Void):Void;

   static var symbolName:String;

   static var symbolOwner;

   public var trueDisabledIcon:String;

   public var trueDisabledSkin:String;

   public var trueDownIcon:String;

   public var trueDownSkin:String;

   public var trueOverIcon:String;

   public var trueOverSkin:String;

   public var trueUpIcon:String;

   public var trueUpSkin:String;

   static var version:String;

   public function viewSkin(varName:String):Void;

};

ÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfËBE?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.controls.SimpleButtonÿþÿÿimport mx.core.UIComponent;



[Event("click")] 

[TagName("SimpleButton")] 

intrinsic class mx.controls.SimpleButton extends mx.core.UIComponent

{

   public function SimpleButton();

   public var __emphasized:Boolean;

   public var __emphatic:Boolean;

   public var __emphaticStyleName:String;

   public var __get__emphasized:Function;

   public var __get__selected:Function;

   public var __get__toggle:Function;

   public var __get__value:Function;

   public var __state:Boolean;

   public var __toggle:Boolean;

   public var autoRepeat:Boolean;

   public var boundingBox_mc:MovieClip;

   public var btnOffset:Number;

   public var buttonDownHandler:Function;

   public function calcSize(Void):Void;

   public function changeIcon(tag:Number, linkageName:String):Void;

   public function changeSkin(tag:Number, linkageName:String):Void;

   public var className:String;

   public var clickHandler:Function;

   public function createChildren(Void):Void;

   public var detail:Number;

   public var dfi;

   public var dfs;

   public var disabledIcon:Object;

   public var disabledSkin:Object;

   public var downIcon:Object;

   public var downSkin:Object;

   public function draw(Void):Void;

   public var dti;

   public var dts;

   function get emphasized():Boolean;

   function set emphasized(val:Boolean);

   static var emphasizedStyleDeclaration;

   static var falseDisabled:Number;

   public var falseDisabledIcon:String;

   public var falseDisabledIconEmphasized:String;

   public var falseDisabledSkin:String;

   public var falseDisabledSkinEmphasized:String;

   static var falseDown:Number;

   public var falseDownIcon:String;

   public var falseDownIconEmphasized:String;

   public var falseDownSkin:String;

   public var falseDownSkinEmphasized:String;

   static var falseOver:Number;

   public var falseOverIcon:String;

   public var falseOverIconEmphasized:String;

   public var falseOverSkin:String;

   public var falseOverSkinEmphasized:String;

   static var falseUp:Number;

   public var falseUpIcon:String;

   public var falseUpIconEmphasized:String;

   public var falseUpSkin:String;

   public var falseUpSkinEmphasized:String;

   public var fdi;

   public var fds;

   public var fri;

   public var frs;

   public var fui;

   public var fus;

   public function getLabel(Void):String;

   public function getSelected():Boolean;

   public function getState(Void):Boolean;

   public function getToggle(Void):Boolean;

   public var iconName:Object;

   public var idNames;

   public function init(Void):Void;

   public var initializing:Boolean;

   public var interval;

   public function keyDown(e:Object):Void;

   public function keyUp(e:Object):Void;

   public var linkLength:Number;

   public function onDragOut(Void):Void;

   public function onDragOver(Void):Void;

   public function onKillFocus(newFocus:Object):Void;

   public function onPress(Void):Void;

   public function onPressDelay(Void):Void;

   public function onPressRepeat(Void):Void;

   public function onRelease(Void):Void;

   public function onReleaseOutside(Void):Void;

   public function onRollOut(Void):Void;

   public function onRollOver(Void):Void;

   public var phase:String;

   public var preset:Boolean;

   public var refNames;

   public function refresh(Void):Void;

   public function removeIcons();

   public var rolloverIcon:Object;

   public var rolloverSkin:Object;

   function set selected(val:Boolean);

   [Inspectable(defaultValue=false)] function get selected():Boolean;

   public function setEnabled(val:Boolean):Void;

   public function setIcon(tag:Number, linkageName:String):Object;

   public function setLabel(val:String):Void;

   public function setSelected(val:Boolean);

   public function setSkin(tag:Number, linkageName:String, initobj:Object):MovieClip;

   public function setState(state:Boolean):Void;

   public function setStateVar(state:Boolean):Void;

   public function setToggle(val:Boolean);

   public function setView(offset:Boolean):Void;

   public function showEmphasized(e:Boolean):Void;

   public function size(Void):Void;

   public var skinName:Object;

   public var stateNames;

   public var style3dInset:Number;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tagMap;

   public var tdi;

   public var tds;

   function set toggle(val:Boolean);

   [Inspectable(defaultValue=false)] function get toggle():Boolean;

   public var tri;

   public var trs;

   static var trueDisabled:Number;

   public var trueDisabledIcon:String;

   public var trueDisabledIconEmphasized:String;

   public var trueDisabledSkin:String;

   public var trueDisabledSkinEmphasized:String;

   static var trueDown:Number;

   public var trueDownIcon:String;

   public var trueDownIconEmphasized:String;

   public var trueDownSkin:String;

   public var trueDownSkinEmphasized:String;

   static var trueOver:Number;

   public var trueOverIcon:String;

   public var trueOverIconEmphasized:String;

   public var trueOverSkin:String;

   public var trueOverSkinEmphasized:String;

   static var trueUp:Number;

   public var trueUpIcon:String;

   public var trueUpIconEmphasized:String;

   public var trueUpSkin:String;

   public var trueUpSkinEmphasized:String;

   public var tui;

   public var tus;

   public var upIcon:Object;

   public var upSkin:Object;

   function set value(val:Boolean);

   function get value():Boolean;

   static var version:String;

   public function viewIcon(varName:String):Void;

   public function viewSkin(varName:String, initObj:Object):Void;

};

ÿþÿ__Packages.mx.core.UIComponentÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.core.UIComponentÿþÿÿþimport mx.core.UIObject;

import mx.skins.SkinElement;



[Event("focusIn")] 

[Event("focusOut")] 

[Event("keyDown")] 

[Event("keyUp")] 

intrinsic class mx.core.UIComponent extends mx.core.UIObject

{

   public function UIComponent();

   public var clipParameters:Object;

   public function dispatchValueChangedEvent(value):Void;

   public var drawFocus:Function;

   [Inspectable(defaultValue=true, verbose=1, category="Other")] public var enabled:Boolean;

   public function enabledChanged(id:String, oldValue:Boolean, newValue:Boolean):Boolean;

   public function findFocusFromObject(o:Object):Object;

   public function findFocusInChildren(o:Object):Object;

   public var focusEnabled:Boolean;

   public var focusManager:MovieClip;

   public var focusTextField:Object;

   public function getFocus():Object;

   public function getFocusManager():Object;

   public var groupName:String;

   function get height():Number;

   public function init():Void;

   public function isParent(o:Object):Boolean;

   static var kStretch:Number;

   static var mergedClipParameters:Boolean;

   public function onKillFocus(newFocus:Object):Void;

   public function onSetFocus(oldFocus:Object):Void;

   public var origBorderStyles:Object;

   public var origBorderValues:Object;

   public var popUp:Boolean;

   public function pressFocus():Void;

   public function releaseFocus():Void;

   public function setEnabled(enabled:Boolean):Void;

   public function setFocus():Void;

   public function setVisible(x:Boolean, noEvent:Boolean):Void;

   public function size():Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tabEnabled:Boolean;

   public var tabIndex:Number;

   static var version:String;

   function get width():Number;

};

ÿþÿ__Packages.mx.core.UIObjectÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.core.UIObjectÿþÿÿÃimport mx.styles.StyleManager;

import mx.styles.CSSStyleDeclaration;

import mx.skins.SkinElement;



[Event("resize")] 

[Event("move")] 

[Event("draw")] 

[Event("load")] 

[Event("unload")] 

intrinsic class mx.core.UIObject extends MovieClip

{

   public function UIObject();

   public function __getTextFormat(tf:TextFormat, bAll:Boolean):Boolean;

   public var __get__minHeight:Function;

   public var __get__minWidth:Function;

   public var __get__scaleX:Function;

   public var __get__scaleY:Function;

   public var __get__visible:Function;

   public var __height:Number;

   private var __onUnload:Function;

   public var __width:Number;

   public var _color;

   public function _createChildren(Void):Void;

   private var _endInit:Function;

   public function _getTextFormat(Void):TextFormat;

   private var _id:String;

   private var _maxHeight:Number;

   private var _maxWidth:Number;

   private var _minHeight:Number;

   private var _minWidth:Number;

   private var _preferredHeight:Number;

   private var _preferredWidth:Number;

   private var _tf:TextFormat;

   public var _topmost:Boolean;

   public var addEventListener:Function;

   function get bottom():Number;

   public var buildDepthTable:Function;

   public function cancelAllDoLaters(Void):Void;

   public var changeColorStyleInChildren:Function;

   public var changeTextStyleInChildren:Function;

   public var childrenCreated:Boolean;

   public var className:String;

   public var clipParameters:Object;

   public var color:Number;

   public function constructObject(Void):Void;

   public var createAccessibilityImplementation:Function;

   public var createChildAtDepth:Function;

   public function createChildren(Void):Void;

   public var createClassChildAtDepth:Function;

   public function createClassObject(className:Function, id:String, depth:Number, initobj:Object):mx.core.UIObject;

   public function createEmptyObject(id:String, depth:Number):mx.core.UIObject;

   public var createEvent:Function;

   public function createLabel(name:String, depth:Number, text):TextField;

   public function createObject(linkageName:String, id:String, depth:Number, initobj:Object):MovieClip;

   public function createSkin(tag:Number):mx.core.UIObject;

   public function destroyObject(id:String):Void;

   public var dispatchEvent:Function;

   public function doLater(obj:Object, fn:String):Void;

   public function doLaterDispatcher(Void):Void;

   public function draw(Void):Void;

   public function drawRect(x1:Number, y1:Number, x2:Number, y2:Number):Void;

   public var embedFonts:Boolean;

   public var findNextAvailableDepth:Function;

   public var fontFamily:String;

   public var fontSize:Number;

   public var fontStyle:String;

   public var fontWeight:String;

   public function getClassStyleDeclaration(Void):mx.styles.CSSStyleDeclaration;

   public function getMinHeight(Void):Number;

   public function getMinWidth(Void):Number;

   public function getSkinIDName(tag:Number):String;

   public function getStyle(styleProp:String);

   public function getStyleName(Void):String;

   public var handleEvent:Function;

   function get height():Number;

   public var idNames:Array;

   public var ignoreClassStyleDeclaration:Object;

   public function init(Void):Void;

   public function initFromClipParameters(Void):Void;

   public var initProperties:Function;

   public function invalidate(Void):Void;

   private var invalidateFlag:Boolean;

   public function invalidateStyle(Void):Void;

   function get left():Number;

   private var lineColor:Number;

   private var lineWidth:Number;

   public var marginLeft:Number;

   public var marginRight:Number;

   static function mergeClipParameters(o, p):Boolean;

   public var methodTable:Array;

   [Inspectable(defaultValue=0, verbose=1, category="Size")] function get minHeight():Number;

   function set minHeight(h:Number):Void;

   [Inspectable(defaultValue=0, verbose=1, category="Size")] function get minWidth():Number;

   function set minWidth(w:Number):Void;

   public function move(x:Number, y:Number, noEvent:Boolean):Void;

   public var notifyStyleChangeInChildren:Function;

   public function redraw(bAlways:Boolean):Void;

   public var removeEventListener:Function;

   function get right():Number;

   function get scaleX():Number;

   function set scaleX(x:Number):Void;

   function get scaleY():Number;

   function set scaleY(y:Number):Void;

   public function setColor(color:Number):Void;

   public function setMinHeight(h:Number):Void;

   public function setMinWidth(w:Number):Void;

   public function setSize(w:Number, h:Number, noEvent:Boolean):Void;

   public function setSkin(tag:Number, linkageName:String, initObj:Object):MovieClip;

   public var setStyle:Function;

   public function setVisible(x:Boolean, noEvent:Boolean):Void;

   public function size(Void):Void;

   public var styleName:String;

   public var stylecache:Object;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tabEnabled:Boolean;

   public var textAlign:String;

   static var textColorList;

   public var textDecoration:String;

   public var textIndent:Number;

   private var tfList:Object;

   function get top():Number;

   public var validateNow:Boolean;

   static var version:String;

   [Inspectable(defaultValue=true, verbose=1, category="Other")] function get visible():Boolean;

   function set visible(x:Boolean):Void;

   function get width():Number;

   function get x():Number;

   function get y():Number;

};

ÿþÿ,__Packages.mx.core.ext.UIComponentExtensionsÿþÿ,__Packages.mx.core.ext.UIComponentExtensionsÿþÿ
Button.swf#¹U?ÿþÿ __Packages.mx.styles.CSSSetStyleÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.managers.OverlappedWindowsÿþÿ
Button.swfÿþÿÿþÿÿþÿ!mx.core.ext.UIComponentExtensionsÿþÿÿ:import mx.core.UIComponent;



intrinsic class mx.core.ext.UIComponentExtensions

{

   static function Extensions():Boolean;

   static var FocusManagerDependency;

   static var OverlappedWindowsDependency;

   static var UIComponentDependency;

   static var UIComponentExtended;

   static var bExtended;

};

ÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swf#¹U?ÿþÿ&__Packages.mx.skins.ColoredSkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ
Button.swfÿþÿÿþÿÿþÿ&__Packages.mx.events.UIEventDispatcherÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.core.ext.UIObjectExtensionsÿþÿÿûimport mx.core.UIObject;

import mx.styles.CSSStyleDeclaration;

import mx.skins.SkinElement;

import mx.events.UIEventDispatcher;



intrinsic class mx.core.ext.UIObjectExtensions

{

   static var CSSTextStylesDependency;

   static function Extensions():Boolean;

   static var SkinElementDependency;

   static var UIEventDispatcherDependency;

   static var UIObjectDependency;

   static var UIObjectExtended;

   static function addGeometry(tf:Object, ui:Object):Void;

   static var bExtended;

};

ÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ
Button.swf#¹U?ÿþÿmx.events.EventDispatcherÿþÿÿ

intrinsic class mx.events.EventDispatcher

{

   static var _fEventDispatcher:mx.events.EventDispatcher;

   static function _removeEventListener(queue:Object, event:String, handler):Void;

   public function addEventListener(event:String, handler):Void;

   public function dispatchEvent(eventObj:Object):Void;

   public function dispatchQueue(queueObj:Object, eventObj:Object):Void;

   static function initialize(object:Object):Void;

   public function removeEventListener(event:String, handler):Void;

};

ÿþÿ&__Packages.mx.events.UIEventDispatcherÿþÿ&__Packages.mx.events.UIEventDispatcherÿþÿ
Button.swf#¹U?ÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.events.UIEventDispatcherÿþÿÿimport mx.core.UIObject;

import mx.events.EventDispatcher;



intrinsic class mx.events.UIEventDispatcher extends mx.events.EventDispatcher

{

   public function __addEventListener(event:String, handler):Void;

   public var __origAddEventListener:Function;

   public var __sentLoadEvent;

   static var _fEventDispatcher:mx.events.UIEventDispatcher;

   static function addKeyEvents(obj:Object):Void;

   static function addLoadEvents(obj:Object):Void;

   public function dispatchEvent(eventObj:Object):Void;

   static function initialize(obj:Object):Void;

   static var keyEvents:Object;

   static var loadEvents:Object;

   static var lowLevelEvents:Object;

   public function onKeyDown(Void):Void;

   public function onKeyUp(Void):Void;

   public function onLoad(Void):Void;

   public function onUnload(Void):Void;

   public var owner:Object;

   public function removeEventListener(event:String, handler):Void;

   static function removeKeyEvents(obj:Object):Void;

   static function removeLoadEvents(obj:Object):Void;

};

ÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.DepthManagerÿþÿÿoimport mx.core.UIObject;



intrinsic class mx.managers.DepthManager

{

   public function DepthManager();

   static var __depthManager:mx.managers.DepthManager;

   public var _childCounter:Number;

   public var _parent:MovieClip;

   public var _topmost:Boolean;

   public function buildDepthTable(Void):Array;

   public function createChildAtDepth(linkageName:String, depthFlag:Number, initObj:Object):MovieClip;

   public function createClassChildAtDepth(className:Function, depthFlag:Number, initObj:Object):mx.ýÿÿÿ	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿcore.UIObject;

   public var createClassObject:Function;

   static function createClassObjectAtDepth(className:Object, depthSpace:Number, initObj:Object):mx.core.UIObject;

   public var createObject:Function;

   static function createObjectAtDepth(linkageName:String, depthSpace:Number, initObj:Object):MovieClip;

   public function findNextAvailableDepth(targetDepth:Number, depthTable:Array, direction:String):Number;

   public var getDepth:Function;

   public function getDepthByFlag(depthFlag:Number, depthTable:Array):Number;

   static var highestDepth:Number;

   static private var holder:MovieClip;

   static var kBottom:Number;

   static var kCursor:Number;

   static var kNotopmost:Number;

   static var kTooltip:Number;

   static var kTop:Number;

   static var kTopmost:Number;

   static var lowestDepth:Number;

   static var numberOfAuthortimeLayers:Number;

   static var reservedDepth:Number;

   public function setDepthAbove(targetInstance:MovieClip):Void;

   public function setDepthBelow(targetInstance:MovieClip):Void;

   public function setDepthTo(depthFlag:Number):Void;

   public function shuffleDepths(subject:MovieClip, targetDepth:Number, depthTable:Array, direction:String):Void;

   static function sortFunction(a:MovieClip, b:MovieClip):Number;

   public var swapDepths:Function;

   static function test(depth:Number):Boolean;

};

ÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ#__Packages.mx.managers.FocusManagerÿþÿ
Button.swf	ëW?ÿþÿ#__Packages.mx.controls.SimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.FocusManagerÿþÿÿêimport mx.core.UIObject;

import mx.managers.SystemManager;

import mx.controls.SimpleButton;

import mx.core.UIComponent;



intrinsic class mx.managers.FocusManager extends mx.core.UIComponent

{

   public function FocusManager();

   static var UIObjectExtensionsDependency;

   public var __defaultPushButton:mx.controls.SimpleButton;

   public var __get__defaultPushButton:Function;

   private var _firstNode:Object;

   private var _firstObj:Object;

   private var _foundList:Object;

   private var _lastNode:Object;

   private var _lastObj:Object;

   private var _lastTarget:Object;

   private var _lastx:Object;

   private var _needPrev:Boolean;

   private var _nextIsNext:Boolean;

   private var _nextNode:Object;

   private var _nextObj:Object;

   public function _onMouseDown(Void):Void;

   private var _prevNode:Object;

   private var _prevObj:Object;

   private var _searchKey:Number;

   public function activate(Void):Void;

   private var activated:Boolean;

   public var bDrawFocus:Boolean;

   public var bNeedFocus:Boolean;

   public var className:String;

   public function deactivate(Void):Void;

   public var defPushButton:mx.controls.SimpleButton;

   function get defaultPushButton():mx.controls.SimpleButton;

   function set defaultPushButton(x:mx.controls.SimpleButton);

   public var defaultPushButtonEnabled:Boolean;

   static function enableFocusManagement():Void;

   public function enabledChanged(id:String, oldValue:Boolean, newValue:Boolean):Boolean;

   public var form;

   public function getActualFocus(o:Object):Object;

   public function getFocus(Void):Object;

   public function getFocusManagerFromObject(o:Object):Object;

   public function getMaxTabIndex(o:mx.core.UIComponent):Number;

   public function getMousedComponentFromChildren(x:Number, y:Number, o:Object):Object;

   public function getNextTabIndex(Void):Number;

   public function getSelectionFocus():Object;

   public function getTabCandidate(o:MovieClip, index:Number, groupName:String, dir:Boolean, firstChild:Boolean):Void;

   public function getTabCandidateFromChildren(o:MovieClip, index:Number, groupName:String, dir:Boolean, firstChild:Boolean):Void;

   public function handleEvent(e:Object);

   public function init(Void):Void;

   static var initialized:Boolean;

   public function isOurFocus(o:Object):Boolean;

   public var lastFocus:Object;

   public var lastSelFocus:Object;

   public var lastTabFocus:Object;

   public var lastXMouse:Number;

   public var lastYMouse:Number;

   public function mouseActivate(Void):Void;

   function get nextTabIndex():Number;

   public function onKeyDown(Void):Void;

   public function onMouseUp(Void):Void;

   public function onSetFocus(o:Object, n:Object):Void;

   public function onUnload(Void):Void;

   public function relocate(Void):Void;

   public function restoreFocus(Void):Void;

   public function sendDefaultPushButtonEvent(Void):Void;

   public function setFocus(o:Object):Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   private var tabCapture:MovieClip;

   public function tabHandler(Void):Void;

   static var version:String;

   public function walkTree(p:MovieClip, index:Number, groupName:String, dir:Boolean, lookup:Boolean, firstChild:Boolean):Void;

};

ÿþÿ(__Packages.mx.managers.OverlappedWindowsÿþÿ(__Packages.mx.managers.OverlappedWindowsÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.OverlappedWindowsÿþÿÿ(import mx.managers.SystemManager;

import mx.core.UIComponent;



intrinsic class mx.managers.OverlappedWindows

{

   static var SystemManagerDependency;

   static function __addEventListener(e:String, o:Object, l:Function):Void;

   static function __removeEventListener(e:String, o:Object, l:Function):Void;

   static function activate(f:MovieClip):Void;

   static function addFocusManager(f:mx.core.UIComponent):Void;

   static function checkIdle(Void):Void;

   static function deactivate(f:MovieClip):Void;

   static function enableOverlappedWindows():Void;

   static var initialized:Boolean;

   static function onMouseDown(Void):Void;

   static function onMouseMove(Void):Void;

   static function onMouseUp(Void):Void;

   static function removeFocusManager(f:mx.core.UIComponent):Void;

};

ÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ$__Packages.mx.managers.SystemManagerÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ$__Packages.mx.events.EventDispatcherÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.managers.SystemManagerÿþÿÿ�import mx.events.EventDispatcher;

import mx.core.UIComponent;



[Event("idle")] 

[Event("resize")] 

intrinsic class mx.managers.SystemManager

{

   static var __addEventListener:Function;

   static var __removeEventListener:Function;

   static var __screen:Object;

   static private var _initialized:Boolean;

   static var _xAddEventListener:Function;

   static var _xRemoveEventListener:Function;

   static var activate:Function;

   static var addEventListener:Function;

   static function addFocusManager(f:mx.core.UIComponent):Void;

   static var checkIdle:Function;

   static var deactivate:Function;

   static var dispatchEvent:Function;

   static var form:MovieClip;

   static var forms:Array;

   static var idleFrames:Number;

   static function init(Void):Void;

   static var interval:Number;

   static var isMouseDown;

   static function onMouseDown(Void):Void;

   static var onMouseMove:Function;

   static var onMouseUp:Function;

   static function onResize(Void):Void;

   static var removeEventListener:Function;

   static function removeFocusManager(f:mx.core.UIComponent):Void;

   static function get screen():Object;

};

ÿþÿ__Packages.mx.skins.Borderÿþÿ__Packages.mx.skins.Borderÿþÿ
Button.swf#¹U?ÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.Borderÿþÿÿhimport mx.core.UIObject;



intrinsic class mx.skins.Border extends mx.core.UIObject

{

   public function Border();

   public var borderStyle:String;

   public var className:String;

   public var idNames:Array;

   public function init(Void):Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   public var tagBorder:Number;

};

ÿþÿ&__Packages.mx.skins.ColoredSkinElementÿþÿ&__Packages.mx.skins.ColoredSkinElementÿþÿ
Button.swf#¹U?ÿþÿmx.skins.ColoredSkinElementÿþÿÿ�

intrinsic class mx.skins.ColoredSkinElement

{

   public var _color;

   public function draw(Void):Void;

   public var getStyle:Function;

   public function invalidateStyle(Void):Void;

   static var mixins:mx.skins.ColoredSkinElement;

   public var onEnterFrame:Function;

   public function setColor(c:Number):Void;

   static function setColorStyle(p:Object, colorStyle:String):Void;

};

ÿþÿ__Packages.mx.skins.RectBorderÿþÿ__Packages.mx.skins.RectBorderÿþÿ
Button.swf$¹U?ÿþÿ__Packages.mx.skins.Borderÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.RectBorderÿþÿÿÅimport mx.skins.Border;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.skins.RectBorder extends mx.skins.Border

{

   public function RectBorder();

   public var __borderMetrics:Object;

   public var backgroundColorName:String;

   public var borderColorName:String;

   function get borderMetrics():Object;

   public var borderStyleName:String;

   public var buttonColorName:String;

   public var className:String;

   public function draw(Void):Void;

   public function drawBorder(Void):Void;

   public function getBorderMetrics(Void):Object;

   function get height():Number;

   public var highlightColorName:String;

   public function init(Void):Void;

   public var offset:Number;

   public function setColor(Void):Void;

   public var shadowColorName:String;

   public function size(Void):Void;

   static var symbolName:String;

   static var symbolOwner:Object;

   static var version:String;

   function get width():Number;

};

ÿþÿ__Packages.mx.skins.SkinElementÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swf$¹U?ÿþÿmx.skins.SkinElementÿþÿÿ¥

intrinsic class mx.skins.SkinElement extends MovieClip

{

   public function __set__visible(visible:Boolean):Void;

   public var height:Number;

   public function move(x:Number, y:Number):Void;

   static function registerElement(name:String, className:Function):Void;

   public function setSize(w:Number, h:Number):Void;

   public var top:Number;

   public var visible:Boolean;

   public var width:Number;

};

ÿþÿ#__Packages.mx.skins.halo.ButtonSkinÿþÿ#__Packages.mx.skins.halo.ButtonSkinÿþÿ
Button.swf#¹U?ÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.ButtonSkinÿþÿÿimport mx.skins.RectBorder;

import mx.core.ext.UIObjectExtensions;

import mx.skins.SkinElement;



intrinsic class mx.skins.halo.ButtonSkin extends mx.skins.RectBorder

{

   public function ButtonSkin();

   static var UIObjectExtensionsDependency;

   public var backgroundColorName;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   public var className;

   public function drawHaloRect(w:Number, h:Number):Void;

   public var drawRoundRect:Function;

   public function init():Void;

   public function size():Void;

   static var symbolName:String;

   static var symbolOwner:Object;

};

ÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ
Button.swf$¹U?ÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIObjectÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.Defaultsÿþÿÿ·import mx.core.UIObject;

import mx.core.ext.UIObjectExtensions;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.skins.halo.Defaults

{

   static var CSSStyleDeclarationDependency;

   static var UIObjectDependency;

   static var UIObjectExtensionsDependency;

   public var beginFill:Function;

   public var beginGradientFill:Function;

   static function classConstruct():Boolean;

   static var classConstructed;

   public var curveTo:Function;

   public function drawRoundRect(x, y, w, h, r, c, alpha, rot, gradient, ratios);

   public var endFill:Function;

   public var lineTo:Function;

   public var moveTo:Function;

   static function setThemeDefaults():Void;

};

ÿþÿ"__Packages.mx.skins.halo.FocusRectÿþÿ"__Packages.mx.skins.halo.FocusRectÿþÿ
Button.swf$¹U?ÿþÿ#__Packages.mx.managers.DepthManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.core.UIComponentÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.SkinElementÿþÿ
Button.swfÿþÿÿþÿÿþÿ!__Packages.mx.skins.halo.Defaultsÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.FocusRectÿþÿÿÎimport mx.core.UIObject;

import mx.skins.halo.Defaults;

import mx.managers.DepthManager;

import mx.skins.SkinElement;

import mx.core.UIComponent;



intrinsic class mx.skins.halo.FocusRect extends mx.skins.SkinElement

{

   static var DefaultsDependency:mx.skins.halo.Defaults;

   public function FocusRect();

   static var UIComponentDependency:mx.core.UIComponent;

   public var boundingBox_mc:MovieClip;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   public function draw(o:Object):Void;

   public var drawRoundRect:Function;

   public function handleEvent(e:Object):Void;

   public function setSize(w:Number, h:Number, r, a:Number, rectCol:Number):Void;

};

ÿþÿ#__Packages.mx.skins.halo.RectBorderÿþÿ#__Packages.mx.skins.halo.RectBorderÿþÿ
Button.swf$¹U?ÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿ)__Packages.mx.core.ext.UIObjectExtensionsÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.skins.RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.skins.halo.RectBorderÿþÿÿoimport mx.core.ext.UIObjectExtensions;

import mx.skins.Border;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.skins.halo.RectBorder extends mx.skins.RectBorder

{

   public function RectBorder();

   static var UIObjectExtensionsDependency;

   public var borderCapColorName:String;

   private var borderWidths:Object;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   private var colorList:Object;

   public function draw3dBorder(c1:Number, c2:Number, c3:Number, c4:Number, c5:Number, c6:Number):Void;

   public function drawBorder(Void):Void;

   public var drawRoundRect:Function;

   public function getBorderMetrics(Void):Object;

   public function init(Void):Void;

   public var shadowCapColorName:String;

   static var symbolName:String;

   static var symbolOwner:Object;

   static var version:String;

};

ÿþÿ __Packages.mx.styles.CSSSetStyleÿþÿ __Packages.mx.styles.CSSSetStyleÿþÿ
Button.swf$¹U?ÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.styles.CSSSetStyleÿþÿÿbimport mx.styles.StyleManager;

import mx.styles.CSSStyleDeclaration;



intrinsic class mx.styles.CSSSetStyle

{

   static var CSSStyleDeclarationDependency;

   public var _color:Number;

   public function _setStyle(styleProp:String, newValue):Void;

   public function changeColorStyleInChildren(sheetName:String, colorStyle:String, newValue):Void;

   public function changeTextStyleInChildren(styleProp:String):Void;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   static function enableRunTimeCSS():Void;

   public var invalidateStyle:Function;

   public function notifyStyleChangeInChildren(sheetName:String, styleProp:String, newValue):Void;

   public var setColor:Function;

   public function setStyle(styleProp:String, newValue):Void;

   public var styleName:String;

   public var stylecache:Object;

};

ÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ(__Packages.mx.styles.CSSStyleDeclarationÿþÿ
Button.swf$¹U?ÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swfÿþÿÿþÿÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.styles.CSSStyleDeclarationÿþÿÿ%import mx.styles.StyleManager;

import mx.styles.CSSTextStyles;



intrinsic class mx.styles.CSSStyleDeclaration

{

   static var CSSTextStylesDependency;

   public function __getTextFormat(tf:TextFormat, bAll:Boolean):Boolean;

   public var _tf:TextFormat;

   static function classConstruct():Boolean;

   static var classConstructed:Boolean;

   public var color:Number;

   public var embedFonts:Boolean;

   public var fontFamily:String;

   public var fontSize:Number;

   public var fontStyle:String;

   public var fontWeight:String;

   public function getStyle(styleProp:String);

   public var marginLeft:Number;

   public var marginRight:Number;

   public var styleName:String;

   public var textAlign:String;

   public var textDecoration:String;

   public var textIndent:Number;

};

ÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ"__Packages.mx.styles.CSSTextStylesÿþÿ
Button.swf$¹U?ÿþÿmx.styles.CSSTextStylesÿþÿt

intrinsic class mx.styles.CSSTextStyles

{

   static function addTextStyles(o:Object, bColor:Boolean):Void;

};

ÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ!__Packages.mx.styles.StyleManagerÿþÿ
Button.swf$¹U?ÿþÿmx.styles.StyleManagerÿþÿÿµ

intrinsic class mx.styles.StyleManager

{

   static var TextFormatStyleProps:Object;

   static var TextStyleMap:Object;

   static var colorNames:Object;

   static var colorStyles:Object;

   static function getColorName(colorName:String):Number;

   static var inheritingStyles:Object;

   static function isColorName(colorName:String):Boolean;

   static function isColorStyle(styleName:String):Boolean;

   static function isInheritingStyle(styleName:String):Boolean;

   static function registerColorName(colorName:String, colorValue:Number):Void;

   static function registerColorStyle(styleName:String):Void;

   static function registerInheritingStyle(styleName:String):Void;

};

ÿþÿBoundingBoxÿþÿ
Button.swfÿþÿÿþÿÿþÿSimpleButtonÿþÿ
Button.swfÿþÿÿþÿÿþÿBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿ
RectBorderÿþÿ
Button.swfÿþÿÿþÿÿþÿ
ButtonSkinÿþÿ
Button.swfÿþÿÿþÿÿþÿ__Packages.mx.controls.Buttonÿþÿ
Button.swfÿþÿÿþÿÿþÿmx.controls.Buttonÿþÿÿqimport mx.core.UIObject;

import mx.controls.SimpleButton;

import mx.core.UIComponent;



[Event("click")] 

[TagName("Button")] 

[IconFile("Button.png")] 

intrinsic class mx.controls.Button extends mx.controls.SimpleButton

{

   public function Button();

   public var __get__icon:Function;

   public var __get__label:Function;

   public var __get__labelPlacement:Function;

   public var __label:String;

   public var __labelPlacement:String;

   public var _color;

   public function _getIcon(Void):String;

   public var _iconLinkageName:String;

   [Bindable] [ChangeEvent("click")] public var _inherited_selected:Boolean;

   public function _setIcon(linkage):Void;

   public var borderW:Number;

   public var btnOffset:Number;

   public function calcSize(tag:Number, ref:Object):Void;

   public var centerContent:Boolean;

   public var className:String;

   public var clipParameters:Object;

   public function createChildren(Void):Void;

   public function draw();

   public var falseDisabledIcon:String;

   public var falseDisabledSkin:String;

   public var falseDownIcon:String;

   public var falseDownSkin:String;

   public var falseOverIcon:String;

   public var falseOverSkin:String;

   public var falseUpIcon:String;

   public var falseUpSkin:String;

   public function getBtnOffset(Void):Number;

   public function getLabel(Void):String;

   public function getLabelPlacement(Void):String;

   public var hitArea_mc:MovieClip;

   function get icon():String;

   [Inspectable(defaultValue="")] function set icon(linkage);

   public function init(Void):Void;

   public var initIcon;

   public function invalidateStyle(c:String):Void;

   [Inspectable(defaultValue="Button")] function set label(lbl:String);

   function get label():String;

   public var labelPath:Object;

   [Inspectable(enumeration="left,right,top,bottom"defaultValue="right")] function set labelPlacement(val:String);

   function get labelPlacement():String;

   static var mergedClipParameters:Boolean;

   public function onRelease(Void):Void;

   public function setColor(c:Number):Void;

   public function setEnabled(enable:Boolean):Void;

   public function setHitArea(w:Number, h:Number);

   public function setLabel(label:String):Void;

   public function setLabelPlacement(val:String):Void;

   public function setSkin(tag:Number, linkageName:String, initobj:Object):MovieClip;

   public function setView(offset:Number):Void;

   public function size(Void):Void;

   static var symbolName:String;

   static var symbolOwner;

   public var trueDisabledIcon:String;

   public var trueDisabledSkin:String;

   public var trueDownIcon:String;

   public var trueDownSkin:String;

   public var trueOverIcon:String;

   public var trueOverSkin:String;

   public var trueUpIcon:String;

   public var trueUpSkin:String;

   static var version:String;

   public function viewSkin(varName:String):Void;

};

ÌÈ
h�hhhhÿÿÿÿÀÀÀÿ´ÿþÿPropSheet::ActiveTabÿþÿ7641”ÿþÿ!PublishGifProperties::PaletteNameÿþÿÿþÿ PublishRNWKProperties::speed256Kÿþÿ0ÿþÿ"PublishHtmlProperties::StartPausedÿþÿ0ÿþÿ%PublishFormatProperties::htmlFileNameÿþÿstorage_dialog.htmlÿþÿ PublishQTProperties::LayerOptionÿþÿÿþÿ PublishQTProperties::AlphaOptionÿþÿÿþÿ"PublishQTProperties::MatchMovieDimÿþÿ1ÿþÿVector::Debugging Permittedÿþÿ0ÿþÿPublishProfileProperties::nameÿþÿDefaultÿþÿPublishHtmlProperties::Loopÿþÿ1ÿþÿPublishFormatProperties::jpegÿþÿ0ÿþÿPublishQTProperties::Widthÿþÿ215ÿþÿ$PublishPNGProperties::OptimizeColorsÿþÿ1ÿþÿ&PublishRNWKProperties::speedSingleISDNÿþÿ0ÿþÿ&PublishRNWKProperties::singleRateAudioÿþÿ0ÿþÿVector::External Playerÿþÿÿþÿ%PublishHtmlProperties::showTagWarnMsgÿþÿ1ÿþÿPublishHtmlProperties::Unitsÿþÿ0ÿþÿ4PublishHtmlProperties::UsingDefaultAlternateFilenameÿþÿ1ÿþÿPublishGifProperties::Smoothÿþÿ1ÿþÿ%PublishRNWKProperties::mediaCopyrightÿþÿ(c) 2000ÿþÿ#PublishRNWKProperties::flashBitRateÿþÿ1200ÿþÿVector::Compress Movieÿþÿ1ÿþÿVector::Package Pathsÿþÿÿþÿ&PublishFormatProperties::flashFileNameÿþÿ..\..\storage_dialog.swfÿþÿ'PublishFormatProperties::gifDefaultNameÿþÿ1ÿþÿ%PublishFormatProperties::projectorMacÿþÿ0ÿþÿ"PublishGifProperties::DitherOptionÿþÿÿþÿ!PublishRNWKProperties::exportSMILÿþÿ1ÿþÿ PublishRNWKProperties::speed384Kÿþÿ0ÿþÿ"PublishRNWKProperties::exportAudioÿþÿ1ÿþÿVector::FireFoxÿþÿ0ÿþÿPublishHtmlProperties::Qualityÿþÿ4ÿþÿ(PublishHtmlProperties::VerticalAlignmentÿþÿ1ÿþÿ$PublishFormatProperties::pngFileNameÿþÿstorage_dialog.pngÿþÿPublishFormatProperties::htmlÿþÿ0ÿþÿ"PublishPNGProperties::FilterOptionÿþÿÿþÿ'PublishRNWKProperties::mediaDescriptionÿþÿÿþÿVector::Override Soundsÿþÿ0ÿþÿ!PublishHtmlProperties::DeviceFontÿþÿ0ÿþÿ-PublishFormatProperties::generatorDefaultNameÿþÿ1ÿþÿPublishQTProperties::Flattenÿþÿ1ÿþÿPublishPNGProperties::BitDepthÿþÿ24-bit with AlphaÿþÿPublishPNGProperties::Smoothÿþÿ1ÿþÿ"PublishGifProperties::DitherSolidsÿþÿ0ÿþÿPublishGifProperties::Interlaceÿþÿ0ÿþÿPublishJpegProperties::DPIÿþÿ4718592ÿþÿVector::Qualityÿþÿ80ÿþÿVector::Protectÿþÿ0ÿþÿ"PublishHtmlProperties::DisplayMenuÿþÿ1ÿþÿ*PublishHtmlProperties::HorizontalAlignmentÿþÿ1ÿþÿ2PublishHtmlProperties::VersionDetectionIfAvailableÿþÿ0ÿþÿVector::Templateÿþÿ0ÿþÿ*PublishFormatProperties::generatorFileNameÿþÿstorage_dialog.swtÿþÿ(PublishFormatProperties::rnwkDefaultNameÿþÿ1ÿþÿ(PublishFormatProperties::jpegDefaultNameÿþÿ1ÿþÿPublishFormatProperties::gifÿþÿ0ÿþÿPublishGifProperties::Loopÿþÿ1ÿþÿPublishGifProperties::Widthÿþÿ215ÿþÿ$PublishRNWKProperties::mediaKeywordsÿþÿÿþÿ!PublishRNWKProperties::mediaTitleÿþÿÿþÿPublishRNWKProperties::speed28Kÿþÿ1ÿþÿ#PublishFormatProperties::qtFileNameÿþÿstorage_dialog.movÿþÿ"PublishPNGProperties::DitherOptionÿþÿÿþÿ#PublishGifProperties::PaletteOptionÿþÿÿþÿ#PublishGifProperties::MatchMovieDimÿþÿ1ÿþÿ$PublishRNWKProperties::speedDualISDNÿþÿ0ÿþÿ$PublishRNWKProperties::realVideoRateÿþÿ100000ÿþÿPublishJpegProperties::Qualityÿþÿ80ÿþÿPublishFormatProperties::flashÿþÿ1ÿþÿ#PublishPNGProperties::PaletteOptionÿþÿÿþÿ#PublishPNGProperties::MatchMovieDimÿþÿ1ÿþÿ$PublishJpegProperties::MatchMovieDimÿþÿ1ÿþÿVector::Package Export Frameÿþÿ1ÿþÿ!PublishProfileProperties::versionÿþÿ1ÿþÿPublishHtmlProperties::Alignÿþÿ0ÿþÿ-PublishFormatProperties::projectorWinFileNameÿþÿstorage_dialog.exeÿþÿ'PublishFormatProperties::pngDefaultNameÿþÿ1ÿþÿ0PublishFormatProperties::projectorMacDefaultNameÿþÿ1ÿþÿ#PublishQTProperties::PlayEveryFrameÿþÿ0ÿþÿ"PublishPNGProperties::DitherSolidsÿþÿ0ÿþÿ"PublishJpegProperties::Progressiveÿþÿ0ÿþÿVector::Debugging PasswordÿþÿÿþÿVector::Omit Trace Actionsÿþÿ0ÿþÿPublishHtmlProperties::Heightÿþÿ138ÿþÿPublishHtmlProperties::Widthÿþÿ215ÿþÿ%PublishFormatProperties::jpegFileNameÿþÿstorage_dialog.jpgÿþÿ)PublishFormatProperties::flashDefaultNameÿþÿ0ÿþÿPublishPNGProperties::Interlaceÿþÿ0ÿþÿPublishGifProperties::Heightÿþÿ138ÿþÿPublishJpegProperties::Sizeÿþÿ0ÿþÿVector::DeviceSoundÿþÿ0ÿþÿVector::TopDownÿþÿ0ÿþÿ'PublishHtmlProperties::TemplateFileNameÿþÿ�C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Html\Default.htmlÿþÿ!PublishHtmlProperties::WindowModeÿþÿ0ÿþÿ2PublishHtmlProperties::UsingDefaultContentFilenameÿþÿ1ÿþÿ-PublishFormatProperties::projectorMacFileNameÿþÿstorage_dialog.hqxÿþÿ(PublishFormatProperties::htmlDefaultNameÿþÿ1ÿþÿPublishFormatProperties::rnwkÿþÿ0ÿþÿPublishFormatProperties::pngÿþÿ0ÿþÿPublishQTProperties::Heightÿþÿ138ÿþÿ%PublishPNGProperties::RemoveGradientsÿþÿ0ÿþÿPublishGifProperties::MaxColorsÿþÿ255ÿþÿ'PublishGifProperties::TransparentOptionÿþÿÿþÿPublishGifProperties::LoopCountÿþÿÿþÿPublishRNWKProperties::speed56Kÿþÿ1ÿþÿVector::Reportÿþÿ0ÿþÿ+PublishHtmlProperties::OwnAlternateFilenameÿþÿÿþÿ(PublishHtmlProperties::AlternateFilenameÿþÿÿþÿ&PublishHtmlProperties::ContentFilenameÿþÿÿþÿ"PublishFormatProperties::generatorÿþÿ0ÿþÿ$PublishGifProperties::OptimizeColorsÿþÿ1ÿþÿ"PublishRNWKProperties::audioFormatÿþÿ0ÿþÿVector::Versionÿþÿ7ÿþÿVector::Event Formatÿþÿ0ÿþÿVector::Stream Compressÿþÿ7ÿþÿPublishFormatProperties::qtÿþÿ0ÿþÿPublishPNGProperties::Heightÿþÿ138ÿþÿPublishPNGProperties::Widthÿþÿ215ÿþÿ%PublishGifProperties::RemoveGradientsÿþÿ0ÿþÿ PublishRNWKProperties::speed512Kÿþÿ0ÿþÿPublishJpegProperties::Heightÿþÿ138ÿþÿVector::ActionScriptVersionÿþÿ2ÿþÿVector::Event Compressÿþÿ7ÿþÿPublishHtmlProperties::Scaleÿþÿ0ÿþÿ0PublishFormatProperties::projectorWinDefaultNameÿþÿ1ÿþÿPublishQTProperties::Loopingÿþÿ0ÿþÿ*PublishQTProperties::UseQTSoundCompressionÿþÿ0ÿþÿ!PublishPNGProperties::PaletteNameÿþÿÿþÿ!PublishPNGProperties::Transparentÿþÿ0ÿþÿ&PublishGifProperties::TransparentAlphaÿþÿ128ÿþÿPublishGifProperties::Animatedÿþÿ0ÿþÿ"PublishRNWKProperties::mediaAuthorÿþÿÿþÿ(PublishRNWKProperties::speedCorporateLANÿþÿ0ÿþÿ&PublishRNWKProperties::showBitrateDlogÿþÿ1ÿþÿ"PublishRNWKProperties::exportFlashÿþÿ1ÿþÿPublishJpegProperties::Widthÿþÿ215ÿþÿVector::Stream Formatÿþÿ0ÿþÿ"PublishHtmlProperties::VersionInfoÿþÿÿþÿ$PublishFormatProperties::gifFileNameÿþÿstorage_dialog.gifÿþÿ&PublishFormatProperties::qtDefaultNameÿþÿ1ÿþÿ"PublishQTProperties::PausedAtStartÿþÿ0ÿþÿ%PublishQTProperties::ControllerOptionÿþÿ0ÿþÿPublishPNGProperties::MaxColorsÿþÿ255ÿþÿ,PublishHtmlProperties::UsingOwnAlternateFileÿþÿ0ÿþÿ%PublishFormatProperties::rnwkFileNameÿþÿstorage_dialog.smilÿþÿ%PublishFormatProperties::projectorWinÿþÿ0ÿþÿ%PublishFormatProperties::defaultNamesÿþÿ0ÿÿÿÿÿþÿÿþÿüÿÿ	CColorDefÿ€ÿ€ÿ€3ÿPï€fÿPï0€™ÿPïH€ÌÿPï`€ÿÿPïx€3ÿï€33ÿ(ï€3fÿ<ï0€3™ÿCïH€3ÌÿFï`€3ÿÿHïx€fÿï0€f3ÿï0€ffÿ(ï0€f™ÿ5ïH€fÌÿ<ï`€fÿÿ@ïx€ÿ€333ÿ0€ÿ€3ÿ ï€33ÿxï€f3ÿdï0€™3ÿ]ïH€Ì3ÿZï`€ÿ3ÿXïx€33ÿÈï€333ÿ0€3f3ÿPPH€3™3ÿPx`€3Ì3ÿP�x€3ÿ3ÿPï�€f3ÿÜï0€f33ÿPH€ff3ÿ(PH€f™3ÿ<x`€fÌ3ÿC�x€fÿ3ÿFï�€ÿ€fffÿ`€ÿ€fÿ ï0€3fÿŒï0€ffÿxï0€™fÿkïH€Ìfÿdï`€ÿfÿ`ïx€3fÿ´ï0€33fÿ PH€3ffÿxPH€3™fÿdx`€3Ìfÿ]�x€3ÿfÿZï�€ffÿÈï0€f3fÿÈPH€fffÿ`€f™fÿP0x€fÌfÿPx�€fÿfÿPï¨€ÿ€™™™ÿ�€ÿ€™ÿ ïH€3™ÿ“ïH€f™ÿ…ïH€™™ÿxïH€Ì™ÿnï`€ÿ™ÿhïx€3™ÿ­ïH€33™ÿ x`€3f™ÿŒx`€3™™ÿxx`€3Ì™ÿk�x€3ÿ™ÿdï�€f™ÿ»ïH€f3™ÿ´x`€ff™ÿ 0x€f™™ÿx0x€fÌ™ÿdx�€fÿ™ÿ]ï¨€ÿ€ÌÌÌÿÀ€ÿ€Ìÿ ï`€3Ìÿ–ï`€fÌÿŒï`€™Ìÿ‚ï`€ÌÌÿxï`€ÿÌÿpïx€3Ìÿªï`€33Ìÿ �x€3fÌÿ“�x€3™Ìÿ…�x€3ÌÌÿx�x€3ÿÌÿnï�€fÌÿ´ï`€f3Ìÿ­�x€ffÌÿ x�€f™ÌÿŒx�€fÌÌÿxx�€fÿÌÿkï¨€ÿ€ÿÿÿÿð€ÿ€ÿÿ ïx€3ÿÿ˜ïx€fÿÿ�ïx€™ÿÿˆïx€Ìÿÿ€ïx€ÿÿÿxïx€3ÿÿ¨ïx€33ÿÿ ï�€3fÿÿ–ï�€3™ÿÿŒï�€3Ìÿÿ‚ï�€3ÿÿÿxï�€fÿÿ°ïx€f3ÿÿªï�€ffÿÿ ï¨€f™ÿÿ“ï¨€fÌÿÿ…ï¨€fÿÿÿxï¨€ÿ€ÿÿïx€ÿ€™ÿïH€™3ÿ
ïH€™fÿïH€™™ÿ(ïH€™Ìÿ2ï`€™ÿÿ8ïx€Ìÿï`€Ì3ÿ
ï`€Ìfÿï`€Ì™ÿï`€ÌÌÿ(ï`€Ìÿÿ0ïx€ÿÿïx€ÿ3ÿïx€ÿfÿïx€ÿ™ÿïx€ÿÌÿ ïx€ÿÿÿ(ïx€ÿ€ÿÿPïx€ÿ€™3ÿãïH€™33ÿx`€™f3ÿx`€™™3ÿ(x`€™Ì3ÿ5�x€™ÿ3ÿ<ï�€Ì3ÿæï`€Ì33ÿ�x€Ìf3ÿ
�x€Ì™3ÿ�x€ÌÌ3ÿ(�x€Ìÿ3ÿ2ï�€ÿ3ÿèïx€ÿ33ÿï�€ÿf3ÿ
ï�€ÿ™3ÿï�€ÿÌ3ÿï�€ÿÿ3ÿ(ï�€ÿ€ÿÿ ïx€ÿ€™fÿÕïH€™3fÿÜx`€™ffÿ0x€™™fÿ(0x€™Ìfÿ<x�€™ÿfÿCï¨€ÌfÿÜï`€Ì3fÿã�x€Ìffÿx�€Ì™fÿx�€ÌÌfÿ(x�€Ìÿfÿ5ï¨€ÿfÿàïx€ÿ3fÿæï�€ÿffÿï¨€ÿ™fÿ
ï¨€ÿÌfÿï¨€ÿÿfÿ(ï¨€ÿ€ÿÿÿ(ïx€ÿ€™™ÿÈïH€™3™ÿÈx`€™f™ÿÈ0x€™™™ÿ�€™Ì™ÿPP¨€™ÿ™ÿPïÀ€Ì™ÿÒï`€Ì3™ÿÕ�x€Ìf™ÿÜx�€Ì™™ÿP¨€ÌÌ™ÿ(P¨€Ìÿ™ÿ<ïÀ€ÿ™ÿØïx€ÿ3™ÿÜï�€ÿf™ÿãï¨€ÿ™™ÿïÀ€ÿÌ™ÿïÀ€ÿÿ™ÿ(ïÀ€ÿ€ÿÿÿxïx€ÿ€™Ìÿ¾ï`€™3Ìÿ»�x€™fÌÿ´x�€™™Ìÿ P¨€™ÌÌÿxP¨€™ÿÌÿdïÀ€ÌÌÿÈï`€Ì3ÌÿÈ�x€ÌfÌÿÈx�€Ì™ÌÿÈP¨€ÌÌÌÿÀ€ÌÿÌÿPïØ€ÿÌÿÐïx€ÿ3ÌÿÒï�€ÿfÌÿÕï¨€ÿ™ÌÿÜïÀ€ÿÌÌÿïØ€ÿÿÌÿ(ïØ€ÿ€ÿÿÿÈïx€ÿ€™ÿÿ¸ïx€™3ÿÿ´ï�€™fÿÿ­ï¨€™™ÿÿ ïÀ€™ÌÿÿŒïÀ€™ÿÿÿxïÀ€ÌÿÿÀïx€Ì3ÿÿ¾ï�€Ìfÿÿ»ï¨€Ì™ÿÿ´ïÀ€ÌÌÿÿ ïØ€ÌÿÿÿxïØ€ÿÿÿÈïx€ÿ3ÿÿÈï�€ÿfÿÿÈï¨€ÿ™ÿÿÈïÀ€ÿÌÿÿÈïØ€ÿÿÿÿð€ÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿfýÿ`ÿÿÿÿzÿÿÿÿ€™fÿªÿÌÿÿÿÿÿÿ€ÿÿÿ*ÿÿÿ]ÿÿÿÿÿªÿÿÔÿÿÿÿÿÿÿþÿ"PublishQTProperties::QTSndSettingsÿÿCQTAudioSettingsÿÿÿþÿhÿþÿÿþÿ

ÿÿÿÿÿþÿÿþÿ8ÿþÿPublishJpegProperties::Sizeÿþÿ0ÿþÿVector::DeviceSoundÿþÿ0ÿþÿVector::TopDownÿþÿ0ÿþÿ'PublishHtmlProperties::TemplateFileNameÿþÿ�C:\Documents and Settings\bradneuberg\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Html\Default.htmlÿþÿ!PublishHtmlProperties::WindowModeÿþÿ0ÿþÿ2PublishHtmlProperties::UsingDefaultContentFilenameÿþÿ1ÿþÿ-PublishFormatProperties::projectorMacFileNameÿþÿstorage_dialog.hqxÿþÿ(PublishFormatProperties::htmlDefaultNameÿþÿ1ÿþÿPublishFormatProperties::rnwkÿþÿ0ÿþÿPublishFormatProperties::pngÿþÿ0ÿþÿPublishQTProperties::Heightÿþÿ138ÿþÿ%PublishPNGProperties::RemoveGradientsÿþÿ0ÿþÿPublishGifProperties::MaxColorsÿþÿ255ÿþÿ'PublishGifProperties::TransparentOptionÿþÿÿþÿPublishGifProperties::LoopCountÿþÿÿþÿPublishRNWKProperties::speed56Kÿþÿ1ÿþÿVector::Reportÿþÿ0ÿþÿ+PublishHtmlProperties::OwnAlternateFilenameÿþÿÿþÿ(PublishHtmlProperties::AlternateFilenameÿþÿÿþÿ&PublishHtmlProperties::ContentFilenameÿþÿÿþÿ"PublishFormatProperties::generatorÿþÿ0ÿþÿ$PublishGifProperties::OptimizeColorsÿþÿ1ÿþÿ"PublishRNWKProperties::audioFormatÿþÿ0ÿþÿVector::Versionÿþÿ7ÿþÿVector::Event Formatÿþÿ0ÿþÿVector::Stream Compressÿþÿ7ÿþÿPublishFormatProperties::qtÿþÿ0ÿþÿPublishPNGProperties::Heightÿþÿ138ÿþÿPublishPNGProperties::Widthÿþÿ215ÿþÿ%PublishGifProperties::RemoveGradientsÿþÿ0ÿþÿ PublishRNWKProperties::speed512Kÿþÿ0ÿþÿPublishJpegProperties::Heightÿþÿ138ÿþÿVector::ActionScriptVersionÿþÿ2ÿþÿVector::Event Compressÿþÿ7ÿþÿPublishHtmlProperties::Scaleÿþÿ0ÿþÿ0PublishFormatProperties::projectorWinDefaultNameÿþÿ1ÿþÿPublishQTProperties::Loopingÿþÿ0ÿþÿ*PublishQTProperties::UseQTSoundCompressionÿþÿ0ÿþÿ!PublishPNGProperties::PaletteNameÿþÿÿþÿ!PublishPNGProperties::Transparentÿþÿ0ÿþÿ&PublishGifProperties::TransparentAlphaÿþÿ128ÿþÿPublishGifProperties::Animatedÿþÿ0ÿþÿ"PublishRNWKProperties::mediaAuthorÿþÿÿþÿ(PublishRNWKProperties::speedCorporateLANÿþÿ0ÿþÿ&PublishRNWKProperties::showBitrateDlogÿþÿ1ÿþÿ"PublishRNWKProperties::exportFlashÿþÿ1ÿþÿPublishJpegProperties::Widthÿþÿ215ÿþÿVector::Stream Formatÿþÿ0ÿþÿ"PublishHtmlProperties::VersionInfoÿþÿÿþÿ$PublishFormatProperties::gifFileNameÿþÿstorage_dialog.gifÿþÿ&PublishFormatProperties::qtDefaultNameÿþÿ1ÿþÿ"PublishQTProperties::PausedAtStartÿþÿ0ÿþÿ%PublishQTProperties::ControllerOptionÿþÿ0ÿþÿPublishPNGProperties::MaxColorsÿþÿ255ÿþÿ,PublishHtmlProperties::UsingOwnAlternateFileÿþÿ0ÿþÿ%PublishFormatProperties::rnwkFileNameÿþÿstorage_dialog.smilÿþÿ%PublishFormatProperties::projectorWinÿþÿ0ÿþÿ%PublishFormatProperties::defaultNamesÿþÿ0ÿÿÿÿÿþÿÿþÿüÿÿ	CColorDefÿ€ÿ€ÿ€3ÿPï€fÿPï0€™ÿPïH€ÌÿPï`€ÿÿPïx€3ÿï€33ÿ(ï€3fÿ<ï0€3™ÿCïH€3ÌÿFï`€3ÿÿHïx€fÿï0€f3ÿï0€ffÿ(ï0€f™ÿ5ïH€fÌÿ<ï`€fÿÿ@ïx€ÿ€333ÿ0€ÿ€3ÿ ï€33ÿxï€f3ÿdï0€™3ÿ]ïH€Ì3ÿZï`€ÿ3ÿXïx€33ÿÈï€333ÿ0€3f3ÿPPH€3™3ÿPx`€3Ì3ÿP�x€3ÿ3ÿPï�€f3ÿÜï0€f33ÿPH€ff3ÿ(PH€f™3ÿ<x`€fÌ3ÿC�x€fÿ3ÿFï�€ÿ€fffÿ`€ÿ€fÿ ï0€3fÿŒï0€ffÿxï0€™fÿkïH€Ìfÿdï`€ÿfÿ`ïx€3fÿ´ï0€33fÿ PH€3ffÿxPH€3™fÿdx`€3Ìfÿ]�x€3ÿfÿZï�€ffÿÈï0€f3fÿÈPH€fffÿ`€f™fÿP0x€fÌfÿPx�€fÿfÿPï¨€ÿ€™™™ÿ�€ÿ€™ÿ ïH€3™ÿ“ïH€f™ÿ…ïH€™™ÿxïH€Ì™ÿnï`€ÿ™ÿhïx€3™ÿ­ïH€33™ÿ x`€3f™ÿŒx`€3™™ÿxx`€3Ì™ÿk�x€3ÿ™ÿdï�€f™ÿ»ïH€f3™ÿ´x`€ff™ÿ 0x€f™™ÿx0x€fÌ™ÿdx�€fÿ™ÿ]ï¨€ÿ€ÌÌÌÿÀ€ÿ€Ìÿ ï`€3Ìÿ–ï`€fÌÿŒï`€™Ìÿ‚ï`€ÌÌÿxï`€ÿÌÿpïx€3Ìÿªï`€33Ìÿ �x€3fÌÿ“�x€3™Ìÿ…�x€3ÌÌÿx�x€3ÿÌÿnï�€fÌÿ´ï`€f3Ìÿ­�x€ffÌÿ x�€f™ÌÿŒx�€fÌÌÿxx�€fÿÌÿkï¨€ÿ€ÿÿÿÿð€ÿ€ÿÿ ïx€3ÿÿ˜ïx€fÿÿ�ïx€™ÿÿˆïx€Ìÿÿ€ïx€ÿÿÿxïx€3ÿÿ¨ïx€33ÿÿ ï�€3fÿÿ–ï�€3™ÿÿŒï�€3Ìÿÿ‚ï�€3ÿÿÿxï�€fÿÿ°ïx€f3ÿÿªï�€ffÿÿ ï¨€f™ÿÿ“ï¨€fÌÿÿ…ï¨€fÿÿÿxï¨€ÿ€ÿÿïx€ÿ€™ÿïH€™3ÿ
ïH€™fÿïH€™™ÿ(ïH€™Ìÿ2ï`€™ÿÿ8ïx€Ìÿï`€Ì3ÿ
ï`€Ìfÿï`€Ì™ÿï`€ÌÌÿ(ï`€Ìÿÿ0ïx€ÿÿïx€ÿ3ÿïx€ÿfÿïx€ÿ™ÿïx€ÿÌÿ ïx€ÿÿÿ(ïx€ÿ€ÿÿPïx€ÿ€™3ÿãïH€™33ÿx`€™f3ÿx`€™™3ÿ(x`€™Ì3ÿ5�x€™ÿ3ÿ<ï�€Ì3ÿæï`€Ì33ÿ�x€Ìf3ÿ
�x€Ì™3ÿ�x€ÌÌ3ÿ(�x€Ìÿ3ÿ2ï�€ÿ3ÿèïx€ÿ33ÿï�€ÿf3ÿ
ï�€ÿ™3ÿï�€ÿÌ3ÿï�€ÿÿ3ÿ(ï�€ÿ€ÿÿ ïx€ÿ€™fÿÕïH€™3fÿÜx`€™ffÿ0x€™™fÿ(0x€™Ìfÿ<x�€™ÿfÿCï¨€ÌfÿÜï`€Ì3fÿã�x€Ìffÿx�€Ì™fÿx�€ÌÌfÿ(x�€Ìÿfÿ5ï¨€ÿfÿàïx€ÿ3fÿæï�€ÿffÿï¨€ÿ™fÿ
ï¨€ÿÌfÿï¨€ÿÿfÿ(ï¨€ÿ€ÿÿÿ(ïx€ÿ€™™ÿÈïH€™3™ÿÈx`€™f™ÿÈ0x€™™™ÿ�€™Ì™ÿPP¨€™ÿ™ÿPïÀ€Ì™ÿÒï`€Ì3™ÿÕ�x€Ìf™ÿÜx�€Ì™™ÿP¨€ÌÌ™ÿ(P¨€Ìÿ™ÿ<ïÀ€ÿ™ÿØïx€ÿ3™ÿÜï�€ÿf™ÿãï¨€ÿ™™ÿïÀ€ÿÌ™ÿïÀ€ÿÿ™ÿ(ïÀ€ÿ€ÿÿÿxïx€ÿ€™Ìÿ¾ï`€™3Ìÿ»�x€™fÌÿ´x�€™™Ìÿ P¨€™ÌÌÿxP¨€™ÿÌÿdïÀ€ÌÌÿÈï`€Ì3ÌÿÈ�x€ÌfÌÿÈx�€Ì™ÌÿÈP¨€ÌÌÌÿÀ€ÌÿÌÿPïØ€ÿÌÿÐïx€ÿ3ÌÿÒï�€ÿfÌÿÕï¨€ÿ™ÌÿÜïÀ€ÿÌÌÿïØ€ÿÿÌÿ(ïØ€ÿ€ÿÿÿÈïx€ÿ€™ÿÿ¸ïx€™3ÿÿ´ï�€™fÿÿ­ï¨€™™ÿÿ ïÀ€™ÌÿÿŒïÀ€™ÿÿÿxïÀ€ÌÿÿÀïx€Ì3ÿÿ¾ï�€Ìfÿÿ»ï¨€Ì™ÿÿ´ïÀ€ÌÌÿÿ ïØ€ÌÿÿÿxïØ€ÿÿÿÈïx€ÿ3ÿÿÈï�€ÿfÿÿÈï¨€ÿ™ÿÿÈïÀ€ÿÌÿÿÈïØ€ÿÿÿÿð€ÿ€ÿRemoveGradientsÿþÿ0ÿþÿ PublishRNWKProperties::speed512Kÿþÿ0ÿþÿPublishJpegProperties::Heightÿþÿ138ÿþÿVector::ActionScriptVersionÿþÿ2ÿþÿVector::Event Compressÿþÿ7ÿþÿPublishHtmlProperties::Scaleÿþÿ0ÿþÿ0PublishFormatProperties::projectorWinDefaultNameÿþÿ1ÿþÿPublishQTProperties::Loopingÿþÿ0ÿþÿ*PublishQTProperties::UseQTSoundCompressionÿþÿ0ÿþÿ!PublishPNGProperties::PaletteNameÿþÿÿþÿ!PublishPNGProperties::Transparentÿþÿ0ÿþÿ&PublishGifProperties::TransparentAlphaÿþÿ128ÿþÿPublishGifProperties::Animatedÿþÿ0ÿþÿ"PublishRNWKProperties::mediaAuthorÿþÿÿþÿ(PublishRNWKProperties::speedCorporateLANÿþÿ0ÿþÿ&PublishRNWKProperties::showBitrateDlogÿþÿ1ÿþÿ"PublishRNWKProperties::exportFlashÿþÿ1ÿþÿPublishJpegProperties::Widthÿþÿ215ÿþÿVector::Stream Formatÿþÿ0ÿþÿ"PublishHtmlProperties::VersionInfoÿþÿÿþÿ$PublishFormatProperties::gifFileNameÿþÿstorage_dialog.gifÿþÿ&PublishFormatProperties::qtDefaultNameÿþÿ1ÿþÿ"PublishQTProperties::PausedAtStartÿþÿ0ÿþÿ%PublishQTProperties::ControllerOptionÿþÿ0ÿþÿPublishPNGProperties::MaxColorsÿþÿ255ÿþÿ,PublishHtmlProperties::UsingOwnAlternateFileÿþÿ0ÿþÿ%PublishFormatProperties::rnwkFileNameÿþÿstorage_dialog.smilÿþÿ%PublishFormatProperties::projectorWinÿþÿ0ÿþÿ%PublishFormatProperties::defaultNamesÿþÿ0ÿÿÿÿÿþÿÿþÿüÿÿ	CColorDefÿ€ÿ€ÿ€3ÿPï€fÿPï0€™ÿPïH€ÌÿPï`€ÿÿPïx€3ÿï€33ÿ(ï€3fÿ<ï0€3™ÿCïH€3ÌÿFï`€3ÿÿHïx€fÿï0€f3ÿÿÿÿÿÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿfýÿ`ÿÿÿÿzÿÿÿÿ€™fÿªÿÌÿÿÿÿÿÿ€ÿÿÿ*ÿÿÿ]ÿÿÿÿÿªÿÿÔÿÿÿÿÿÿÿþÿ"PublishQTProperties::QTSndSettingsÿÿCQTAudioSettinÿï0€ffÿ(ï0€f™ÿ5ïH€fÌÿ<ï`€fÿÿ@ïx€ÿ€333ÿ0€ÿ€3ÿ ï€33ÿxï€f3ÿdï0€™3ÿ]ïH€Ì3ÿZï`€ÿ3ÿXïx€33ÿÈï€333ÿ0€3f3ÿPPH€3™3ÿPx`€3Ì3ÿP�x€3ÿ3ÿPï�€f3ÿÜï0€f33ÿPH€ff3ÿ(PH€f™3ÿ<x`€fÌ3ÿC�x€fÿ3ÿFï�€ÿ€fffÿ`€ÿ€fÿ ï0€3fÿŒï0€ffÿxï0€™fÿkïH€Ìfÿdï`€ÿfÿgsÿÿÿþÿhÿþÿÿþÿ

ÿÿÿÿÿþÿÿþÿ`ïx€3fÿ´ï0€33fÿ PH€3ffÿxPH€3™fÿdx`€3Ìfÿ]�x€3ÿfÿZï�€ffÿÈï0€f3fÿÈPH€fffÿ`€f™fÿP0x€fÌfÿPx�€fÿfÿPï¨€ÿ€™™™ÿ�€ÿ€™ÿ ïH€3™ÿ“ïH€f™ÿ…ïH€™™ÿxïH€Ì™ÿnï`€ÿ™ÿhïx€3™ÿ­ïH€33™ÿ x`€3f™ÿŒx`€3™™ÿxx`€3Ì™ÿk�x€3ÿ™ÿdï�€f™ÿ»ïH€f3™ÿ´x`€ff™ÿ 0x€f™™ÿx0x€fÌ™ÿdx�€fÿ™ÿ]ï¨€ÿ€ÌÌÌÿÀ€ÿ€Ìÿ ï`€3Ìÿ–ï`€fÌÿŒï`€™Ìÿ‚ï`€ÌÌÿxï`€ÿÌÿpïx€3Ìÿªï`€33Ìÿ �x€3fÌÿ“�x€3™Ìÿ…�x€3ÌÌÿx�x€3ÿÌÿnï�€fÌÿ´ï`€f3Ìÿ­�x€ffÌÿ x�€f™ÌÿŒx�€fÌÌÿxx�€fÿÌÿkï¨€ÿ€ÿÿÿÿð€ÿ€ÿÿ ïx€3ÿÿ˜ïx€fÿÿ�ïx€™ÿÿˆïx€Ìÿÿ€ïx€ÿÿÿxïx€3ÿÿ¨ïx€33ÿÿ ï�€3fÿÿ–ï�€3™ÿÿŒï�€3Ìÿÿ‚ï�€3ÿÿÿxï�€fÿÿ°ïx€f3ÿÿªï�€ffÿÿ ï¨€f™ÿÿ“ï¨€fÌÿÿ…ï¨€fÿÿÿxï¨€ÿ€ÿÿïx€ÿ€™ÿïH€™3ÿ
ïH€™fÿïH€™™ÿ(ïH€™Ìÿ2ï`€™ÿÿ8ïx€Ìÿï`€Ì3ÿ
ï`€Ìfÿï`€Ì™ÿï`€ÌÌÿ(ï`€Ìÿÿ0ïx€ÿÿïx€ÿ3ÿïx€ÿfÿïx€ÿ™ÿïx€ÿÌÿ ïx€ÿÿÿ(ïx€ÿ€ÿÿPïx€ÿ€™3ÿãïH€™33ÿx`€™f3ÿx`€™™3ÿ(x`€™Ì3ÿ5�x€™ÿ3ÿ<ï�€Ì3ÿæï`€Ì33ÿ�x€Ìf3ÿ
�x€Ì™3ÿ�x€ÌÌ3ÿ(�x€Ìÿ3ÿ2ï�€ÿ3ÿèïx€ÿ33ÿï�€ÿf3ÿ
ï�€ÿ™3ÿï�€ÿÌ3ÿï�€ÿÿ3ÿ(ï�€ÿ€ÿÿ ïx€ÿ€™fÿÕïH€™3fÿÜx`€™ffÿ0x€™™fÿ(0x€™Ìfÿ<x�€™ÿfÿCï¨€ÌfÿÜï`€Ì3fÿã�x€Ìffÿx�€Ì™fÿx�€ÌÌfÿ(x�€Ìÿfÿ5ï¨€ÿfÿàïx€ÿ3fÿæï�€ÿffÿï¨€ÿ™fÿ
ï¨€ÿÌfÿï¨€ÿÿfÿ(ï¨€ÿ€ÿÿÿ(ïx€ÿ€™™ÿÈïH€™3™ÿÈx`€™f™ÿÈ0x€™™™ÿ�€™Ì™ÿPP¨€™ÿ™ÿPïÀ€Ì™ÿÒï`€Ì3™ÿÕ�x€Ìf™ÿÜx�€Ì™™ÿP¨€ÌÌ™ÿ(P¨€Ìÿ™ÿ<ïÀ€ÿ™ÿØïx€ÿ3™ÿÜï�€ÿf™ÿãï¨€ÿ™™ÿïÀ€ÿÌ™ÿïÀ€ÿÿ™ÿ(ïÀ€ÿ€ÿÿÿxïx€ÿ€™Ìÿ¾ï`€™3Ìÿ»�x€™fÌÿ´x�€™™Ìÿ P¨€™ÌÌÿxP¨€™ÿÌÿdïÀ€ÌÌÿÈï`€Ì3ÌÿÈ�x€ÌfÌÿÈx�€Ì™ÌÿÈP¨€ÌÌÌÿÀ€ÌÿÌÿPïØ€ÿÌÿÐïx€ÿ3ÌÿÒï�€ÿfÌÿÕï¨€ÿ™ÌÿÜïÀ€ÿÌÌÿïØ€ÿÿÌÿ(ïØ€ÿ€ÿÿÿÈïx€ÿ€™ÿÿ¸ïx€™3ÿÿ´ï�€™fÿÿ­ï¨€™™ÿÿ ïÀ€™ÌÿÿŒïÀ€™ÿÿÿxïÀ€ÌÿÿÀïx€Ì3ÿÿ¾ï�€Ìfÿÿ»ï¨€Ì™ÿÿ´ïÀ€ÌÌÿÿ ïØ€ÌÿÿÿxïØ€ÿÿÿÈïx€ÿ3ÿÿÈï�€ÿfÿÿÈï¨€ÿ™ÿÿÈïÀ€ÿÌÿÿÈïØ€ÿÿÿÿð€ÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿÿÿÿÿ€ÿfýÿ`ÿÿÿÿzÿÿÿÿ€™fÿªÿÌÿÿÿÿÿÿ€ÿÿÿ*ÿÿÿ]ÿÿÿÿÿªÿÿÔÿÿÿÿÿÿÿþÿ"PublishQTProperties::QTSndSettingsÿÿCQTAudioSettingsÿÿÿþÿhÿþÿÿþÿ

ÿÿÿÿÿþÿÿþÿ
__CPAN_FILE__ src/storage/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: ["dojo.storage"],
	browser: ["dojo.storage.browser"],
	dashboard: ["dojo.storage.dashboard"]
});
dojo.provide("dojo.storage.*");


__CPAN_FILE__ src/storage/Storage.as
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

import DojoExternalInterface;

class Storage {
	public static var SUCCESS = "success";
	public static var FAILED = "failed";
	public static var PENDING = "pending";
	
	public var so;
	
	public function Storage(){
		//getURL("javascript:dojo.debug('FLASH:Storage constructor')");
		DojoExternalInterface.initialize();
		DojoExternalInterface.addCallback("put", this, put);
		DojoExternalInterface.addCallback("get", this, get);
		DojoExternalInterface.addCallback("showSettings", this, showSettings);
		DojoExternalInterface.addCallback("clear", this, clear);
		DojoExternalInterface.addCallback("getKeys", this, getKeys);
		DojoExternalInterface.addCallback("remove", this, remove);
		DojoExternalInterface.loaded();
		
		// preload the System Settings finished button movie for offline
		// access so it is in the cache
		_root.createEmptyMovieClip("_settingsBackground", 1);
		// getURL("javascript:alert('"+DojoExternalInterface.dojoPath+"');");
		_root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath + "storage_dialog.swf");
	}

	public function put(keyName, keyValue, namespace){
		// Get the SharedObject for these values and save it
		so = SharedObject.getLocal(namespace);
		
		// prepare a storage status handler
		var self = this;
		so.onStatus = function(infoObject:Object){
			//getURL("javascript:dojo.debug('FLASH: onStatus, infoObject="+infoObject.code+"')");
			
			// delete the data value if the request was denied
			if (infoObject.code == "SharedObject.Flush.Failed"){
				delete self.so.data[keyName];
			}
			
			var statusResults;
			if(infoObject.code == "SharedObject.Flush.Failed"){
				statusResults = Storage.FAILED;
			}else if(infoObject.code == "SharedObject.Flush.Pending"){
				statusResults = Storage.PENDING;
			}else if(infoObject.code == "SharedObject.Flush.Success"){
				statusResults = Storage.SUCCESS;
			}
			//getURL("javascript:dojo.debug('FLASH: onStatus, statusResults="+statusResults+"')");
			
			// give the status results to JavaScript
			DojoExternalInterface.call("dojo.storage._onStatus", null, statusResults, 
																 keyName);
		}
		
		// save the key and value
		so.data[keyName] = keyValue;
		var flushResults = so.flush();
		
		// return results of this command to JavaScript
		var statusResults;
		if(flushResults == true){
			statusResults = Storage.SUCCESS;
		}else if(flushResults == "pending"){
			statusResults = Storage.PENDING;
		}else{
			statusResults = Storage.FAILED;
		}
		
		DojoExternalInterface.call("dojo.storage._onStatus", null, statusResults, 
															 keyName);
	}

	public function get(keyName, namespace){
		// Get the SharedObject for these values and save it
		so = SharedObject.getLocal(namespace);
		var results = so.data[keyName];
		
		return results;
	}
	
	public function showSettings(){
		// Show the configuration options for the Flash player, opened to the
		// section for local storage controls (pane 1)
		System.showSettings(1);
		
		// there is no way we can intercept when the Close button is pressed, allowing us
		// to hide the Flash dialog. Instead, we need to load a movie in the
		// background that we can show a close button on.
		_root.createEmptyMovieClip("_settingsBackground", 1);
		_root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath + "storage_dialog.swf");
	}
	
	public function clear(namespace){
		so = SharedObject.getLocal(namespace);
		so.clear();
		so.flush();
	}
	
	public function getKeys(namespace){
		// Returns a list of the available keys in this namespace
		
		// get the storage object
		so = SharedObject.getLocal(namespace);
		
		// get all of the keys
		var results = new Array();
		for(var i in so.data)
			results.push(i);	
		
		// join the keys together in a comma seperated string
		results = results.join(",");
		
		return results;
	}
	
	public function remove(keyName, namespace){
		// Removes a key

		// get the storage object
		so = SharedObject.getLocal(namespace);
		
		// delete this value
		delete so.data[keyName];
		
		// save the changes
		so.flush();
	}

	static function main(mc){
		//getURL("javascript:dojo.debug('FLASH: storage loaded')");
		_root.app = new Storage(); 
	}
}


__CPAN_DIR__ src/io
__CPAN_FILE__ src/io/xip_server.html
<!--
	/*
		Copyright (c) 2004-2006, The Dojo Foundation
		All Rights Reserved.
	
		Licensed under the Academic Free License version 2.1 or above OR the
		modified BSD license. For more information on Dojo licensing, see:
	
			http://dojotoolkit.org/community/licensing.shtml
	*/
	Pieces taken from Dojo source to make this file stand-alone
-->
<html>
<head>
	<title></title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
	<script type="text/javascript" src="isAllowed.js"></script>
	<!--
	BY DEFAULT THIS FILE DOES NOT WORK SO THAT YOU DON'T ACCIDENTALLY EXPOSE
	ALL OF YOUR XHR-ENABLED SERVICES ON YOUR SITE. 
	
	In order for this file to work, you should define a function with the following signature:
	
	function isAllowedRequest(request){
		return false;	
	}
	
	Return true out of the function if you want to allow the cross-domain request.
	
	DON'T DEFINE THIS FUNCTION IN THIS FILE! Define it in a separate file called isAllowed.js
	and include it in this page with a script tag that has a src attribute pointing to the file.
	See the very first script tag in this file for an example. You do not have to place the
	script file in the same directory as this file, just update the path above if you move it
	somewhere else.
	
	Customize the isAllowedRequest function to restrict what types of requests are allowed
	for this server. The request object has the following properties:
	- requestHeaders: an object with the request headers that are to be added to
	                  the XHR request.
	- method: the HTTP method (GET, POST, etc...)
	- uri: The URI for the request.
	- data: The URL-encoded data for the request. For a GET request, this would
	        be the querystring parameters. For a POST request, it wll be the
	        body data.
	-->
	<script type="text/javascript">
	// <!--
	/*
	See xip_client.html for more info on the xip fragment identifier protocol.
	
	This page uses Dojo to do the actual XMLHttpRequest (XHR) to the server, but you could
	replace the Dojo references with your own XHR code if you like. But keep the other xip
	code to communicate back to the xip client frame.
	*/
	djConfig = {
		parseWidgets: false,
		baseScriptUri: "./"
	}
	// -->
	</script>
	<script type="text/javascript">
		dojo = {};
		dojo.hostenv = {};
		// These are in order of decreasing likelihood; this will change in time.
		dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
		
		dojo.hostenv.getXmlhttpObject = function(){
				var http = null;
			var last_e = null;
			try{ http = new XMLHttpRequest(); }catch(e){}
				if(!http){
				for(var i=0; i<3; ++i){
					var progid = dojo.hostenv._XMLHTTP_PROGIDS[i];
					try{
						http = new ActiveXObject(progid);
					}catch(e){
						last_e = e;
					}
		
					if(http){
						dojo.hostenv._XMLHTTP_PROGIDS = [progid];  // so faster next time
						break;
					}
				}
		
				/*if(http && !http.toString) {
					http.toString = function() { "[object XMLHttpRequest]"; }
				}*/
			}
		
			if(!http){
				throw "xip_server.html: XMLHTTP not available: " + last_e;
			}
		
			return http;
		}

		dojo.setHeaders = function(http, headers){
			if(headers) {
				for(var header in headers) {
					var headerValue = headers[header];
					http.setRequestHeader(header, headerValue);
				}
			}
		}

	//Choosing 1024 as an arbitrary limit for the URL sizes.
	//Anecdotal info seems to indicate this is safe to use in all
	//modern browsers.
	xipUrlLimit = 1024;
	xipIdCounter = 1;

	function xipServerInit(){
		xipCurrentHash = "";
		xipRequestMessage = "";
		xipResponseParts = [];
		xipPartIndex = 0;
	}

	function xipServerLoaded(){
		xipServerInit();
		xipClientUrl = decodeURIComponent(window.location.hash.substring(1, window.location.hash.length));
		
		setInterval(pollHash, 10);
		setClientUrl("loaded");
	}

	function pollHash(){
		//Can't use location.hash because at least Firefox does a decodeURIComponent on it.
		var urlParts = window.location.href.split("#");
		if(urlParts.length == 2){
			var newHash = urlParts[1];
			if(newHash != xipCurrentHash){
				try{
					messageReceived(newHash);
				}catch(e){
					//Make sure to not keep processing the error hash value.
					xipCurrentHash = newHash;
					throw e;
				}
				xipCurrentHash = newHash;
			}
		}
	}

	function messageReceived(urlEncodedMessage){
		//Split off xip header.
		var parts = urlEncodedMessage.split(":");
		var command = parts[1];
		urlEncodedMessage = parts[2] || "";
		
		switch(command){
			case "ok":
				sendResponsePart();
				break;
			case "start":
				xipRequestMessage = "";
				xipRequestMessage += urlEncodedMessage;
				setClientUrl("ok");
				break;
			case "part":
				xipRequestMessage += urlEncodedMessage;			
				setClientUrl("ok");
				break;
			case "end":
				setClientUrl("ok");
				xipRequestMessage += urlEncodedMessage;
				sendXhr();
				break;
		}
	}

	function sendResponse(urlEncodedData){
		//Break the message into parts, if necessary.
		xipResponseParts = [];
		var resData = urlEncodedData;
		var urlLength = xipClientUrl.length;
		var partLength = xipUrlLimit - urlLength;
		var resIndex = 0;

		while((resData.length - resIndex) + urlLength > xipUrlLimit){
			xipResponseParts.push(resData.substring(resIndex, resIndex + partLength));
			resIndex += partLength;
		}
		xipResponseParts.push(resData.substring(resIndex, resData.length));
		
		xipPartIndex = 0;
		sendResponsePart();
	}
	
	function sendResponsePart(){
		if(xipPartIndex < xipResponseParts.length){
			//Get the message part.
			var partData = xipResponseParts[xipPartIndex];
			
			//Get the command.
			var cmd = "part";
			if(xipPartIndex + 1 == xipResponseParts.length){
				cmd = "end";
			}else if (xipPartIndex == 0){
				cmd = "start";
			}

			setClientUrl(cmd, partData);
			xipPartIndex++;
		}else{
			xipServerInit();
		}
	}

	function setClientUrl(cmd, message){
		var clientUrl = xipClientUrl + "#" + (xipIdCounter++) + ":" + cmd;
		if(message){
			clientUrl += ":" + message;
		}

		//Safari won't let us replace across domains.
		if(navigator.userAgent.indexOf("Safari") == -1){
			parent.location.replace(clientUrl);
		}else{
			parent.location = clientUrl;
		}
	}

	function xhrDone(xhr){
		/* Need to pull off and return the following data:
			- responseHeaders
			- status
			- statusText
			- responseText
		*/
		var response = {};
	
		if(typeof(xhr.getAllResponseHeaders) != "undefined"){
			var allHeaders = xhr.getAllResponseHeaders();
			if(allHeaders){
				response.responseHeaders = allHeaders;
			}
		}
		
		if(xhr.status == 0 || xhr.status){
			response.status = xhr.status;
		}
		
		if(xhr.statusText){
			response.statusText = xhr.statusText;
		}
		
		if(xhr.responseText){
			response.responseText = xhr.responseText;
		}
	
		//Build a string of the response object.
		var result = "";
		var isFirst = true;
		for (var param in response){
			if(isFirst){
				isFirst = false;
			}else{
				result += "&";
			}
			result += param + "=" + encodeURIComponent(response[param]);
		}
		sendResponse(result);
	}

	function sendXhr(){
		var request = {};
		var nvPairs = xipRequestMessage.split("&");
		var i = 0;
		var nameValue = null;
		for(i = 0; i < nvPairs.length; i++){
			if(nvPairs[i]){
				var nameValue = nvPairs[i].split("=");
				request[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
			}
		}

		//Split up the request headers, if any.
		var headers = {};
		if(request.requestHeaders){
			nvPairs = request.requestHeaders.split("\r\n");
			for(i = 0; i < nvPairs.length; i++){
				if(nvPairs[i]){
					nameValue = nvPairs[i].split(": ");
					headers[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
				}
			}

			request.requestHeaders = headers;
		}
		
		if(isAllowedRequest(request)){
		
			//The request is allowed, so set up the XHR object.
			var xhr = dojo.hostenv.getXmlhttpObject();
			
			//Start timer to look for readyState.
			var xhrIntervalId = setInterval(function(){
			
				if(xhr.readyState == 4){
					clearInterval(xhrIntervalId);
					xhrDone(xhr);
				}
			}, 10);

			//Actually start up the XHR request.
			xhr.open(request.method, request.uri, true);
			dojo.setHeaders(xhr, request.requestHeaders);
			
			var content = "";
			if(request.data){
				content = request.data;
			}

			try{
				xhr.send(content);
			}catch(e){
				if(typeof xhr.abort == "function"){
					xhr.abort();
					xhrDone({status: 404, statusText: "xip_server.html error: " + e});
				}
			}
		}
	}

	window.onload = xipServerLoaded;
	// -->
	</script>
</head>
<body>
	<h4>The Dojo Toolkit -- xip_server.html</h4>

	<p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file
	that should go on the server that will actually be doing the XHR request.</p>
</body>
</html>

__CPAN_FILE__ src/io/BrowserIO.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.BrowserIO");

dojo.require("dojo.io.common");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.func");
dojo.require("dojo.string.extras");
dojo.require("dojo.dom");
dojo.require("dojo.undo.browser");

dojo.io.checkChildrenForFile = function(node){
	var hasFile = false;
	var inputs = node.getElementsByTagName("input");
	dojo.lang.forEach(inputs, function(input){
		if(hasFile){ return; }
		if(input.getAttribute("type")=="file"){
			hasFile = true;
		}
	});
	return hasFile;
}

dojo.io.formHasFile = function(formNode){
	return dojo.io.checkChildrenForFile(formNode);
}

dojo.io.updateNode = function(node, urlOrArgs){
	node = dojo.byId(node);
	var args = urlOrArgs;
	if(dojo.lang.isString(urlOrArgs)){
		args = { url: urlOrArgs };
	}
	args.mimetype = "text/html";
	args.load = function(t, d, e){
		while(node.firstChild){
			if(dojo["event"]){
				try{
					dojo.event.browser.clean(node.firstChild);
				}catch(e){}
			}
			node.removeChild(node.firstChild);
		}
		node.innerHTML = d;
	};
	dojo.io.bind(args);
}

dojo.io.formFilter = function(node) {
	var type = (node.type||"").toLowerCase();
	return !node.disabled && node.name
		&& !dojo.lang.inArray(["file", "submit", "image", "reset", "button"], type);
}

// TODO: Move to htmlUtils
dojo.io.encodeForm = function(formNode, encoding, formFilter){
	if((!formNode)||(!formNode.tagName)||(!formNode.tagName.toLowerCase() == "form")){
		dojo.raise("Attempted to encode a non-form element.");
	}
	if(!formFilter) { formFilter = dojo.io.formFilter; }
	var enc = /utf/i.test(encoding||"") ? encodeURIComponent : dojo.string.encodeAscii;
	var values = [];

	for(var i = 0; i < formNode.elements.length; i++){
		var elm = formNode.elements[i];
		if(!elm || elm.tagName.toLowerCase() == "fieldset" || !formFilter(elm)) { continue; }
		var name = enc(elm.name);
		var type = elm.type.toLowerCase();

		if(type == "select-multiple"){
			for(var j = 0; j < elm.options.length; j++){
				if(elm.options[j].selected) {
					values.push(name + "=" + enc(elm.options[j].value));
				}
			}
		}else if(dojo.lang.inArray(["radio", "checkbox"], type)){
			if(elm.checked){
				values.push(name + "=" + enc(elm.value));
			}
		}else{
			values.push(name + "=" + enc(elm.value));
		}
	}

	// now collect input type="image", which doesn't show up in the elements array
	var inputs = formNode.getElementsByTagName("input");
	for(var i = 0; i < inputs.length; i++) {
		var input = inputs[i];
		if(input.type.toLowerCase() == "image" && input.form == formNode
			&& formFilter(input)) {
			var name = enc(input.name);
			values.push(name + "=" + enc(input.value));
			values.push(name + ".x=0");
			values.push(name + ".y=0");
		}
	}
	return values.join("&") + "&";
}

dojo.io.FormBind = function(args) {
	this.bindArgs = {};

	if(args && args.formNode) {
		this.init(args);
	} else if(args) {
		this.init({formNode: args});
	}
}
dojo.lang.extend(dojo.io.FormBind, {
	form: null,

	bindArgs: null,

	clickedButton: null,

	init: function(args) {
		var form = dojo.byId(args.formNode);

		if(!form || !form.tagName || form.tagName.toLowerCase() != "form") {
			throw new Error("FormBind: Couldn't apply, invalid form");
		} else if(this.form == form) {
			return;
		} else if(this.form) {
			throw new Error("FormBind: Already applied to a form");
		}

		dojo.lang.mixin(this.bindArgs, args);
		this.form = form;

		this.connect(form, "onsubmit", "submit");

		for(var i = 0; i < form.elements.length; i++) {
			var node = form.elements[i];
			if(node && node.type && dojo.lang.inArray(["submit", "button"], node.type.toLowerCase())) {
				this.connect(node, "onclick", "click");
			}
		}

		var inputs = form.getElementsByTagName("input");
		for(var i = 0; i < inputs.length; i++) {
			var input = inputs[i];
			if(input.type.toLowerCase() == "image" && input.form == form) {
				this.connect(input, "onclick", "click");
			}
		}
	},

	onSubmit: function(form) {
		return true;
	},

	submit: function(e) {
		e.preventDefault();
		if(this.onSubmit(this.form)) {
			dojo.io.bind(dojo.lang.mixin(this.bindArgs, {
				formFilter: dojo.lang.hitch(this, "formFilter")
			}));
		}
	},

	click: function(e) {
		var node = e.currentTarget;
		if(node.disabled) { return; }
		this.clickedButton = node;
	},

	formFilter: function(node) {
		var type = (node.type||"").toLowerCase();
		var accept = false;
		if(node.disabled || !node.name) {
			accept = false;
		} else if(dojo.lang.inArray(["submit", "button", "image"], type)) {
			if(!this.clickedButton) { this.clickedButton = node; }
			accept = node == this.clickedButton;
		} else {
			accept = !dojo.lang.inArray(["file", "submit", "reset", "button"], type);
		}
		return accept;
	},

	// in case you don't have dojo.event.* pulled in
	connect: function(srcObj, srcFcn, targetFcn) {
		if(dojo.evalObjPath("dojo.event.connect")) {
			dojo.event.connect(srcObj, srcFcn, this, targetFcn);
		} else {
			var fcn = dojo.lang.hitch(this, targetFcn);
			srcObj[srcFcn] = function(e) {
				if(!e) { e = window.event; }
				if(!e.currentTarget) { e.currentTarget = e.srcElement; }
				if(!e.preventDefault) { e.preventDefault = function() { window.event.returnValue = false; } }
				fcn(e);
			}
		}
	}
});

dojo.io.XMLHTTPTransport = new function(){
	var _this = this;

	var _cache = {}; // FIXME: make this public? do we even need to?
	this.useCache = false; // if this is true, we'll cache unless kwArgs.useCache = false
	this.preventCache = false; // if this is true, we'll always force GET requests to cache

	// FIXME: Should this even be a function? or do we just hard code it in the next 2 functions?
	function getCacheKey(url, query, method) {
		return url + "|" + query + "|" + method.toLowerCase();
	}

	function addToCache(url, query, method, http) {
		_cache[getCacheKey(url, query, method)] = http;
	}

	function getFromCache(url, query, method) {
		return _cache[getCacheKey(url, query, method)];
	}

	this.clearCache = function() {
		_cache = {};
	}

	// moved successful load stuff here
	function doLoad(kwArgs, http, url, query, useCache) {
		if(	((http.status>=200)&&(http.status<300))|| 	// allow any 2XX response code
			(http.status==304)|| 						// get it out of the cache
			(location.protocol=="file:" && (http.status==0 || http.status==undefined))||
			(location.protocol=="chrome:" && (http.status==0 || http.status==undefined))
		){
			var ret;
			if(kwArgs.method.toLowerCase() == "head"){
				var headers = http.getAllResponseHeaders();
				ret = {};
				ret.toString = function(){ return headers; }
				var values = headers.split(/[\r\n]+/g);
				for(var i = 0; i < values.length; i++) {
					var pair = values[i].match(/^([^:]+)\s*:\s*(.+)$/i);
					if(pair) {
						ret[pair[1]] = pair[2];
					}
				}
			}else if(kwArgs.mimetype == "text/javascript"){
				try{
					ret = dj_eval(http.responseText);
				}catch(e){
					dojo.debug(e);
					dojo.debug(http.responseText);
					ret = null;
				}
			}else if(kwArgs.mimetype == "text/json" || kwArgs.mimetype == "application/json"){
				try{
					ret = dj_eval("("+http.responseText+")");
				}catch(e){
					dojo.debug(e);
					dojo.debug(http.responseText);
					ret = false;
				}
			}else if((kwArgs.mimetype == "application/xml")||
						(kwArgs.mimetype == "text/xml")){
				ret = http.responseXML;
				if(!ret || typeof ret == "string" || !http.getResponseHeader("Content-Type")) {
					ret = dojo.dom.createDocumentFromText(http.responseText);
				}
			}else{
				ret = http.responseText;
			}

			if(useCache){ // only cache successful responses
				addToCache(url, query, kwArgs.method, http);
			}
			kwArgs[(typeof kwArgs.load == "function") ? "load" : "handle"]("load", ret, http, kwArgs);
		}else{
			var errObj = new dojo.io.Error("XMLHttpTransport Error: "+http.status+" "+http.statusText);
			kwArgs[(typeof kwArgs.error == "function") ? "error" : "handle"]("error", errObj, http, kwArgs);
		}
	}

	// set headers (note: Content-Type will get overriden if kwArgs.contentType is set)
	function setHeaders(http, kwArgs){
		if(kwArgs["headers"]) {
			for(var header in kwArgs["headers"]) {
				if(header.toLowerCase() == "content-type" && !kwArgs["contentType"]) {
					kwArgs["contentType"] = kwArgs["headers"][header];
				} else {
					http.setRequestHeader(header, kwArgs["headers"][header]);
				}
			}
		}
	}

	this.inFlight = [];
	this.inFlightTimer = null;

	this.startWatchingInFlight = function(){
		if(!this.inFlightTimer){
			// setInterval broken in mozilla x86_64 in some circumstances, see
			// https://bugzilla.mozilla.org/show_bug.cgi?id=344439
			// using setTimeout instead
			this.inFlightTimer = setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();", 10);
		}
	}

	this.watchInFlight = function(){
		var now = null;
		// make sure sync calls stay thread safe, if this callback is called during a sync call
		// and this results in another sync call before the first sync call ends the browser hangs
		if(!dojo.hostenv._blockAsync && !_this._blockAsync){
			for(var x=this.inFlight.length-1; x>=0; x--){
				try{
					var tif = this.inFlight[x];
					if(!tif || tif.http._aborted || !tif.http.readyState){
						this.inFlight.splice(x, 1); continue; 
					}
					if(4==tif.http.readyState){
						// remove it so we can clean refs
						this.inFlight.splice(x, 1);
						doLoad(tif.req, tif.http, tif.url, tif.query, tif.useCache);
					}else if (tif.startTime){
						//See if this is a timeout case.
						if(!now){
							now = (new Date()).getTime();
						}
						if(tif.startTime + (tif.req.timeoutSeconds * 1000) < now){
							//Stop the request.
							if(typeof tif.http.abort == "function"){
								tif.http.abort();
							}
		
							// remove it so we can clean refs
							this.inFlight.splice(x, 1);
							tif.req[(typeof tif.req.timeout == "function") ? "timeout" : "handle"]("timeout", null, tif.http, tif.req);
						}
					}
				}catch(e){
					try{
						var errObj = new dojo.io.Error("XMLHttpTransport.watchInFlight Error: " + e);
						tif.req[(typeof tif.req.error == "function") ? "error" : "handle"]("error", errObj, tif.http, tif.req);
					}catch(e2){
						dojo.debug("XMLHttpTransport error callback failed: " + e2);
					}
				}
			}
		}

		clearTimeout(this.inFlightTimer);
		if(this.inFlight.length == 0){
			this.inFlightTimer = null;
			return;
		}
		this.inFlightTimer = setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();", 10);
	}

	var hasXmlHttp = dojo.hostenv.getXmlhttpObject() ? true : false;
	this.canHandle = function(kwArgs){
		// canHandle just tells dojo.io.bind() if this is a good transport to
		// use for the particular type of request.

		// FIXME: we need to determine when form values need to be
		// multi-part mime encoded and avoid using this transport for those
		// requests.
		return hasXmlHttp
			&& dojo.lang.inArray(["text/plain", "text/html", "application/xml", "text/xml", "text/javascript", "text/json", "application/json"], (kwArgs["mimetype"].toLowerCase()||""))
			&& !( kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"]) );
	}

	this.multipartBoundary = "45309FFF-BD65-4d50-99C9-36986896A96F";	// unique guid as a boundary value for multipart posts

	this.bind = function(kwArgs){
		if(!kwArgs["url"]){
			// are we performing a history action?
			if( !kwArgs["formNode"]
				&& (kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"] || kwArgs["watchForURL"])
				&& (!djConfig.preventBackButtonFix)) {
        dojo.deprecated("Using dojo.io.XMLHTTPTransport.bind() to add to browser history without doing an IO request",
        				"Use dojo.undo.browser.addToHistory() instead.", "0.4");
				dojo.undo.browser.addToHistory(kwArgs);
				return true;
			}
		}

		// build this first for cache purposes
		var url = kwArgs.url;
		var query = "";
		if(kwArgs["formNode"]){
			var ta = kwArgs.formNode.getAttribute("action");
			if((ta)&&(!kwArgs["url"])){ url = ta; }
			var tp = kwArgs.formNode.getAttribute("method");
			if((tp)&&(!kwArgs["method"])){ kwArgs.method = tp; }
			query += dojo.io.encodeForm(kwArgs.formNode, kwArgs.encoding, kwArgs["formFilter"]);
		}

		if(url.indexOf("#") > -1) {
			dojo.debug("Warning: dojo.io.bind: stripping hash values from url:", url);
			url = url.split("#")[0];
		}

		if(kwArgs["file"]){
			// force post for file transfer
			kwArgs.method = "post";
		}

		if(!kwArgs["method"]){
			kwArgs.method = "get";
		}

		// guess the multipart value
		if(kwArgs.method.toLowerCase() == "get"){
			// GET cannot use multipart
			kwArgs.multipart = false;
		}else{
			if(kwArgs["file"]){
				// enforce multipart when sending files
				kwArgs.multipart = true;
			}else if(!kwArgs["multipart"]){
				// default 
				kwArgs.multipart = false;
			}
		}

		if(kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"]){
			dojo.undo.browser.addToHistory(kwArgs);
		}

		var content = kwArgs["content"] || {};

		if(kwArgs.sendTransport) {
			content["dojo.transport"] = "xmlhttp";
		}

		do { // break-block
			if(kwArgs.postContent){
				query = kwArgs.postContent;
				break;
			}

			if(content) {
				query += dojo.io.argsFromMap(content, kwArgs.encoding);
			}
			
			if(kwArgs.method.toLowerCase() == "get" || !kwArgs.multipart){
				break;
			}

			var	t = [];
			if(query.length){
				var q = query.split("&");
				for(var i = 0; i < q.length; ++i){
					if(q[i].length){
						var p = q[i].split("=");
						t.push(	"--" + this.multipartBoundary,
								"Content-Disposition: form-data; name=\"" + p[0] + "\"", 
								"",
								p[1]);
					}
				}
			}

			if(kwArgs.file){
				if(dojo.lang.isArray(kwArgs.file)){
					for(var i = 0; i < kwArgs.file.length; ++i){
						var o = kwArgs.file[i];
						t.push(	"--" + this.multipartBoundary,
								"Content-Disposition: form-data; name=\"" + o.name + "\"; filename=\"" + ("fileName" in o ? o.fileName : o.name) + "\"",
								"Content-Type: " + ("contentType" in o ? o.contentType : "application/octet-stream"),
								"",
								o.content);
					}
				}else{
					var o = kwArgs.file;
					t.push(	"--" + this.multipartBoundary,
							"Content-Disposition: form-data; name=\"" + o.name + "\"; filename=\"" + ("fileName" in o ? o.fileName : o.name) + "\"",
							"Content-Type: " + ("contentType" in o ? o.contentType : "application/octet-stream"),
							"",
							o.content);
				}
			}

			if(t.length){
				t.push("--"+this.multipartBoundary+"--", "");
				query = t.join("\r\n");
			}
		}while(false);

		// kwArgs.Connection = "close";

		var async = kwArgs["sync"] ? false : true;

		var preventCache = kwArgs["preventCache"] ||
			(this.preventCache == true && kwArgs["preventCache"] != false);
		var useCache = kwArgs["useCache"] == true ||
			(this.useCache == true && kwArgs["useCache"] != false );

		// preventCache is browser-level (add query string junk), useCache
		// is for the local cache. If we say preventCache, then don't attempt
		// to look in the cache, but if useCache is true, we still want to cache
		// the response
		if(!preventCache && useCache){
			var cachedHttp = getFromCache(url, query, kwArgs.method);
			if(cachedHttp){
				doLoad(kwArgs, cachedHttp, url, query, false);
				return;
			}
		}

		// much of this is from getText, but reproduced here because we need
		// more flexibility
		var http = dojo.hostenv.getXmlhttpObject(kwArgs);	
		var received = false;

		// build a handler function that calls back to the handler obj
		if(async){
			var startTime = 
			// FIXME: setting up this callback handler leaks on IE!!!
			this.inFlight.push({
				"req":		kwArgs,
				"http":		http,
				"url":	 	url,
				"query":	query,
				"useCache":	useCache,
				"startTime": kwArgs.timeoutSeconds ? (new Date()).getTime() : 0
			});
			this.startWatchingInFlight();
		}else{
			// block async callbacks until sync is in, needed in khtml, others?
			_this._blockAsync = true;
		}

		if(kwArgs.method.toLowerCase() == "post"){
			// FIXME: need to hack in more flexible Content-Type setting here!
			if (!kwArgs.user) {
				http.open("POST", url, async);
			}else{
        http.open("POST", url, async, kwArgs.user, kwArgs.password);
			}
			setHeaders(http, kwArgs);
			http.setRequestHeader("Content-Type", kwArgs.multipart ? ("multipart/form-data; boundary=" + this.multipartBoundary) : 
				(kwArgs.contentType || "application/x-www-form-urlencoded"));
			try{
				http.send(query);
			}catch(e){
				if(typeof http.abort == "function"){
					http.abort();
				}
				doLoad(kwArgs, {status: 404}, url, query, useCache);
			}
		}else{
			var tmpUrl = url;
			if(query != "") {
				tmpUrl += (tmpUrl.indexOf("?") > -1 ? "&" : "?") + query;
			}
			if(preventCache) {
				tmpUrl += (dojo.string.endsWithAny(tmpUrl, "?", "&")
					? "" : (tmpUrl.indexOf("?") > -1 ? "&" : "?")) + "dojo.preventCache=" + new Date().valueOf();
			}
			if (!kwArgs.user) {
				http.open(kwArgs.method.toUpperCase(), tmpUrl, async);
			}else{
				http.open(kwArgs.method.toUpperCase(), tmpUrl, async, kwArgs.user, kwArgs.password);
			}
			setHeaders(http, kwArgs);
			try {
				http.send(null);
			}catch(e)	{
				if(typeof http.abort == "function"){
					http.abort();
				}
				doLoad(kwArgs, {status: 404}, url, query, useCache);
			}
		}

		if( !async ) {
			doLoad(kwArgs, http, url, query, useCache);
			_this._blockAsync = false;
		}

		kwArgs.abort = function(){
			try{// khtml doesent reset readyState on abort, need this workaround
				http._aborted = true; 
			}catch(e){/*squelsh*/}
			return http.abort();
		}

		return;
	}
	dojo.io.transports.addTransport("XMLHTTPTransport");
}

__CPAN_FILE__ src/io/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.common");
dojo.require("dojo.string");
dojo.require("dojo.lang.extras");

/******************************************************************************
 *	Notes about dojo.io design:
 *	
 *	The dojo.io.* package has the unenviable task of making a lot of different
 *	types of I/O feel natural, despite a universal lack of good (or even
 *	reasonable!) I/O capability in the host environment. So lets pin this down
 *	a little bit further.
 *
 *	Rhino:
 *		perhaps the best situation anywhere. Access to Java classes allows you
 *		to do anything one might want in terms of I/O, both synchronously and
 *		async. Can open TCP sockets and perform low-latency client/server
 *		interactions. HTTP transport is available through Java HTTP client and
 *		server classes. Wish it were always this easy.
 *
 *	xpcshell:
 *		XPCOM for I/O.
 *
 *	spidermonkey:
 *		S.O.L.
 *
 *	Browsers:
 *		Browsers generally do not provide any useable filesystem access. We are
 *		therefore limited to HTTP for moving information to and from Dojo
 *		instances living in a browser.
 *
 *		XMLHTTP:
 *			Sync or async, allows reading of arbitrary text files (including
 *			JS, which can then be eval()'d), writing requires server
 *			cooperation and is limited to HTTP mechanisms (POST and GET).
 *
 *		<iframe> hacks:
 *			iframe document hacks allow browsers to communicate asynchronously
 *			with a server via HTTP POST and GET operations. With significant
 *			effort and server cooperation, low-latency data transit between
 *			client and server can be acheived via iframe mechanisms (repubsub).
 *
 *		SVG:
 *			Adobe's SVG viewer implements helpful primitives for XML-based
 *			requests, but receipt of arbitrary text data seems unlikely w/o
 *			<![CDATA[]]> sections.
 *
 *
 *	A discussion between Dylan, Mark, Tom, and Alex helped to lay down a lot
 *	the IO API interface. A transcript of it can be found at:
 *		http://dojotoolkit.org/viewcvs/viewcvs.py/documents/irc/irc_io_api_log.txt?rev=307&view=auto
 *	
 *	Also referenced in the design of the API was the DOM 3 L&S spec:
 *		http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html
 ******************************************************************************/

// a map of the available transport options. Transports should add themselves
// by calling add(name)
dojo.io.transports = [];
dojo.io.hdlrFuncNames = [ "load", "error", "timeout" ]; // we're omitting a progress() event for now

dojo.io.Request = function(/*String*/ url, /*String*/ mimetype, /*String*/ transport, /*String or Boolean*/ changeUrl){
// summary:
//		Constructs a Request object that is used by dojo.io.bind(). dojo.io.bind() will create one of these for you if
//		you call dojo.io.bind() with an plain object containing the bind parameters.
//		This method can either take the arguments specified, or an Object containing all of the parameters that you
//		want to use to create the dojo.io.Request (similar to how dojo.io.bind() is called.
//		The named parameters to this constructor represent the minimum set of parameters need
	if((arguments.length == 1)&&(arguments[0].constructor == Object)){
		this.fromKwArgs(arguments[0]);
	}else{
		this.url = url;
		if(mimetype){ this.mimetype = mimetype; }
		if(transport){ this.transport = transport; }
		if(arguments.length >= 4){ this.changeUrl = changeUrl; }
	}
}

dojo.lang.extend(dojo.io.Request, {

	/** The URL to hit */
	url: "",
	
	/** The mime type used to interrpret the response body */
	mimetype: "text/plain",
	
	/** The HTTP method to use */
	method: "GET",
	
	/** An Object containing key-value pairs to be included with the request */
	content: undefined, // Object
	
	/** The transport medium to use */
	transport: undefined, // String
	
	/** If defined the URL of the page is physically changed */
	changeUrl: undefined, // String
	
	/** A form node to use in the request */
	formNode: undefined, // HTMLFormElement
	
	/** Whether the request should be made synchronously */
	sync: false,
	
	bindSuccess: false,

	/** Cache/look for the request in the cache before attempting to request?
	 *  NOTE: this isn't a browser cache, this is internal and would only cache in-page
	 */
	useCache: false,

	/** Prevent the browser from caching this by adding a query string argument to the URL */
	preventCache: false,
	
	// events stuff
	load: function(/*String*/ type, /*Object*/ data, /*Object*/ transportImplementation, /*Object*/ kwArgs){
		// summary:
		//		Called on successful completion of a bind.
		//		type:
		//				A string with value "load"
		//		data:
		//				The object representing the result of the bind. The actual structure
		//				of the data object will depend on the mimetype that was given to bind
		//				in the bind arguments.
		//		transportImplementation:
		//				The object that implements a particular transport. Structure is depedent
		//				on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
		//				XMLHttpRequest object from the browser.
		//		kwArgs:
		//				Object that contains the request parameters that were given to the
		//				bind call. Useful for storing and retrieving state from when bind
		//				was called.
	},
	error: function(/*String*/ type, /*Object*/ error, /*Object*/ transportImplementation, /*Object*/ kwArgs){
		// summary:
		//		Called when there is an error with a bind.
		//		type:
		//				A string with value "error"
		//		error:
		//				The error object. Should be a dojo.io.Error object, but not guaranteed.
		//		transportImplementation:
		//				The object that implements a particular transport. Structure is depedent
		//				on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
		//				XMLHttpRequest object from the browser.
		//		kwArgs:
		//				Object that contains the request parameters that were given to the
		//				bind call. Useful for storing and retrieving state from when bind
		//				was called.
	},
	timeout: function(/*String*/ type, /*Object*/ empty, /*Object*/ transportImplementation, /*Object*/ kwArgs){
		// summary:
		//		Called when there is an error with a bind. Only implemented in certain transports at this time.
		//		type:
		//				A string with value "timeout"
		//		empty:
		//				Should be null. Just a spacer argument so that load, error, timeout and handle have the
		//				same signatures.
		//		transportImplementation:
		//				The object that implements a particular transport. Structure is depedent
		//				on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
		//				XMLHttpRequest object from the browser. May be null for the timeout case for
		//				some transports.
		//		kwArgs:
		//				Object that contains the request parameters that were given to the
		//				bind call. Useful for storing and retrieving state from when bind
		//				was called.
	},
	handle: function(/*String*/ type, /*Object*/ data, /*Object*/ transportImplementation, /*Object*/ kwArgs){
		// summary:
		//		The handle method can be defined instead of defining separate load, error and timeout
		//		callbacks.
		//		type:
		//				A string with the type of callback: "load", "error", or "timeout".
		//		data:
		//				See the above callbacks for what this parameter could be.
		//		transportImplementation:
		//				The object that implements a particular transport. Structure is depedent
		//				on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
		//				XMLHttpRequest object from the browser.
		//		kwArgs:
		//				Object that contains the request parameters that were given to the
		//				bind call. Useful for storing and retrieving state from when bind
		//				was called.	
	},

	//FIXME: change IframeIO.js to use timeouts?
	// The number of seconds to wait until firing a timeout callback.
	// If it is zero, that means, don't do a timeout check.
	timeoutSeconds: 0,
	
	// the abort method needs to be filled in by the transport that accepts the
	// bind() request
	abort: function(){ },
	
	// backButton: function(){ },
	// forwardButton: function(){ },

	fromKwArgs: function(/*Object*/ kwArgs){
		// summary:
		//		Creates a dojo.io.Request from a simple object (kwArgs object).

		// normalize args
		if(kwArgs["url"]){ kwArgs.url = kwArgs.url.toString(); }
		if(kwArgs["formNode"]) { kwArgs.formNode = dojo.byId(kwArgs.formNode); }
		if(!kwArgs["method"] && kwArgs["formNode"] && kwArgs["formNode"].method) {
			kwArgs.method = kwArgs["formNode"].method;
		}
		
		// backwards compatibility
		if(!kwArgs["handle"] && kwArgs["handler"]){ kwArgs.handle = kwArgs.handler; }
		if(!kwArgs["load"] && kwArgs["loaded"]){ kwArgs.load = kwArgs.loaded; }
		if(!kwArgs["changeUrl"] && kwArgs["changeURL"]) { kwArgs.changeUrl = kwArgs.changeURL; }

		// encoding fun!
		kwArgs.encoding = dojo.lang.firstValued(kwArgs["encoding"], djConfig["bindEncoding"], "");

		kwArgs.sendTransport = dojo.lang.firstValued(kwArgs["sendTransport"], djConfig["ioSendTransport"], false);

		var isFunction = dojo.lang.isFunction;
		for(var x=0; x<dojo.io.hdlrFuncNames.length; x++){
			var fn = dojo.io.hdlrFuncNames[x];
			if(kwArgs[fn] && isFunction(kwArgs[fn])){ continue; }
			if(kwArgs["handle"] && isFunction(kwArgs["handle"])){
				kwArgs[fn] = kwArgs.handle;
			}
			// handler is aliased above, shouldn't need this check
			/* else if(dojo.lang.isObject(kwArgs.handler)){
				if(isFunction(kwArgs.handler[fn])){
					kwArgs[fn] = kwArgs.handler[fn]||kwArgs.handler["handle"]||function(){};
				}
			}*/
		}
		dojo.lang.mixin(this, kwArgs);
	}

});

dojo.io.Error = function(/*String*/ msg, /*String*/ type, /*Number*/num){
	// summary:
	//		Constructs an object representing a bind error.
	this.message = msg;
	this.type =  type || "unknown"; // must be one of "io", "parse", "unknown"
	this.number = num || 0; // per-substrate error number, not normalized
}

dojo.io.transports.addTransport = function(name){
	// summary:
	//		Used to register transports that can support bind calls.
	this.push(name);
	// FIXME: do we need to handle things that aren't direct children of the
	// dojo.io module? (say, dojo.io.foo.fooTransport?)
	this[name] = dojo.io[name];
}

// binding interface, the various implementations register their capabilities
// and the bind() method dispatches
dojo.io.bind = function(/*Object*/ request){
	// summary:
	//		Binding interface for IO. Loading different IO transports, like
	//		dojo.io.BrowserIO or dojo.io.IframeIO will register with bind
	//		to handle particular types of bind calls.
	//		request:
	//				Object containing bind arguments. This object is converted to
	//				a dojo.io.Request object, and that request object is the return
	//				value for this method.
	if(!(request instanceof dojo.io.Request)){
		try{
			request = new dojo.io.Request(request);
		}catch(e){ dojo.debug(e); }
	}

	// if the request asks for a particular implementation, use it
	var tsName = "";
	if(request["transport"]){
		tsName = request["transport"];
		if(!this[tsName]){
			dojo.io.sendBindError(request, "No dojo.io.bind() transport with name '"
				+ request["transport"] + "'.");
			return request; //dojo.io.Request
		}
		if(!this[tsName].canHandle(request)){
			dojo.io.sendBindError(request, "dojo.io.bind() transport with name '"
				+ request["transport"] + "' cannot handle this type of request.");
			return request;	//dojo.io.Request
		}
	}else{
		// otherwise we do our best to auto-detect what available transports
		// will handle 
		for(var x=0; x<dojo.io.transports.length; x++){
			var tmp = dojo.io.transports[x];
			if((this[tmp])&&(this[tmp].canHandle(request))){
				tsName = tmp;
				break;
			}
		}
		if(tsName == ""){
			dojo.io.sendBindError(request, "None of the loaded transports for dojo.io.bind()"
				+ " can handle the request.");
			return request; //dojo.io.Request
		}
	}
	this[tsName].bind(request);
	request.bindSuccess = true;
	return request; //dojo.io.Request
}

dojo.io.sendBindError = function(request /* Object */, message /* String */){
	// summary:
	//		Used internally by dojo.io.bind() to return/raise a bind error.

	//Need to be careful since not all hostenvs support setTimeout.
	if((typeof request.error == "function" || typeof request.handle == "function")
		&& (typeof setTimeout == "function" || typeof setTimeout == "object")){
		var errorObject = new dojo.io.Error(message);
		setTimeout(function(){
			request[(typeof request.error == "function") ? "error" : "handle"]("error", errorObject, null, request);
		}, 50);
	}else{
		dojo.raise(message);
	}
}

dojo.io.queueBind = function(/* Object */ request){
	// summary:
	//		queueBind will use dojo.io.bind() but guarantee that only one bind
	//		call is handled at a time. If queueBind is called while a bind call
	//		is in process, it will queue up the other calls to bind and call them
	//		in order as bind calls complete.
	//		request:
	//			Same sort of request object as used for dojo.io.bind().
	if(!(request instanceof dojo.io.Request)){
		try{
			request = new dojo.io.Request(request);
		}catch(e){ dojo.debug(e); }
	}

	// make sure we get called if/when we get a response
	var oldLoad = request.load;
	request.load = function(){
		dojo.io._queueBindInFlight = false;
		var ret = oldLoad.apply(this, arguments);
		dojo.io._dispatchNextQueueBind();
		return ret;
	}

	var oldErr = request.error;
	request.error = function(){
		dojo.io._queueBindInFlight = false;
		var ret = oldErr.apply(this, arguments);
		dojo.io._dispatchNextQueueBind();
		return ret;
	}

	dojo.io._bindQueue.push(request);
	dojo.io._dispatchNextQueueBind();
	return request; //dojo.io.Request
}

dojo.io._dispatchNextQueueBind = function(){
	// summary:
	//	Private method used by dojo.io.queueBind().
	if(!dojo.io._queueBindInFlight){
		dojo.io._queueBindInFlight = true;
		if(dojo.io._bindQueue.length > 0){
			dojo.io.bind(dojo.io._bindQueue.shift());
		}else{
			dojo.io._queueBindInFlight = false;
		}
	}
}
dojo.io._bindQueue = [];
dojo.io._queueBindInFlight = false;

dojo.io.argsFromMap = function(/*Object*/ map, /*String*/ encoding, /*String*/ last){
	// summary:
	//		Converts name/values pairs in the map object to an URL-encoded string
	//		with format of name1=value1&name2=value2...
	//		map:
	//			Object that has the contains the names and values.
	//		encoding:
	//			String to specify how to encode the name and value. If the encoding string
	//			contains "utf" (case-insensitive), then encodeURIComponent is used. Otherwise
	//			dojo.string.encodeAscii is used.
	//		last:
	//			The last parameter in the list. Helps with final string formatting?
	var enc = /utf/i.test(encoding||"") ? encodeURIComponent : dojo.string.encodeAscii;
	var mapped = [];
	var control = new Object();
	for(var name in map){
		var domap = function(elt){
			var val = enc(name)+"="+enc(elt);
			mapped[(last == name) ? "push" : "unshift"](val);
		}
		if(!control[name]){
			var value = map[name];
			// FIXME: should be isArrayLike?
			if (dojo.lang.isArray(value)){
				dojo.lang.forEach(value, domap);
			}else{
				domap(value);
			}
		}
	}
	return mapped.join("&"); //String
}

dojo.io.setIFrameSrc = function(/*DOMNode*/ iframe, /*String*/ src, /*Boolean*/ replace){
	//summary:
	//		Sets the URL that is loaded in an IFrame. The replace parameter indicates whether
	//		location.replace() should be used when changing the location of the iframe.
	try{
		var r = dojo.render.html;
		// dojo.debug(iframe);
		if(!replace){
			if(r.safari){
				iframe.location = src;
			}else{
				frames[iframe.name].location = src;
			}
		}else{
			// Fun with DOM 0 incompatibilities!
			var idoc;
			if(r.ie){
				idoc = iframe.contentWindow.document;
			}else if(r.safari){
				idoc = iframe.document;
			}else{ //  if(r.moz){
				idoc = iframe.contentWindow;
			}

			//For Safari (at least 2.0.3) and Opera, if the iframe
			//has just been created but it doesn't have content
			//yet, then iframe.document may be null. In that case,
			//use iframe.location and return.
			if(!idoc){
				iframe.location = src;
				return;
			}else{
				idoc.location.replace(src);
			}
		}
	}catch(e){ 
		dojo.debug(e); 
		dojo.debug("setIFrameSrc: "+e); 
	}
}

/*
dojo.io.sampleTranport = new function(){
	this.canHandle = function(kwArgs){
		// canHandle just tells dojo.io.bind() if this is a good transport to
		// use for the particular type of request.
		if(	
			(
				(kwArgs["mimetype"] == "text/plain") ||
				(kwArgs["mimetype"] == "text/html") ||
				(kwArgs["mimetype"] == "text/javascript")
			)&&(
				(kwArgs["method"] == "get") ||
				( (kwArgs["method"] == "post") && (!kwArgs["formNode"]) )
			)
		){
			return true;
		}

		return false;
	}

	this.bind = function(kwArgs){
		var hdlrObj = {};

		// set up a handler object
		for(var x=0; x<dojo.io.hdlrFuncNames.length; x++){
			var fn = dojo.io.hdlrFuncNames[x];
			if(typeof kwArgs.handler == "object"){
				if(typeof kwArgs.handler[fn] == "function"){
					hdlrObj[fn] = kwArgs.handler[fn]||kwArgs.handler["handle"];
				}
			}else if(typeof kwArgs[fn] == "function"){
				hdlrObj[fn] = kwArgs[fn];
			}else{
				hdlrObj[fn] = kwArgs["handle"]||function(){};
			}
		}

		// build a handler function that calls back to the handler obj
		var hdlrFunc = function(evt){
			if(evt.type == "onload"){
				hdlrObj.load("load", evt.data, evt);
			}else if(evt.type == "onerr"){
				var errObj = new dojo.io.Error("sampleTransport Error: "+evt.msg);
				hdlrObj.error("error", errObj);
			}
		}

		// the sample transport would attach the hdlrFunc() when sending the
		// request down the pipe at this point
		var tgtURL = kwArgs.url+"?"+dojo.io.argsFromMap(kwArgs.content);
		// sampleTransport.sendRequest(tgtURL, hdlrFunc);
	}

	dojo.io.transports.addTransport("sampleTranport");
}
*/

__CPAN_FILE__ src/io/cometd.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.io.common"); // io/common.js provides setIFrameSrc and the IO module
dojo.provide("dojo.io.cometd");
dojo.require("dojo.AdapterRegistry");
dojo.require("dojo.json");
dojo.require("dojo.io.BrowserIO"); // we need XHR for the handshake, etc.
// FIXME: determine if we can use XMLHTTP to make x-domain posts despite not
//        being able to hear back about the result
dojo.require("dojo.io.IframeIO");
dojo.require("dojo.io.ScriptSrcIO"); // for x-domain long polling
dojo.require("dojo.io.cookie"); // for peering
dojo.require("dojo.event.*");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");

/*
 * this file defines Comet protocol client. Actual message transport is
 * deferred to one of several connection type implementations. The default is a
 * forever-frame implementation. A single global object named "cometd" is
 * used to mediate for these connection types in order to provide a stable
 * interface.
 */

// TODO: the auth handling in this file is a *mess*. It should probably live in
// the cometd object with the ability to mix in or call down to an auth-handler
// object, the prototypical variant of which is a no-op

cometd = new function(){

	this.initialized = false;
	this.connected = false;

	this.connectionTypes = new dojo.AdapterRegistry(true);

	this.version = 0.1;
	this.minimumVersion = 0.1;
	this.clientId = null;

	this._isXD = false;
	this.handshakeReturn = null;
	this.currentTransport = null;
	this.url = null;
	this.lastMessage = null;
	this.globalTopicChannels = {};
	this.backlog = [];

	this.tunnelInit = function(childLocation, childDomain){
		// placeholder
	}

	this.tunnelCollapse = function(){
		dojo.debug("tunnel collapsed!");
		// placeholder
	}

	this.init = function(props, root, bargs){
		// FIXME: if the root isn't from the same host, we should automatically
		// try to select an XD-capable transport
		props = props||{};
		// go ask the short bus server what we can support
		props.version = this.version;
		props.minimumVersion = this.minimumVersion;
		props.channel = "/meta/handshake";
		// FIXME: do we just assume that the props knows
		// everything we care about WRT to auth? Should we be trying to
		// call back into it for subsequent auth actions? Should we fire
		// local auth functions to ask for/get auth data?

		// FIXME: what about ScriptSrcIO for x-domain comet?
		this.url = root||djConfig["cometdRoot"];
		if(!this.url){
			dojo.debug("no cometd root specified in djConfig and no root passed");
			return;
		}
		
		// FIXME: we need to select a way to handle JSONP-style stuff
		// generically here. We already know if the server is gonna be on
		// another domain (or can know it), so we should select appropriate
		// negotiation methods here as well as in final transport type
		// selection.
		var bindArgs = {
			url: this.url,
			method: "POST",
			mimetype: "text/json",
			load: dojo.lang.hitch(this, "finishInit"),
			content: { "message": dojo.json.serialize([props]) }
		};

		// borrowed from dojo.uri.Uri in lieu of fixed host and port properties
        var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
		var r = (""+window.location).match(new RegExp(regexp));
		if(r[4]){
			var tmp = r[4].split(":");
			var thisHost = tmp[0];
			var thisPort = tmp[1]||"80"; // FIXME: match 443

			r = this.url.match(new RegExp(regexp));
			if(r[4]){
				tmp = r[4].split(":");
				var urlHost = tmp[0];
				var urlPort = tmp[1]||"80";
				if(	(urlHost != thisHost)||
					(urlPort != thisPort) ){
					dojo.debug(thisHost, urlHost);
					dojo.debug(thisPort, urlPort);

					this._isXD = true;
					bindArgs.transport = "ScriptSrcTransport";
					bindArgs.jsonParamName = "jsonp";
					bindArgs.method = "GET";
				}
			}
		}
		if(bargs){
			dojo.lang.mixin(bindArgs, bargs);
		}
		return dojo.io.bind(bindArgs);
	}

	this.finishInit = function(type, data, evt, request){
		data = data[0];
		this.handshakeReturn = data;
		// pick a transport
		if(data["authSuccessful"] == false){
			dojo.debug("cometd authentication failed");
			return;
		}
		if(data.version < this.minimumVersion){
			dojo.debug("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version);
			return;
		}
		this.currentTransport = this.connectionTypes.match(
			data.supportedConnectionTypes,
			data.version,
			this._isXD
		);
		this.currentTransport.version = data.version;
		this.clientId = data.clientId;
		this.tunnelInit = dojo.lang.hitch(this.currentTransport, "tunnelInit");
		this.tunnelCollapse = dojo.lang.hitch(this.currentTransport, "tunnelCollapse");
		this.initialized = true;
		this.currentTransport.startup(data);
		while(this.backlog.length != 0){
			var cur = this.backlog.shift();
			var fn = cur.shift();
			this[fn].apply(this, cur);
		}
	}

	this._getRandStr = function(){
		return Math.random().toString().substring(2, 10);
	}

	// public API functions called by cometd or by the transport classes
	this.deliver = function(messages){
		dojo.lang.forEach(messages, this._deliver, this);
	}

	this._deliver = function(message){
		// dipatch events along the specified path
		if(!message["channel"]){
			dojo.debug("cometd error: no channel for message!");
			return;
		}
		if(!this.currentTransport){
			this.backlog.push(["deliver", message]);
			return;
		}
		this.lastMessage = message;
		// check to see if we got a /meta channel message that we care about
		if(	(message.channel.length > 5)&&
			(message.channel.substr(0, 5) == "/meta")){
			// check for various meta topic actions that we need to respond to
			switch(message.channel){
				case "/meta/subscribe":
					if(!message.successful){
						dojo.debug("cometd subscription error for channel", message.channel, ":", message.error);
						return;
					}
					this.subscribed(message.subscription, message);
					break;
				case "/meta/unsubscribe":
					if(!message.successful){
						dojo.debug("cometd unsubscription error for channel", message.channel, ":", message.error);
						return;
					}
					this.unsubscribed(message.subscription, message);
					break;
			}
		}
		// send the message down for processing by the transport
		this.currentTransport.deliver(message);

		// dispatch the message to any locally subscribed listeners
		var tname = (this.globalTopicChannels[message.channel]) ? message.channel : "/cometd"+message.channel;
		dojo.event.topic.publish(tname, message);
	}

	this.disconnect = function(){
		if(!this.currentTransport){
			dojo.debug("no current transport to disconnect from");
			return;
		}
		this.currentTransport.disconnect();
	}

	// public API functions called by end users
	this.publish = function(/*string*/channel, /*object*/data, /*object*/properties){
		// summary: 
		//		publishes the passed message to the cometd server for delivery
		//		on the specified topic
		// channel:
		//		the destination channel for the message
		// data:
		//		a JSON object containing the message "payload"
		// properties:
		//		Optional. Other meta-data to be mixed into the top-level of the
		//		message
		if(!this.currentTransport){
			this.backlog.push(["publish", channel, data, properties]);
			return;
		}
		var message = {
			data: data,
			channel: channel
		};
		if(properties){
			dojo.lang.mixin(message, properties);
		}
		return this.currentTransport.sendMessage(message);
	}

	this.subscribe = function(	/*string*/				channel, 
								/*boolean, optional*/	useLocalTopics, 
								/*object, optional*/	objOrFunc, 
								/*string, optional*/	funcName){ // return: boolean
		// summary:
		//		inform the server of this client's interest in channel
		// channel:
		//		name of the cometd channel to subscribe to
		// useLocalTopics:
		//		Determines if up a local event topic subscription to the passed
		//		function using the channel name that was passed is constructed,
		//		or if the topic name will be prefixed with some other
		//		identifier for local message distribution. Setting this to
		//		"true" is a good way to hook up server-sent message delivery to
		//		pre-existing local topics.
		// objOrFunc:
		//		an object scope for funcName or the name or reference to a
		//		function to be called when messages are delivered to the
		//		channel
		// funcName:
		//		the second half of the objOrFunc/funcName pair for identifying
		//		a callback function to notifiy upon channel message delivery
		if(!this.currentTransport){
			this.backlog.push(["subscribe", channel, useLocalTopics, objOrFunc, funcName]);
			return;
		}
		if(objOrFunc){
			var tname = (useLocalTopics) ? channel : "/cometd"+channel;
			if(useLocalTopics){
				this.globalTopicChannels[channel] = true;
			}
			dojo.event.topic.subscribe(tname, objOrFunc, funcName);
		}
		// FIXME: would we handle queuing of the subscription if not connected?
		// Or should the transport object?
		return this.currentTransport.sendMessage({
			channel: "/meta/subscribe",
			subscription: channel
		});
	}

	this.subscribed = function(	/*string*/				channel, 
								/*obj*/					message){
		dojo.debug(channel);
		dojo.debugShallow(message);
	}

	this.unsubscribe = function(/*string*/				channel, 
								/*boolean, optional*/	useLocalTopics, 
								/*object, optional*/	objOrFunc, 
								/*string, optional*/	funcName){ // return: boolean
		// summary:
		//		inform the server of this client's disinterest in channel
		// channel:
		//		name of the cometd channel to subscribe to
		// useLocalTopics:
		//		Determines if up a local event topic subscription to the passed
		//		function using the channel name that was passed is destroyed,
		//		or if the topic name will be prefixed with some other
		//		identifier for stopping message distribution.
		// objOrFunc:
		//		an object scope for funcName or the name or reference to a
		//		function to be called when messages are delivered to the
		//		channel
		// funcName:
		//		the second half of the objOrFunc/funcName pair for identifying
		if(!this.currentTransport){
			this.backlog.push(["unsubscribe", channel, useLocalTopics, objOrFunc, funcName]);
			return;
		}
		//		a callback function to notifiy upon channel message delivery
		if(objOrFunc){
			// FIXME: should actual local topic unsubscription be delayed for
			// successful unsubcribe notices from the other end? (guessing "no")
			// FIXME: if useLocalTopics is false, should we go ahead and
			// destroy the local topic?
			var tname = (useLocalTopics) ? channel : "/cometd"+channel;
			dojo.event.topic.unsubscribe(tname, objOrFunc, funcName);
		}
		return this.currentTransport.sendMessage({
			channel: "/meta/unsubscribe",
			subscription: channel
		});
	}

	this.unsubscribed = function(/*string*/				channel, 
								/*obj*/					message){
		dojo.debug(channel);
		dojo.debugShallow(message);
	}

	// FIXME: add an "addPublisher" function

}

/*
transport objects MUST expose the following methods:
	- check
	- startup
	- sendMessage
	- deliver
	- disconnect
optional, standard but transport dependent methods are:
	- tunnelCollapse
	- tunnelInit

Transports SHOULD be namespaced under the cometd object and transports MUST
register themselves with cometd.connectionTypes

here's a stub transport defintion:

cometd.blahTransport = new function(){
	this.connected = false;
	this.connectionId = null;
	this.authToken = null;
	this.lastTimestamp = null;
	this.lastId = null;

	this.check = function(types, version, xdomain){
		// summary:
		//		determines whether or not this transport is suitable given a
		//		list of transport types that the server supports
		return dojo.lang.inArray(types, "blah");
	}

	this.startup = function(){
		if(this.connected){ return; }
		// FIXME: fill in startup routine here
		this.connected = true;
	}

	this.sendMessage = function(message){
		// FIXME: fill in message sending logic
	}

	this.deliver = function(message){
		if(message["timestamp"]){
			this.lastTimestamp = message.timestamp;
		}
		if(message["id"]){
			this.lastId = message.id;
		}
		if(	(message.channel.length > 5)&&
			(message.channel.substr(0, 5) == "/meta")){
			// check for various meta topic actions that we need to respond to
			// switch(message.channel){
			// 	case "/meta/connect":
			//		// FIXME: fill in logic here
			//		break;
			//	// case ...: ...
			//	}
		}
	}

	this.disconnect = function(){
		if(!this.connected){ return; }
		// FIXME: fill in shutdown routine here
		this.connected = false;
	}
}
cometd.connectionTypes.register("blah", cometd.blahTransport.check, cometd.blahTransport);
*/

cometd.iframeTransport = new function(){
	this.connected = false;
	this.connectionId = null;

	this.rcvNode = null;
	this.rcvNodeName = "";
	this.phonyForm = null;
	this.authToken = null;
	this.lastTimestamp = null;
	this.lastId = null;
	this.backlog = [];

	this.check = function(types, version, xdomain){
		return ((!xdomain)&&
				(!dojo.render.html.safari)&&
				(dojo.lang.inArray(types, "iframe")));
	}

	this.tunnelInit = function(){
		// we've gotten our initialization document back in the iframe, so
		// now open up a connection and start passing data!
		this.postToIframe({
			message: dojo.json.serialize([
				{
					channel:	"/meta/connect",
					clientId:	cometd.clientId,
					connectionType: "iframe"
					// FIXME: auth not passed here!
					// "authToken": this.authToken
				}
			])
		});
	}

	this.tunnelCollapse = function(){
		if(this.connected){
			// try to restart the tunnel
			this.connected = false;

			this.postToIframe({
				message: dojo.json.serialize([
					{
						channel:	"/meta/reconnect",
						clientId:	cometd.clientId,
						connectionId:	this.connectionId,
						timestamp:	this.lastTimestamp,
						id:			this.lastId
						// FIXME: no authToken provision!
					}
				])
			});
		}
	}

	this.deliver = function(message){
		// handle delivery details that this transport particularly cares
		// about. Most functions of should be handled by the main cometd object
		// with only transport-specific details and state being tracked here.
		if(message["timestamp"]){
			this.lastTimestamp = message.timestamp;
		}
		if(message["id"]){
			this.lastId = message.id;
		}
		// check to see if we got a /meta channel message that we care about
		if(	(message.channel.length > 5)&&
			(message.channel.substr(0, 5) == "/meta")){
			// check for various meta topic actions that we need to respond to
			switch(message.channel){
				case "/meta/connect":
					if(!message.successful){
						dojo.debug("cometd connection error:", message.error);
						return;
					}
					this.connectionId = message.connectionId;
					this.connected = true;
					this.processBacklog();
					break;
				case "/meta/reconnect":
					if(!message.successful){
						dojo.debug("cometd reconnection error:", message.error);
						return;
					}
					this.connected = true;
					break;
				case "/meta/subscribe":
					if(!message.successful){
						dojo.debug("cometd subscription error for channel", message.channel, ":", message.error);
						return;
					}
					// this.subscribed(message.channel);
					dojo.debug(message.channel);
					break;
			}
		}
	}

	this.widenDomain = function(domainStr){
		// allow us to make reqests to the TLD
		var cd = domainStr||document.domain;
		if(cd.indexOf(".")==-1){ return; } // probably file:/// or localhost
		var dps = cd.split(".");
		if(dps.length<=2){ return; } // probably file:/// or an RFC 1918 address
		dps = dps.slice(dps.length-2);
		document.domain = dps.join(".");
		return document.domain;
	}

	this.postToIframe = function(content, url){
		if(!this.phonyForm){
			if(dojo.render.html.ie){
				this.phonyForm = document.createElement("<form enctype='application/x-www-form-urlencoded' method='POST' style='display: none;'>");
				dojo.body().appendChild(this.phonyForm);
			}else{
				this.phonyForm = document.createElement("form");
				this.phonyForm.style.display = "none"; // FIXME: will this still work?
				dojo.body().appendChild(this.phonyForm);
				this.phonyForm.enctype = "application/x-www-form-urlencoded";
				this.phonyForm.method = "POST";
			}
		}

		this.phonyForm.action = url||cometd.url;
		this.phonyForm.target = this.rcvNodeName;
		this.phonyForm.setAttribute("target", this.rcvNodeName);

		while(this.phonyForm.firstChild){
			this.phonyForm.removeChild(this.phonyForm.firstChild);
		}

		for(var x in content){
			var tn;
			if(dojo.render.html.ie){
				tn = document.createElement("<input type='hidden' name='"+x+"' value='"+content[x]+"'>");
				this.phonyForm.appendChild(tn);
			}else{
				tn = document.createElement("input");
				this.phonyForm.appendChild(tn);
				tn.type = "hidden";
				tn.name = x;
				tn.value = content[x];
			}
		}
		this.phonyForm.submit();
	}

	this.processBacklog = function(){
		while(this.backlog.length > 0){
			this.sendMessage(this.backlog.shift(), true);
		}
	}

	this.sendMessage = function(message, bypassBacklog){
		// FIXME: what about auth fields?
		if((bypassBacklog)||(this.connected)){
			message.connectionId = this.connectionId;
			message.clientId = cometd.clientId;
			var bindArgs = {
				url: cometd.url||djConfig["cometdRoot"],
				method: "POST",
				mimetype: "text/json",
				// FIXME: we should be able to do better than this given that we're sending an array!
				content: { message: dojo.json.serialize([ message ]) }
			};
			return dojo.io.bind(bindArgs);
		}else{
			this.backlog.push(message);
		}
	}

	this.startup = function(handshakeData){
		dojo.debug("startup!");
		dojo.debug(dojo.json.serialize(handshakeData));

		if(this.connected){ return; }

		// this.widenDomain();

		// NOTE: we require the server to cooperate by hosting
		// cometdInit.html at the designated endpoint
		this.rcvNodeName = "cometdRcv_"+cometd._getRandStr();
		// the "forever frame" approach

		var initUrl = cometd.url+"/?tunnelInit=iframe"; // &domain="+document.domain;
		if(false && dojo.render.html.ie){ // FIXME: DISALBED FOR NOW
			// use the "htmlfile hack" to prevent the background click junk
			this.rcvNode = new ActiveXObject("htmlfile");
			this.rcvNode.open();
			this.rcvNode.write("<html>");
			this.rcvNode.write("<script>document.domain = '"+document.domain+"'");
			this.rcvNode.write("</html>");
			this.rcvNode.close();

			var ifrDiv = this.rcvNode.createElement("div");
			this.rcvNode.appendChild(ifrDiv);
			this.rcvNode.parentWindow.dojo = dojo;
			ifrDiv.innerHTML = "<iframe src='"+initUrl+"'></iframe>"
		}else{
			this.rcvNode = dojo.io.createIFrame(this.rcvNodeName, "", initUrl);
			// dojo.io.setIFrameSrc(this.rcvNode, initUrl);
			// we're still waiting on the iframe to call back up to use and
			// advertise that it's been initialized via tunnelInit
		}
	}
}

cometd.mimeReplaceTransport = new function(){
	this.connected = false;
	this.connectionId = null;
	this.xhr = null;

	this.authToken = null;
	this.lastTimestamp = null;
	this.lastId = null;
	this.backlog = [];

	this.check = function(types, version, xdomain){
		return ((!xdomain)&&
				(dojo.render.html.mozilla)&& // seems only Moz really supports this right now = (
				(dojo.lang.inArray(types, "mime-message-block")));
	}

	this.tunnelInit = function(){
		if(this.connected){ return; }
		// FIXME: open up the connection here
		this.openTunnelWith({
			message: dojo.json.serialize([
				{
					channel:	"/meta/connect",
					clientId:	cometd.clientId,
					connectionType: "mime-message-block"
					// FIXME: auth not passed here!
					// "authToken": this.authToken
				}
			])
		});
		this.connected = true;
	}

	this.tunnelCollapse = function(){
		if(this.connected){
			// try to restart the tunnel
			this.connected = false;
			this.openTunnelWith({
				message: dojo.json.serialize([
					{
						channel:	"/meta/reconnect",
						clientId:	cometd.clientId,
						connectionId:	this.connectionId,
						timestamp:	this.lastTimestamp,
						id:			this.lastId
						// FIXME: no authToken provision!
					}
				])
			});
		}
	}

	this.deliver = cometd.iframeTransport.deliver;
	// the logic appears to be the same

	this.handleOnLoad = function(resp){
		cometd.deliver(dojo.json.evalJson(this.xhr.responseText));
	}

	this.openTunnelWith = function(content, url){
		// set up the XHR object and register the multipart callbacks
		this.xhr = dojo.hostenv.getXmlhttpObject();
		this.xhr.multipart = true; // FIXME: do Opera and Safari support this flag?
		if(dojo.render.html.mozilla){
			this.xhr.addEventListener("load", dojo.lang.hitch(this, "handleOnLoad"), false);
		}else if(dojo.render.html.safari){
			// Blah. WebKit doesn't actually populate responseText and/or responseXML. Useless.
			dojo.debug("Webkit is broken with multipart responses over XHR = (");
			this.xhr.onreadystatechange = dojo.lang.hitch(this, "handleOnLoad");
		}else{
			this.xhr.onload = dojo.lang.hitch(this, "handleOnLoad");
		}
		this.xhr.open("POST", (url||cometd.url), true); // async post
		this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		dojo.debug(dojo.json.serialize(content));
		this.xhr.send(dojo.io.argsFromMap(content, "utf8"));
	}

	this.processBacklog = function(){
		while(this.backlog.length > 0){
			this.sendMessage(this.backlog.shift(), true);
		}
	}

	this.sendMessage = function(message, bypassBacklog){
		// FIXME: what about auth fields?
		if((bypassBacklog)||(this.connected)){
			message.connectionId = this.connectionId;
			message.clientId = cometd.clientId;
			var bindArgs = {
				url: cometd.url||djConfig["cometdRoot"],
				method: "POST",
				mimetype: "text/json",
				content: { message: dojo.json.serialize([ message ]) }
			};
			return dojo.io.bind(bindArgs);
		}else{
			this.backlog.push(message);
		}
	}

	this.startup = function(handshakeData){
		dojo.debugShallow(handshakeData);
		if(this.connected){ return; }
		this.tunnelInit();
	}
}

cometd.longPollTransport = new function(){
	this.connected = false;
	this.connectionId = null;

	this.authToken = null;
	this.lastTimestamp = null;
	this.lastId = null;
	this.backlog = [];

	this.check = function(types, version, xdomain){
		return ((!xdomain)&&(dojo.lang.inArray(types, "long-polling")));
	}

	this.tunnelInit = function(){
		if(this.connected){ return; }
		// FIXME: open up the connection here
		this.openTunnelWith({
			message: dojo.json.serialize([
				{
					channel:	"/meta/connect",
					clientId:	cometd.clientId,
					connectionType: "long-polling"
					// FIXME: auth not passed here!
					// "authToken": this.authToken
				}
			])
		});
		this.connected = true;
	}

	this.tunnelCollapse = function(){
		if(!this.connected){
			// try to restart the tunnel
			this.connected = false;
			dojo.debug("clientId:", cometd.clientId);
			this.openTunnelWith({
				message: dojo.json.serialize([
					{
						channel:	"/meta/reconnect",
						connectionType: "long-polling",
						clientId:	cometd.clientId,
						connectionId:	this.connectionId,
						timestamp:	this.lastTimestamp,
						id:			this.lastId
						// FIXME: no authToken provision!
					}
				])
			});
		}
	}

	this.deliver = cometd.iframeTransport.deliver;
	// the logic appears to be the same

	this.openTunnelWith = function(content, url){
		dojo.io.bind({
			url: (url||cometd.url),
			method: "post",
			content: content,
			mimetype: "text/json",
			load: dojo.lang.hitch(this, function(type, data, evt, args){
				// dojo.debug(evt.responseText);
				cometd.deliver(data);
				this.connected = false;
				this.tunnelCollapse();
			}),
			error: function(){ dojo.debug("tunnel opening failed"); }
		});
		this.connected = true;
	}

	this.processBacklog = function(){
		while(this.backlog.length > 0){
			this.sendMessage(this.backlog.shift(), true);
		}
	}

	this.sendMessage = function(message, bypassBacklog){
		// FIXME: what about auth fields?
		if((bypassBacklog)||(this.connected)){
			message.connectionId = this.connectionId;
			message.clientId = cometd.clientId;
			var bindArgs = {
				url: cometd.url||djConfig["cometdRoot"],
				method: "post",
				mimetype: "text/json",
				content: { message: dojo.json.serialize([ message ]) }
			};
			return dojo.io.bind(bindArgs);
		}else{
			this.backlog.push(message);
		}
	}

	this.startup = function(handshakeData){
		if(this.connected){ return; }
		this.tunnelInit();
	}
}

cometd.callbackPollTransport = new function(){
	this.connected = false;
	this.connectionId = null;

	this.authToken = null;
	this.lastTimestamp = null;
	this.lastId = null;
	this.backlog = [];

	this.check = function(types, version, xdomain){
		// we handle x-domain!
		return dojo.lang.inArray(types, "callback-polling");
	}

	this.tunnelInit = function(){
		if(this.connected){ return; }
		// FIXME: open up the connection here
		this.openTunnelWith({
			message: dojo.json.serialize([
				{
					channel:	"/meta/connect",
					clientId:	cometd.clientId,
					connectionType: "callback-polling"
					// FIXME: auth not passed here!
					// "authToken": this.authToken
				}
			])
		});
		this.connected = true;
	}

	this.tunnelCollapse = function(){
		if(!this.connected){
			// try to restart the tunnel
			this.connected = false;
			this.openTunnelWith({
				message: dojo.json.serialize([
					{
						channel:	"/meta/reconnect",
						connectionType: "long-polling",
						clientId:	cometd.clientId,
						connectionId:	this.connectionId,
						timestamp:	this.lastTimestamp,
						id:			this.lastId
						// FIXME: no authToken provision!
					}
				])
			});
		}
	}

	this.deliver = cometd.iframeTransport.deliver;
	// the logic appears to be the same

	this.openTunnelWith = function(content, url){
		// create a <script> element to generate the request
		var req = dojo.io.bind({
			url: (url||cometd.url),
			content: content,
			mimetype: "text/json",
			transport: "ScriptSrcTransport",
			jsonParamName: "jsonp",
			load: dojo.lang.hitch(this, function(type, data, evt, args){
				dojo.debug(dojo.json.serialize(data));
				cometd.deliver(data);
				this.connected = false;
				this.tunnelCollapse();
			}),
			error: function(){ dojo.debug("tunnel opening failed"); }
		});
		this.connected = true;
	}

	this.processBacklog = function(){
		while(this.backlog.length > 0){
			this.sendMessage(this.backlog.shift(), true);
		}
	}

	this.sendMessage = function(message, bypassBacklog){
		// FIXME: what about auth fields?
		if((bypassBacklog)||(this.connected)){
			message.connectionId = this.connectionId;
			message.clientId = cometd.clientId;
			var bindArgs = {
				url: cometd.url||djConfig["cometdRoot"],
				mimetype: "text/json",
				transport: "ScriptSrcTransport",
				jsonParamName: "jsonp",
				content: { message: dojo.json.serialize([ message ]) }
			};
			return dojo.io.bind(bindArgs);
		}else{
			this.backlog.push(message);
		}
	}

	this.startup = function(handshakeData){
		if(this.connected){ return; }
		this.tunnelInit();
	}
}

cometd.connectionTypes.register("mime-message-block", cometd.mimeReplaceTransport.check, cometd.mimeReplaceTransport);
cometd.connectionTypes.register("long-polling", cometd.longPollTransport.check, cometd.longPollTransport);
cometd.connectionTypes.register("callback-polling", cometd.callbackPollTransport.check, cometd.callbackPollTransport);
cometd.connectionTypes.register("iframe", cometd.iframeTransport.check, cometd.iframeTransport);

// FIXME: need to implement fallback-polling, IE XML block

dojo.io.cometd = cometd;

__CPAN_FILE__ src/io/XhrIframeProxy.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.XhrIframeProxy");

dojo.require("dojo.experimental");
dojo.experimental("dojo.io.XhrIframeProxy");

dojo.require("dojo.io.IframeIO");
dojo.require("dojo.html.iframe");
dojo.require("dojo.dom");
dojo.require("dojo.uri.Uri");

/*
TODO: This page might generate a "loading unsecure items on a secure page"
popup in browsers if it is served on a https URL, given that we are not
setting a src on the iframe element.
//TODO: Document that it doesn't work from local disk in Safari.

*/

dojo.io.XhrIframeProxy = new function(){
	this.xipClientUrl = dojo.uri.dojoUri("src/io/xip_client.html");

	this._state = {};
	this._stateIdCounter = 0;

	this.send = function(facade){		
		var stateId = "XhrIframeProxy" + (this._stateIdCounter++);
		facade._stateId = stateId;

		this._state[stateId] = {
			facade: facade,
			stateId: stateId,
			clientFrame: dojo.io.createIFrame(stateId,
				"dojo.io.XhrIframeProxy.clientFrameLoaded('" + stateId + "');",
				this.xipClientUrl)
		};
	}
	
	this.receive = function(stateId, urlEncodedData){
		/* urlEncodedData should have the following params:
				- responseHeaders
				- status
				- statusText
				- responseText
		*/
		//Decode response data.
		var response = {};
		var nvPairs = urlEncodedData.split("&");
		for(var i = 0; i < nvPairs.length; i++){
			if(nvPairs[i]){
				var nameValue = nvPairs[i].split("=");
				response[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
			}
		}

		//Set data on facade object.
		var state = this._state[stateId];
		var facade = state.facade;

		facade._setResponseHeaders(response.responseHeaders);
		if(response.status == 0 || response.status){
			facade.status = parseInt(response.status, 10);
		}
		if(response.statusText){
			facade.statusText = response.statusText;
		}
		if(response.responseText){
			facade.responseText = response.responseText;
			
			//Fix responseXML.
			var contentType = facade.getResponseHeader("Content-Type");
			if(contentType && (contentType == "application/xml" || contentType == "text/xml")){
				facade.responseXML = dojo.dom.createDocumentFromText(response.responseText, contentType);
			}
		}
		facade.readyState = 4;
		
		this.destroyState(stateId);
	}

	this.clientFrameLoaded = function(stateId){
		var state = this._state[stateId];
		var facade = state.facade;
		var clientWindow = dojo.html.iframeContentWindow(state.clientFrame);
		
		var reqHeaders = [];
		for(var param in facade._requestHeaders){
			reqHeaders.push(param + ": " + facade._requestHeaders[param]);
		}
		
		var requestData = {
			uri: facade._uri
		};
		if(reqHeaders.length > 0){
			requestData.requestHeaders = reqHeaders.join("\r\n");		
		}
		if(facade._method){
			requestData.method = facade._method;
		}
		if(facade._bodyData){
			requestData.data = facade._bodyData;
		}

		clientWindow.send(stateId, facade._ifpServerUrl, dojo.io.argsFromMap(requestData, "utf8"));
	}
	
	this.destroyState = function(stateId){
		var state = this._state[stateId];
		if(state){
			delete this._state[stateId];
			var parentNode = state.clientFrame.parentNode;
			parentNode.removeChild(state.clientFrame);
			state.clientFrame = null;
			state = null;
		}
	}

	this.createFacade = function(){
		if(arguments && arguments[0] && arguments[0]["iframeProxyUrl"]){
			return new dojo.io.XhrIframeFacade(arguments[0]["iframeProxyUrl"]);
		}else{
			return dojo.io.XhrIframeProxy.oldGetXmlhttpObject.apply(dojo.hostenv, arguments);
		}
	}
}

//Replace the normal XHR factory with the proxy one.
dojo.io.XhrIframeProxy.oldGetXmlhttpObject = dojo.hostenv.getXmlhttpObject;
dojo.hostenv.getXmlhttpObject = dojo.io.XhrIframeProxy.createFacade;

/**
	Using this a reference: http://www.w3.org/TR/XMLHttpRequest/

	Does not implement the onreadystate callback since dojo.io.BrowserIO does
	not use it.
*/
dojo.io.XhrIframeFacade = function(ifpServerUrl){
	this._requestHeaders = {};
	this._allResponseHeaders = null;
	this._responseHeaders = {};
	this._method = null;
	this._uri = null;
	this._bodyData = null;
	this.responseText = null;
	this.responseXML = null;
	this.status = null;
	this.statusText = null;
	this.readyState = 0;
	
	this._ifpServerUrl = ifpServerUrl;
	this._stateId = null;
}

dojo.lang.extend(dojo.io.XhrIframeFacade, {
	//The open method does not properly reset since Dojo does not reuse XHR objects.
	open: function(method, uri){
		this._method = method;
		this._uri = uri;

		this.readyState = 1;
	},
	
	setRequestHeader: function(header, value){
		this._requestHeaders[header] = value;
	},
	
	send: function(stringData){
		this._bodyData = stringData;
		
		dojo.io.XhrIframeProxy.send(this);
		
		this.readyState = 2;
	},
	abort: function(){
		dojo.io.XhrIframeProxy.destroyState(this._stateId);
	},
	
	getAllResponseHeaders: function(){
		return this._allResponseHeaders;

	},
	
	getResponseHeader: function(header){
		return this._responseHeaders[header];
	},
	
	_setResponseHeaders: function(allHeaders){
		if(allHeaders){
			this._allResponseHeaders = allHeaders;
			
			//Make sure ther are now CR characters in the headers.
			allHeaders = allHeaders.replace(/\r/g, "");
			var nvPairs = allHeaders.split("\n");
			for(var i = 0; i < nvPairs.length; i++){
				if(nvPairs[i]){
					var nameValue = nvPairs[i].split(": ");
					this._responseHeaders[nameValue[0]] = nameValue[1];
				}
			}
		}
	}
});

__CPAN_FILE__ src/io/RhinoIO.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.RhinoIO");

dojo.require("dojo.io.common");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.array");
dojo.require("dojo.string.extras");

dojo.io.RhinoHTTPTransport = new function(){
		this.canHandle = function(req){
			// We have to limit to text types because Rhino doesnt support 
			// a W3C dom implementation out of the box.  In the future we 
			// should provide some kind of hook to inject your own, because
			// in all my projects I use XML for Script to provide a W3C DOM.
			if(!dojo.lang.inArray((req.mimetype.toLowerCase() || ""),
				["text/plain", "text/html", "text/javascript", "text/json", "application/json"])){
				return false;
			}
			
			// We only handle http requests!  Unfortunately, because the method is 
			// protected, I can't directly create a java.net.HttpURLConnection, so
			// this is the only way to test.
			if(req.url.substr(0, 7) != "http://"){
				return false;
			}
			
			return true;
		}

		function doLoad(req, conn){
			var ret;
			if (req.method.toLowerCase() == "head"){
				// TODO: return the headers
			}else{
				var stream = conn.getContent();
				var reader = new java.io.BufferedReader(new java.io.InputStreamReader(stream));

				// read line-by-line because why not?
				var text = "";
				var line = null;
				while((line = reader.readLine()) != null){
					text += line;
				}

				if(req.mimetype == "text/javascript"){
					try{
						ret = dj_eval(text);
					}catch(e){
						dojo.debug(e);
						dojo.debug(text);
						ret = null;
					}
				}else if(req.mimetype == "text/json" || req.mimetype == "application/json"){
					try{
						ret = dj_eval("("+text+")");
					}catch(e){
						dojo.debug(e);
						dojo.debug(text);
						ret = false;
					}
				}else{
					ret = text;
				}
			}

			req.load("load", ret, req);
		}
		
		function connect(req){
			var content = req.content || {};
			var query;
	
			if (req.sendTransport){
				content["dojo.transport"] = "rhinohttp";
			}
	
			if(req.postContent){
				query = req.postContent;
			}else{
				query = dojo.io.argsFromMap(content, req.encoding);
			}
	
			var url_text = req.url;
			if(req.method.toLowerCase() == "get" && query != ""){
				url_text = url_text + "?" + query;
			}
			
			var url  = new java.net.URL(url_text);
			var conn = url.openConnection();
			
			//
			// configure the connection
			//
			
			conn.setRequestMethod(req.method.toUpperCase());
			
			if(req.headers){
				for(var header in req.headers){
					if(header.toLowerCase() == "content-type" && !req.contentType){
						req.contentType = req.headers[header];
					}else{
						conn.setRequestProperty(header, req.headers[header]);
					}
				}
			}
			if(req.contentType){
				conn.setRequestProperty("Content-Type", req.contentType);
			}

			if(req.method.toLowerCase() == "post"){
				conn.setDoOutput(true);

				// write the post data
				var output_stream = conn.getOutputStream();
				var byte_array = (new java.lang.String(query)).getBytes();
				output_stream.write(byte_array, 0, byte_array.length);
			}
			
			// do it to it!
			conn.connect();

			// perform the load
			doLoad(req, conn);
		}
		
		this.bind = function(req){
			var async = req["sync"] ? false : true;
			if (async){
				setTimeout(dojo.lang.hitch(this, function(){
					connect(req);
				}), 1);
			} else {
				connect(req);
			}
		}

		dojo.io.transports.addTransport("RhinoHTTPTransport");
}

__CPAN_FILE__ src/io/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: ["dojo.io.common"],
	rhino: ["dojo.io.RhinoIO"],
	browser: ["dojo.io.BrowserIO", "dojo.io.cookie"],
	dashboard: ["dojo.io.BrowserIO", "dojo.io.cookie"]
});
dojo.provide("dojo.io.*");

__CPAN_FILE__ src/io/ScriptSrcIO.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.ScriptSrcIO");
dojo.require("dojo.io.BrowserIO");
dojo.require("dojo.undo.browser");

//FIXME: should constantParams be JS object?
//FIXME: check dojo.io calls. Can we move the BrowserIO defined calls somewhere
//       else so that we don't depend on BrowserIO at all? The dependent calls
//       have to do with dealing with forms and making query params from JS object.
/**
 * See test_ScriptSrcIO.html for usage information.
 * Notes:
 * - The watchInFlight timer is set to 100 ms instead of 10ms (which is what BrowserIO.js uses).
 */
dojo.io.ScriptSrcTransport = new function(){
	this.preventCache = false; // if this is true, we'll always force GET requests to not cache
	this.maxUrlLength = 1000; //Used to calculate if script request should be multipart.
	this.inFlightTimer = null;

	this.DsrStatusCodes = {
		Continue: 100,
		Ok: 200,
		Error: 500
	};

	this.startWatchingInFlight = function(){
		if(!this.inFlightTimer){
			this.inFlightTimer = setInterval("dojo.io.ScriptSrcTransport.watchInFlight();", 100);
		}
	}

	this.watchInFlight = function(){
		var totalCount = 0;
		var doneCount = 0;
		for(var param in this._state){
			totalCount++;
			var currentState = this._state[param];
			if(currentState.isDone){
				doneCount++;
				delete this._state[param];
			}else if(!currentState.isFinishing){
				var listener = currentState.kwArgs;
				try{
					if(currentState.checkString && eval("typeof(" + currentState.checkString + ") != 'undefined'")){
						currentState.isFinishing = true;
						this._finish(currentState, "load");
						doneCount++;
						delete this._state[param];
					}else if(listener.timeoutSeconds && listener.timeout){
						if(currentState.startTime + (listener.timeoutSeconds * 1000) < (new Date()).getTime()){
							currentState.isFinishing = true;
							this._finish(currentState, "timeout");
							doneCount++;
							delete this._state[param];
						}
					}else if(!listener.timeoutSeconds){
						//Increment the done count if no timeout is specified, so
						//that we turn off the timer if all that is left in the state
						//list are things we can't clean up because they fail without
						//getting a callback.
						doneCount++;
					}
				}catch(e){
					currentState.isFinishing = true;
					this._finish(currentState, "error", {status: this.DsrStatusCodes.Error, response: e});
				}
			}
		}
	
		if(doneCount >= totalCount){
			clearInterval(this.inFlightTimer);
			this.inFlightTimer = null;
		}
	}

	this.canHandle = function(kwArgs){
		return dojo.lang.inArray(["text/javascript", "text/json", "application/json"], (kwArgs["mimetype"].toLowerCase()))
			&& (kwArgs["method"].toLowerCase() == "get")
			&& !(kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"]))
			&& (!kwArgs["sync"] || kwArgs["sync"] == false)
			&& !kwArgs["file"]
			&& !kwArgs["multipart"];
	}

	/**
	 * Removes any script tags from the DOM that may have been added by ScriptSrcTransport.
	 * Be careful though, by removing them from the script, you may invalidate some
	 * script objects that were defined by the js file that was pulled in as the
	 * src of the script tag. Test carefully if you decide to call this method.
	 * 
	 * In MSIE 6 (and probably 5.x), if you removed the script element while 
	 * part of the script is still executing, the browser will crash.
	 */
	this.removeScripts = function(){
		var scripts = document.getElementsByTagName("script");
		for(var i = 0; scripts && i < scripts.length; i++){
			var scriptTag = scripts[i];
			if(scriptTag.className == "ScriptSrcTransport"){
				var parent = scriptTag.parentNode;
				parent.removeChild(scriptTag);
				i--; //Set the index back one since we removed an item.
			}
		}
	}

	this.bind = function(kwArgs){
		//START duplication from BrowserIO.js (some changes made)
		var url = kwArgs.url;
		var query = "";
		
		if(kwArgs["formNode"]){
			var ta = kwArgs.formNode.getAttribute("action");
			if((ta)&&(!kwArgs["url"])){ url = ta; }
			var tp = kwArgs.formNode.getAttribute("method");
			if((tp)&&(!kwArgs["method"])){ kwArgs.method = tp; }
			query += dojo.io.encodeForm(kwArgs.formNode, kwArgs.encoding, kwArgs["formFilter"]);
		}

		if(url.indexOf("#") > -1) {
			dojo.debug("Warning: dojo.io.bind: stripping hash values from url:", url);
			url = url.split("#")[0];
		}

		//Break off the domain/path of the URL.
		var urlParts = url.split("?");
		if(urlParts && urlParts.length == 2){
			url = urlParts[0];
			query += (query ? "&" : "") + urlParts[1];
		}

		if(kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"]){
			dojo.undo.browser.addToHistory(kwArgs);
		}

		//Create an ID for the request.
		var id = kwArgs["apiId"] ? kwArgs["apiId"] : "id" + this._counter++;

		//Fill out any other content pieces.
		var content = kwArgs["content"];
		var jsonpName = kwArgs.jsonParamName;
		if(kwArgs.sendTransport || jsonpName) {
			if (!content){
				content = {};
			}
			if(kwArgs.sendTransport){
				content["dojo.transport"] = "scriptsrc";
			}

			if(jsonpName){
				content[jsonpName] = "dojo.io.ScriptSrcTransport._state." + id + ".jsonpCall";
			}
		}

		if(kwArgs.postContent){
			query = kwArgs.postContent;
		}else if(content){
			query += ((query) ? "&" : "") + dojo.io.argsFromMap(content, kwArgs.encoding, jsonpName);
		}
		//END duplication from BrowserIO.js

		//START DSR

		//If an apiId is specified, then we want to make sure useRequestId is true.
		if(kwArgs["apiId"]){
			kwArgs["useRequestId"] = true;
		}

		//Set up the state for this request.
		var state = {
			"id": id,
			"idParam": "_dsrid=" + id,
			"url": url,
			"query": query,
			"kwArgs": kwArgs,
			"startTime": (new Date()).getTime(),
			"isFinishing": false
		};

		if(!url){
			//Error. An URL is needed.
			this._finish(state, "error", {status: this.DsrStatusCodes.Error, statusText: "url.none"});
			return;
		}

		//If this is a jsonp request, intercept the jsonp callback
		if(content && content[jsonpName]){
			state.jsonp = content[jsonpName];
			state.jsonpCall = function(data){
				if(data["Error"]||data["error"]){
					if(dojo["json"] && dojo["json"]["serialize"]){
						dojo.debug(dojo.json.serialize(data));
					}
					dojo.io.ScriptSrcTransport._finish(this, "error", data);
				}else{
					dojo.io.ScriptSrcTransport._finish(this, "load", data);
				}
			};
		}

		//Only store the request state on the state tracking object if a callback
		//is expected or if polling on a checkString will be done.
		if(kwArgs["useRequestId"] || kwArgs["checkString"] || state["jsonp"]){
			this._state[id] = state;
		}

		//A checkstring is a string that if evaled will not be undefined once the
		//script src loads. Used as an alternative to depending on a callback from
		//the script file. If this is set, then multipart is not assumed to be used,
		//since multipart requires a specific callback. With checkString we will be doing
		//polling.
		if(kwArgs["checkString"]){
			state.checkString = kwArgs["checkString"];
		}

		//Constant params are parameters that should always be sent with each
		//part of a multipart URL.
		state.constantParams = (kwArgs["constantParams"] == null ? "" : kwArgs["constantParams"]);
	
		if(kwArgs["preventCache"] ||
			(this.preventCache == true && kwArgs["preventCache"] != false)){
			state.nocacheParam = "dojo.preventCache=" + new Date().valueOf();
		}else{
			state.nocacheParam = "";
		}

		//Get total length URL, if we were to do it as one URL.
		//Add some padding, extra & separators.
		var urlLength = state.url.length + state.query.length + state.constantParams.length 
				+ state.nocacheParam.length + this._extraPaddingLength;

		if(kwArgs["useRequestId"]){
			urlLength += state.idParam.length;
		}
		
		if(!kwArgs["checkString"] && kwArgs["useRequestId"] 
			&& !state["jsonp"] && !kwArgs["forceSingleRequest"]
			&& urlLength > this.maxUrlLength){
			if(url > this.maxUrlLength){
				//Error. The URL domain and path are too long. We can't
				//segment that, so return an error.
				this._finish(state, "error", {status: this.DsrStatusCodes.Error, statusText: "url.tooBig"});
				return;
			}else{
				//Start the multiple requests.
				this._multiAttach(state, 1);
			}
		}else{
			//Send one URL.
			var queryParams = [state.constantParams, state.nocacheParam, state.query];
			if(kwArgs["useRequestId"] && !state["jsonp"]){
				queryParams.unshift(state.idParam);
			}
			var finalUrl = this._buildUrl(state.url, queryParams);

			//Track the final URL in case we need to use that instead of api ID when receiving
			//the load callback.
			state.finalUrl = finalUrl;
			
			this._attach(state.id, finalUrl);
		}
		//END DSR

		this.startWatchingInFlight();
	}
	
	//Private properties/methods
	this._counter = 1;
	this._state = {};
	this._extraPaddingLength = 16;

	//Is there a dojo function for this already?
	this._buildUrl = function(url, nameValueArray){
		var finalUrl = url;
		var joiner = "?";
		for(var i = 0; i < nameValueArray.length; i++){
			if(nameValueArray[i]){
				finalUrl += joiner + nameValueArray[i];
				joiner = "&";
			}
		}

		return finalUrl;
	}

	this._attach = function(id, url){
		//Attach the script to the DOM.
		var element = document.createElement("script");
		element.type = "text/javascript";
		element.src = url;
		element.id = id;
		element.className = "ScriptSrcTransport";
		document.getElementsByTagName("head")[0].appendChild(element);
	}

	this._multiAttach = function(state, part){
		//Check to make sure we still have a query to send up. This is mostly
		//a protection from a goof on the server side when it sends a part OK
		//response instead of a final response.
		if(state.query == null){
			this._finish(state, "error", {status: this.DsrStatusCodes.Error, statusText: "query.null"});
			return;
		}

		if(!state.constantParams){
			state.constantParams = "";
		}

		//How much of the query can we take?
		//Add a padding constant to account for _part and a couple extra amperstands.
		//Also add space for id since we'll need it now.
		var queryMax = this.maxUrlLength - state.idParam.length
					 - state.constantParams.length - state.url.length
					 - state.nocacheParam.length - this._extraPaddingLength;
		
		//Figure out if this is the last part.
		var isDone = state.query.length < queryMax;
	
		//Break up the query string if necessary.
		var currentQuery;
		if(isDone){
			currentQuery = state.query;
			state.query = null;
		}else{
			//Find the & or = nearest the max url length.
			var ampEnd = state.query.lastIndexOf("&", queryMax - 1);
			var eqEnd = state.query.lastIndexOf("=", queryMax - 1);

			//See if & is closer, or if = is right at the edge,
			//which means we should put it on the next URL.
			if(ampEnd > eqEnd || eqEnd == queryMax - 1){
				//& is nearer the end. So just chop off from there.
				currentQuery = state.query.substring(0, ampEnd);
				state.query = state.query.substring(ampEnd + 1, state.query.length) //strip off amperstand with the + 1.
			}else{
				//= is nearer the end. Take the max amount possible. 
				currentQuery = state.query.substring(0, queryMax);
			 
				//Find the last query name in the currentQuery so we can prepend it to
				//ampEnd. Could be -1 (not there), so account for that.
				var queryName = currentQuery.substring((ampEnd == -1 ? 0 : ampEnd + 1), eqEnd);
				state.query = queryName + "=" + state.query.substring(queryMax, state.query.length);
			}
		}
		
		//Now send a part of the script
		var queryParams = [currentQuery, state.idParam, state.constantParams, state.nocacheParam];
		if(!isDone){
			queryParams.push("_part=" + part);
		}

		var url = this._buildUrl(state.url, queryParams);

		this._attach(state.id + "_" + part, url);
	}

	this._finish = function(state, callback, event){
		if(callback != "partOk" && !state.kwArgs[callback] && !state.kwArgs["handle"]){
			//Ignore "partOk" because that is an internal callback.
			if(callback == "error"){
				state.isDone = true;
				throw event;
			}
		}else{
			switch(callback){
				case "load":
					var response = event ? event.response : null;
					if(!response){
						response = event;
					}
					state.kwArgs[(typeof state.kwArgs.load == "function") ? "load" : "handle"]("load", response, event, state.kwArgs);
					state.isDone = true;
					break;
				case "partOk":
					var part = parseInt(event.response.part, 10) + 1;
					//Update the constant params, if any.
					if(event.response.constantParams){
						state.constantParams = event.response.constantParams;
					}
					this._multiAttach(state, part);
					state.isDone = false;
					break;
				case "error":
					state.kwArgs[(typeof state.kwArgs.error == "function") ? "error" : "handle"]("error", event.response, event, state.kwArgs);
					state.isDone = true;
					break;
				default:
					state.kwArgs[(typeof state.kwArgs[callback] == "function") ? callback : "handle"](callback, event, event, state.kwArgs);
					state.isDone = true;
			}
		}
	}

	dojo.io.transports.addTransport("ScriptSrcTransport");
}

//Define callback handler.
window.onscriptload = function(event){
	var state = null;
	var transport = dojo.io.ScriptSrcTransport;
	
	//Find the matching state object for event ID.
	if(transport._state[event.id]){
		state = transport._state[event.id];
	}else{
		//The ID did not match directly to an entry in the state list.
		//Try searching the state objects for a matching original URL.
		var tempState;
		for(var param in transport._state){
			tempState = transport._state[param];
			if(tempState.finalUrl && tempState.finalUrl == event.id){
				state = tempState;
				break;
			}
		}

		//If no matching original URL is found, then use the URL that was actually used
		//in the SCRIPT SRC attribute.
		if(state == null){
			var scripts = document.getElementsByTagName("script");
			for(var i = 0; scripts && i < scripts.length; i++){
				var scriptTag = scripts[i];
				if(scriptTag.getAttribute("class") == "ScriptSrcTransport"
					&& scriptTag.src == event.id){
					state = transport._state[scriptTag.id];
					break;
				}
			}
		}
		
		//If state is still null, then throw an error.
		if(state == null){
			throw "No matching state for onscriptload event.id: " + event.id;
		}
	}

	var callbackName = "error";
	switch(event.status){
		case dojo.io.ScriptSrcTransport.DsrStatusCodes.Continue:
			//A part of a multipart request.
			callbackName = "partOk";
			break;
		case dojo.io.ScriptSrcTransport.DsrStatusCodes.Ok:
			//Successful reponse.
			callbackName = "load";
			break;
	}

	transport._finish(state, callbackName, event);
};

__CPAN_FILE__ src/io/cookie.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.cookie");

dojo.io.cookie.setCookie = function(name, value, days, path, domain, secure) {
	var expires = -1;
	if(typeof days == "number" && days >= 0) {
		var d = new Date();
		d.setTime(d.getTime()+(days*24*60*60*1000));
		expires = d.toGMTString();
	}
	value = escape(value);
	document.cookie = name + "=" + value + ";"
		+ (expires != -1 ? " expires=" + expires + ";" : "")
		+ (path ? "path=" + path : "")
		+ (domain ? "; domain=" + domain : "")
		+ (secure ? "; secure" : "");
}

dojo.io.cookie.set = dojo.io.cookie.setCookie;

dojo.io.cookie.getCookie = function(name) {
	// FIXME: Which cookie should we return?
	//        If there are cookies set for different sub domains in the current
	//        scope there could be more than one cookie with the same name.
	//        I think taking the last one in the list takes the one from the
	//        deepest subdomain, which is what we're doing here.
	var idx = document.cookie.lastIndexOf(name+'=');
	if(idx == -1) { return null; }
	var value = document.cookie.substring(idx+name.length+1);
	var end = value.indexOf(';');
	if(end == -1) { end = value.length; }
	value = value.substring(0, end);
	value = unescape(value);
	return value;
}

dojo.io.cookie.get = dojo.io.cookie.getCookie;

dojo.io.cookie.deleteCookie = function(name) {
	dojo.io.cookie.setCookie(name, "-", 0);
}

dojo.io.cookie.setObjectCookie = function(name, obj, days, path, domain, secure, clearCurrent) {
	if(arguments.length == 5) { // for backwards compat
		clearCurrent = domain;
		domain = null;
		secure = null;
	}
	var pairs = [], cookie, value = "";
	if(!clearCurrent) { cookie = dojo.io.cookie.getObjectCookie(name); }
	if(days >= 0) {
		if(!cookie) { cookie = {}; }
		for(var prop in obj) {
			if(prop == null) {
				delete cookie[prop];
			} else if(typeof obj[prop] == "string" || typeof obj[prop] == "number") {
				cookie[prop] = obj[prop];
			}
		}
		prop = null;
		for(var prop in cookie) {
			pairs.push(escape(prop) + "=" + escape(cookie[prop]));
		}
		value = pairs.join("&");
	}
	dojo.io.cookie.setCookie(name, value, days, path, domain, secure);
}

dojo.io.cookie.getObjectCookie = function(name) {
	var values = null, cookie = dojo.io.cookie.getCookie(name);
	if(cookie) {
		values = {};
		var pairs = cookie.split("&");
		for(var i = 0; i < pairs.length; i++) {
			var pair = pairs[i].split("=");
			var value = pair[1];
			if( isNaN(value) ) { value = unescape(pair[1]); }
			values[ unescape(pair[0]) ] = value;
		}
	}
	return values;
}

dojo.io.cookie.isSupported = function() {
	if(typeof navigator.cookieEnabled != "boolean") {
		dojo.io.cookie.setCookie("__TestingYourBrowserForCookieSupport__",
			"CookiesAllowed", 90, null);
		var cookieVal = dojo.io.cookie.getCookie("__TestingYourBrowserForCookieSupport__");
		navigator.cookieEnabled = (cookieVal == "CookiesAllowed");
		if(navigator.cookieEnabled) {
			// FIXME: should we leave this around?
			this.deleteCookie("__TestingYourBrowserForCookieSupport__");
		}
	}
	return navigator.cookieEnabled;
}

// need to leave this in for backwards-compat from 0.1 for when it gets pulled in by dojo.io.*
if(!dojo.io.cookies) { dojo.io.cookies = dojo.io.cookie; }

__CPAN_FILE__ src/io/RepubsubIO.js
//	Copyright (c) 2004 Friendster Inc., Licensed under the Academic Free
//	License version 2.0 or later 

dojo.require("dojo.event.*");
dojo.require("dojo.io.BrowserIO");

dojo.provide("dojo.io.RepubsubIO");

dojo.io.repubsubTranport = new function(){
	var rps = dojo.io.repubsub;
	this.canHandle = function(kwArgs){
		if((kwArgs["mimetype"] == "text/javascript")&&(kwArgs["method"] == "repubsub")){
			return true;
		}
		return false;
	}

	this.bind = function(kwArgs){
		if(!rps.isInitialized){
			// open up our tunnel, queue up requests anyway
			rps.init();
		}
		// FIXME: we need to turn this into a topic subscription
		// var tgtURL = kwArgs.url+"?"+dojo.io.argsFromMap(kwArgs.content);
		// sampleTransport.sendRequest(tgtURL, hdlrFunc);

		// a normal "bind()" call in a request-response transport layer is
		// something that (usually) encodes most of it's payload with the
		// request. Multi-event systems like repubsub are a bit more complex,
		// and repubsub in particular distinguishes the publish and subscribe
		// portions of thep rocess with different method calls to handle each.
		// Therefore, a "bind" in the sense of repubsub must first determine if
		// we have an open subscription to a channel provided by the server,
		// and then "publish" the request payload if there is any. We therefore
		// must take care not to incorrectly or too agressively register or
		// file event handlers which are provided with the kwArgs method.

		// NOTE: we ONLY pay attention to those event handlers that are
		// registered with the bind request that subscribes to the channel. If
		// event handlers are provided with subsequent requests, we might in
		// the future support some additive or replacement syntax, but for now
		// they get dropped on the floor.

		// NOTE: in this case, url MUST be the "topic" to which we
		// subscribe/publish for this channel
		if(!rps.topics[kwArgs.url]){
			kwArgs.rpsLoad = function(evt){
				kwArgs.load("load", evt);
			}
			rps.subscribe(kwArgs.url, kwArgs, "rpsLoad");
		}

		if(kwArgs["content"]){
			// what we wanted to send
			var cEvt = dojo.io.repubsubEvent.initFromProperties(kwArgs.content);
			rps.publish(kwArgs.url, cEvt);
		}
	}

	dojo.io.transports.addTransport("repubsubTranport");
}

dojo.io.repubsub = new function(){
	this.initDoc = "init.html";
	this.isInitialized = false;
	this.subscriptionBacklog = [];
	this.debug = true;
	this.rcvNodeName = null;
	this.sndNodeName = null;
	this.rcvNode = null;
	this.sndNode = null;
	this.canRcv = false;
	this.canSnd = false;
	this.canLog = false;
	this.sndTimer = null;
	this.windowRef = window;
	this.backlog = [];
	this.tunnelInitCount = 0;
	this.tunnelFrameKey = "tunnel_frame";
	this.serverBaseURL = location.protocol+"//"+location.host+location.pathname;
	this.logBacklog = [];
	this.getRandStr = function(){
		return Math.random().toString().substring(2, 10);
	}
	this.userid = "guest";
	this.tunnelID = this.getRandStr();
	this.attachPathList = [];
	this.topics = []; // list of topics we have listeners to

	// actually, now that I think about it a little bit more, it would sure be
	// useful to parse out the <script> src attributes. We're looking for
	// something with a "do_method=lib", since that's what would have included
	// us in the first place (in the common case).
	this.parseGetStr = function(){
		var baseUrl = document.location.toString();
		var params = baseUrl.split("?", 2);
		if(params.length > 1){
			var paramStr = params[1];
			var pairs = paramStr.split("&");
			var opts = [];
			for(var x in pairs){
				var sp = pairs[x].split("=");
				// FIXME: is this eval dangerous?
				try{
					opts[sp[0]]=eval(sp[1]);
				}catch(e){
					opts[sp[0]]=sp[1];
				}
			}
			return opts;
		}else{
			return [];
		}
	}

	// parse URL params and use them as default vals
	var getOpts = this.parseGetStr();
	for(var x in getOpts){
		// FIXME: should I be checking for undefined here before setting? Does
		//        that buy me anything?
		this[x] = getOpts[x];
	}

	if(!this["tunnelURI"]){
		this.tunnelURI = [	"/who/", escape(this.userid), "/s/", 
							this.getRandStr(), "/kn_journal"].join("");
		// this.tunnelURI = this.absoluteTopicURI(this.tunnelURI);
	}

	/*
	if (self.kn_tunnelID) kn.tunnelID = self.kn_tunnelID; // the server says
	if (kn._argv.kn_tunnelID) kn.tunnelID = kn._argv.kn_tunnelID; // the url says
	*/

	// check the options object if it exists and use its properties as an
	// over-ride
	if(window["repubsubOpts"]||window["rpsOpts"]){
		var optObj = window["repubsubOpts"]||window["rpsOpts"];
		for(var x in optObj){
			this[x] = optObj[x]; // copy the option object properties
		}
	}

	// things that get called directly from our iframe to inform us of events
	this.tunnelCloseCallback = function(){
		// when we get this callback, we should immediately attempt to re-start
		// our tunnel connection
		dojo.io.setIFrameSrc(this.rcvNode, this.initDoc+"?callback=repubsub.rcvNodeReady&domain="+document.domain);
	}

	this.receiveEventFromTunnel = function(evt, srcWindow){
		// we should never be getting events from windows we didn't create
		// NOTE: events sourced from the local window are also supported for
		// 		 debugging purposes

		// any event object MUST have a an "elements" property
		if(!evt["elements"]){
			this.log("bailing! event received without elements!", "error");
			return;
		}

		// if the event passes some minimal sanity tests, we need to attempt to
		// dispatch it!

		// first, it seems we have to munge the event object a bit
		var e = {};
		for(var i=0; i<evt.elements.length; i++){
			var ee = evt.elements[i];
			e[ee.name||ee.nameU] = (ee.value||ee.valueU);
			// FIXME: need to enable this only in some extreme debugging mode!
			this.log("[event]: "+(ee.name||ee.nameU)+": "+e[ee.name||ee.nameU]);
		}

		// NOTE: the previous version of this library put a bunch of code here
		// to manage state that tried to make sure that we never, ever, lost
		// any info about an event. If we unload RIGHT HERE, I don't think it's
		// going to make a huge difference one way or another. Time will tell.

		// and with THAT out of the way, dispatch it!
		this.dispatch(e);

		// TODO: remove the script block that created the event obj to save
		// memory, etc.
	}

	this.widenDomain = function(domainStr){
		// the purpose of this is to set the most liberal domain policy
		// available
		var cd = domainStr||document.domain;
		if(cd.indexOf(".")==-1){ return; } // probably file:/// or localhost
		var dps = cd.split(".");
		if(dps.length<=2){ return; } // probably file:/// or an RFC 1918 address
		dps = dps.slice(dps.length-2);
		document.domain = dps.join(".");
	}

	// FIXME: parseCookie and setCookie should be methods that are more broadly
	// available. Perhaps in htmlUtils?

	this.parseCookie = function(){
		var cs = document.cookie;
		var keypairs = cs.split(";");
		for(var x=0; x<keypairs.length; x++){
			keypairs[x] = keypairs[x].split("=");
			if(x!=keypairs.length-1){ cs+=";"; }
		}
		return keypairs;
	}

	this.setCookie = function(keypairs, clobber){
		// NOTE: we want to only ever set session cookies, so never provide an
		// 		 expires date
		if((clobber)&&(clobber==true)){ document.cookie = ""; }
		var cs = "";
		for(var x=0; x<keypairs.length; x++){
			cs += keypairs[x][0]+"="+keypairs[x][1];
			if(x!=keypairs.length-1){ cs+=";"; }
		}
		document.cookie = cs;
	}

	// FIXME: need to replace w/ dojo.log.*
	this.log = function(str, lvl){
		if(!this.debug){ return; } // we of course only care if we're in debug mode
		while(this.logBacklog.length>0){
			if(!this.canLog){ break; }
			var blo = this.logBacklog.shift();
			this.writeLog("["+blo[0]+"]: "+blo[1], blo[2]);
		}
		this.writeLog(str, lvl);
	}

	this.writeLog = function(str, lvl){
		dojo.debug(((new Date()).toLocaleTimeString())+": "+str);
	}

	this.init = function(){
		this.widenDomain();
		// this.findPeers();
		this.openTunnel();
		this.isInitialized = true;
		// FIXME: this seems like entirely the wrong place to replay the backlog
		while(this.subscriptionBacklog.length){
			this.subscribe.apply(this, this.subscriptionBacklog.shift());
		}
	}

	this.clobber = function(){
		if(this.rcvNode){
			this.setCookie( [
					[this.tunnelFrameKey,"closed"],
					["path","/"]
				], false 
			);
		}
	}

	this.openTunnel = function(){
		// We create two iframes here:

		// one for getting data
		this.rcvNodeName = "rcvIFrame_"+this.getRandStr();
		// set cookie that can be used to find the receiving iframe
		this.setCookie( [
				[this.tunnelFrameKey,this.rcvNodeName],
				["path","/"]
			], false
		);

		this.rcvNode = dojo.io.createIFrame(this.rcvNodeName);
		// FIXME: set the src attribute here to the initialization URL
		dojo.io.setIFrameSrc(this.rcvNode, this.initDoc+"?callback=repubsub.rcvNodeReady&domain="+document.domain);

		// the other for posting data in reply

		this.sndNodeName = "sndIFrame_"+this.getRandStr();
		this.sndNode = dojo.io.createIFrame(this.sndNodeName);
		// FIXME: set the src attribute here to the initialization URL
		dojo.io.setIFrameSrc(this.sndNode, this.initDoc+"?callback=repubsub.sndNodeReady&domain="+document.domain);

	}

	this.rcvNodeReady = function(){
		// FIXME: why is this sequence number needed? Why isn't the UID gen
		// 		  function enough?
        var statusURI = [this.tunnelURI, '/kn_status/', this.getRandStr(), '_', 
						 String(this.tunnelInitCount++)].join(""); 
            // (kn._seqNum++); // FIXME: !!!!
		// this.canRcv = true;
		this.log("rcvNodeReady");
		// FIXME: initialize receiver and request the base topic
		// dojo.io.setIFrameSrc(this.rcvNode, this.serverBaseURL+"/kn?do_method=blank");
		var initURIArr = [	this.serverBaseURL, "/kn?kn_from=", escape(this.tunnelURI),
							"&kn_id=", escape(this.tunnelID), "&kn_status_from=", 
							escape(statusURI)];
		// FIXME: does the above really need a kn_response_flush? won't the
		// 		  server already know? If not, what good is it anyway?
		dojo.io.setIFrameSrc(this.rcvNode, initURIArr.join(""));

		// setup a status path listener, but don't tell the server about it,
		// since it already knows we're itnerested in our own tunnel status
		this.subscribe(statusURI, this, "statusListener", true);

		this.log(initURIArr.join(""));
	}

	this.sndNodeReady = function(){
		this.canSnd = true;
		this.log("sndNodeReady");
		this.log(this.backlog.length);
		// FIXME: handle any pent-up send commands
		if(this.backlog.length > 0){
			this.dequeueEvent();
		}
	}

	this.statusListener = function(evt){
		this.log("status listener called");
		this.log(evt.status, "info");
	}

	// this handles local event propigation
	this.dispatch = function(evt){
		// figure out what topic it came from
		if(evt["to"]||evt["kn_routed_from"]){
			var rf = evt["to"]||evt["kn_routed_from"];
			// split off the base server URL
			var topic = rf.split(this.serverBaseURL, 2)[1];
			if(!topic){
				// FIXME: how do we recover when we don't get a sane "from"? Do
				// we try to route to it anyway?
				topic = rf;
			}
			this.log("[topic] "+topic);
			if(topic.length>3){
				if(topic.slice(0, 3)=="/kn"){
					topic = topic.slice(3);
				}
			}
			if(this.attachPathList[topic]){
				this.attachPathList[topic](evt);
			}
		}
	}

	this.subscribe = function(	topic /* kn_from in the old terminilogy */, 
								toObj, toFunc, dontTellServer){
		if(!this.isInitialized){
			this.subscriptionBacklog.push([topic, toObj, toFunc, dontTellServer]);
			return;
		}
		if(!this.attachPathList[topic]){
			this.attachPathList[topic] = function(){ return true; }
			this.log("subscribing to: "+topic);
			this.topics.push(topic);
		}
		var revt = new dojo.io.repubsubEvent(this.tunnelURI, topic, "route");
		var rstr = [this.serverBaseURL+"/kn", revt.toGetString()].join("");
		dojo.event.kwConnect({
			once: true,
			srcObj: this.attachPathList, 
			srcFunc: topic, 
			adviceObj: toObj, 
			adviceFunc: toFunc
		});
		// NOTE: the above is a local mapping, if we're not the leader, we
		// 		 should connect our mapping to the topic handler of the peer
		// 		 leader, this ensures that not matter what happens to the
		// 		 leader, we don't really loose our heads if/when the leader
		// 		 goes away.
		if(!this.rcvNode){ /* this should be an error! */ }
		if(dontTellServer){
			return;
		}
		this.log("sending subscription to: "+topic);
		// create a subscription event object and give it all the props we need
		// to updates on the specified topic

		// FIXME: we should only enqueue if this is our first subscription!
		this.sendTopicSubToServer(topic, rstr);
	}

	this.sendTopicSubToServer = function(topic, str){
		if(!this.attachPathList[topic]["subscriptions"]){
			this.enqueueEventStr(str);
			this.attachPathList[topic].subscriptions = 0;
		}
		this.attachPathList[topic].subscriptions++;
	}

	this.unSubscribe = function(topic, toObj, toFunc){
		// first, locally disconnect
		dojo.event.kwDisconnect({
			srcObj: this.attachPathList, 
			srcFunc: topic, 
			adviceObj: toObj, 
			adviceFunc: toFunc
		});
		
		// FIXME: figure out if there are any remaining listeners to the topic,
		// 		  and if not, inform the server of our desire not to be
		// 		  notified of updates to the topic
	}

	// the "publish" method is really a misnomer, since it really means "take
	// this event and send it to the server". Note that the "dispatch" method
	// handles local event promigulation, and therefore we emulate both sides
	// of a real event router without having to swallow all of the complexity.
	this.publish = function(topic, event){
		var evt = dojo.io.repubsubEvent.initFromProperties(event);
		// FIXME: need to make sure we have from and to set correctly
		// 		  before we serialize and send off to the great blue
		// 		  younder.
		evt.to = topic;
		// evt.from = this.tunnelURI;

		var evtURLParts = [];
		evtURLParts.push(this.serverBaseURL+"/kn");

		// serialize the event to a string and then post it to the correct
		// topic
		evtURLParts.push(evt.toGetString());
		this.enqueueEventStr(evtURLParts.join(""));
	}

	this.enqueueEventStr = function(evtStr){
		this.log("enqueueEventStr");
		this.backlog.push(evtStr);
		this.dequeueEvent();
	}

	this.dequeueEvent = function(force){
		this.log("dequeueEvent");
		if(this.backlog.length <= 0){ return; }
		if((this.canSnd)||(force)){
			dojo.io.setIFrameSrc(this.sndNode, this.backlog.shift()+"&callback=repubsub.sndNodeReady");
			this.canSnd = false;
		}else{
			this.log("sndNode not available yet!", "debug");
		}
	}
}

dojo.io.repubsubEvent = function(to, from, method, id, routeURI, payload, dispname, uid){
	this.to = to;
	this.from = from;
	this.method = method||"route";
	this.id = id||repubsub.getRandStr();
	this.uri = routeURI;
	this.displayname = dispname||repubsub.displayname;
	this.userid = uid||repubsub.userid;
	this.payload = payload||"";
	this.flushChars = 4096;

	this.initFromProperties = function(evt){
		if(evt.constructor = dojo.io.repubsubEvent){ 
			for(var x in evt){
				this[x] = evt[x];
			}
		}else{
			// we want to copy all the properties of the evt object, and transform
			// those that are "stock" properties of dojo.io.repubsubEvent. All others should
			// be copied as-is
			for(var x in evt){
				if(typeof this.forwardPropertiesMap[x] == "string"){
					this[this.forwardPropertiesMap[x]] = evt[x];
				}else{
					this[x] = evt[x];
				}
			}
		}
	}

	this.toGetString = function(noQmark){
		var qs = [ ((noQmark) ? "" : "?") ];
		for(var x=0; x<this.properties.length; x++){
			var tp = this.properties[x];
			if(this[tp[0]]){
				qs.push(tp[1]+"="+encodeURIComponent(String(this[tp[0]])));
			}
			// FIXME: we need to be able to serialize non-stock properties!!!
		}
		return qs.join("&");
	}

}

dojo.io.repubsubEvent.prototype.properties = [["from", "kn_from"], ["to", "kn_to"], 
									["method", "do_method"], ["id", "kn_id"], 
									["uri", "kn_uri"], 
									["displayname", "kn_displayname"], 
									["userid", "kn_userid"], 
									["payload", "kn_payload"],
									["flushChars", "kn_response_flush"],
									["responseFormat", "kn_response_format"] ];

// maps properties from their old names to their new names...
dojo.io.repubsubEvent.prototype.forwardPropertiesMap = {};
// ...and vice versa...
dojo.io.repubsubEvent.prototype.reversePropertiesMap = {};

// and we then populate them both from the properties list
for(var x=0; x<dojo.io.repubsubEvent.prototype.properties.length; x++){
	var tp = dojo.io.repubsubEvent.prototype.properties[x];
	dojo.io.repubsubEvent.prototype.reversePropertiesMap[tp[0]] = tp[1];
	dojo.io.repubsubEvent.prototype.forwardPropertiesMap[tp[1]] = tp[0];
}
// static version of initFromProperties, creates new event and object and
// returns it after init
dojo.io.repubsubEvent.initFromProperties = function(evt){
	var eventObj = new dojo.io.repubsubEvent();
	eventObj.initFromProperties(evt);
	return eventObj;
}

__CPAN_FILE__ src/io/IframeIO.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.io.IframeIO");
dojo.require("dojo.io.BrowserIO");
dojo.require("dojo.uri.*");

// FIXME: is it possible to use the Google htmlfile hack to prevent the
// background click with this transport?

dojo.io.createIFrame = function(fname, onloadstr, uri){
	if(window[fname]){ return window[fname]; }
	if(window.frames[fname]){ return window.frames[fname]; }
	var r = dojo.render.html;
	var cframe = null;
	var turi = uri||dojo.uri.dojoUri("iframe_history.html?noInit=true");
	var ifrstr = ((r.ie)&&(dojo.render.os.win)) ? '<iframe name="'+fname+'" src="'+turi+'" onload="'+onloadstr+'">' : 'iframe';
	cframe = document.createElement(ifrstr);
	with(cframe){
		name = fname;
		setAttribute("name", fname);
		id = fname;
	}
	dojo.body().appendChild(cframe);
	window[fname] = cframe;

	with(cframe.style){
		if(!r.safari){
			//We can't change the src in Safari 2.0.3 if absolute position. Bizarro.
			position = "absolute";
		}
		left = top = "0px";
		height = width = "1px";
		visibility = "hidden";
		/*
		if(djConfig.isDebug){
			position = "relative";
			height = "300px";
			width = "600px";
			visibility = "visible";
		}
		*/
	}

	if(!r.ie){
		dojo.io.setIFrameSrc(cframe, turi, true);
		cframe.onload = new Function(onloadstr);
	}
	
	return cframe;
}

dojo.io.IframeTransport = new function(){
	var _this = this;
	this.currentRequest = null;
	this.requestQueue = [];
	this.iframeName = "dojoIoIframe";

	this.fireNextRequest = function(){
		try{
			if((this.currentRequest)||(this.requestQueue.length == 0)){ return; }
			// dojo.debug("fireNextRequest");
			var cr = this.currentRequest = this.requestQueue.shift();
			cr._contentToClean = [];
			var fn = cr["formNode"];
			var content = cr["content"] || {};
			if(cr.sendTransport) {
				content["dojo.transport"] = "iframe";
			}
			if(fn){
				if(content){
					// if we have things in content, we need to add them to the form
					// before submission
					for(var x in content){
						if(!fn[x]){
							var tn;
							if(dojo.render.html.ie){
								tn = document.createElement("<input type='hidden' name='"+x+"' value='"+content[x]+"'>");
								fn.appendChild(tn);
							}else{
								tn = document.createElement("input");
								fn.appendChild(tn);
								tn.type = "hidden";
								tn.name = x;
								tn.value = content[x];
							}
							cr._contentToClean.push(x);
						}else{
							fn[x].value = content[x];
						}
					}
				}
				if(cr["url"]){
					cr._originalAction = fn.getAttribute("action");
					fn.setAttribute("action", cr.url);
				}
				if(!fn.getAttribute("method")){
					fn.setAttribute("method", (cr["method"]) ? cr["method"] : "post");
				}
				cr._originalTarget = fn.getAttribute("target");
				fn.setAttribute("target", this.iframeName);
				fn.target = this.iframeName;
				fn.submit();
			}else{
				// otherwise we post a GET string by changing URL location for the
				// iframe
				var query = dojo.io.argsFromMap(this.currentRequest.content);
				var tmpUrl = cr.url + (cr.url.indexOf("?") > -1 ? "&" : "?") + query;
				dojo.io.setIFrameSrc(this.iframe, tmpUrl, true);
			}
		}catch(e){
			this.iframeOnload(e);
		}
	}

	this.canHandle = function(kwArgs){
		return (
			(
				dojo.lang.inArray([	"text/plain", "text/html", "text/javascript", "text/json", "application/json"], kwArgs["mimetype"])
			)&&(
				dojo.lang.inArray(["post", "get"], kwArgs["method"].toLowerCase())
			)&&(
				// never handle a sync request
				!  ((kwArgs["sync"])&&(kwArgs["sync"] == true))
			)
		);
	}

	this.bind = function(kwArgs){
		if(!this["iframe"]){ this.setUpIframe(); }
		this.requestQueue.push(kwArgs);
		this.fireNextRequest();
		return;
	}

	this.setUpIframe = function(){

		// NOTE: IE 5.0 and earlier Mozilla's don't support an onload event for
		//       iframes. OTOH, we don't care.
		this.iframe = dojo.io.createIFrame(this.iframeName, "dojo.io.IframeTransport.iframeOnload();");
	}

	this.iframeOnload = function(errorObject /* Object */){
		if(!_this.currentRequest){
			_this.fireNextRequest();
			return;
		}

		var req = _this.currentRequest;

		if(req.formNode){
			// remove all the hidden content inputs
			var toClean = req._contentToClean;
			for(var i = 0; i < toClean.length; i++) {
				var key = toClean[i];
				if(dojo.render.html.safari){
					//In Safari (at least 2.0.3), can't use formNode[key] syntax to find the node,
					//for nodes that were dynamically added.
					var fNode = req.formNode;
					for(var j = 0; j < fNode.childNodes.length; j++){
						var chNode = fNode.childNodes[j];
						if(chNode.name == key){
							var pNode = chNode.parentNode;
							pNode.removeChild(chNode);
							break;
						}
					}
				}else{
					var input = req.formNode[key];
					req.formNode.removeChild(input);
					req.formNode[key] = null;
				}
			}
	
			// restore original action + target
			if(req["_originalAction"]){
				req.formNode.setAttribute("action", req._originalAction);
			}
			if(req["_originalTarget"]){
				req.formNode.setAttribute("target", req._originalTarget);
				req.formNode.target = req._originalTarget;
			}
		}

		var contentDoc = function(iframe_el){
			var doc = iframe_el.contentDocument || // W3
				(
					(iframe_el.contentWindow)&&(iframe_el.contentWindow.document)
				) ||  // IE
				(
					(iframe_el.name)&&(document.frames[iframe_el.name])&&
					(document.frames[iframe_el.name].document)
				) || null;
			return doc;
		};

		var value;
		var success = false;

		if (errorObject){
				this._callError(req, "IframeTransport Request Error: " + errorObject);
		}else{
			var ifd = contentDoc(_this.iframe);
			// handle successful returns
			// FIXME: how do we determine success for iframes? Is there an equiv of
			// the "status" property?
	
			try{
				var cmt = req.mimetype;
				if((cmt == "text/javascript")||(cmt == "text/json")||(cmt == "application/json")){
					// FIXME: not sure what to do here? try to pull some evalulable
					// text from a textarea or cdata section? 
					// how should we set up the contract for that?
					var js = ifd.getElementsByTagName("textarea")[0].value;
					if(cmt == "text/json" || cmt == "application/json") { js = "(" + js + ")"; }
					value = dj_eval(js);
				}else if(cmt == "text/html"){
					value = ifd;
				}else{ // text/plain
					value = ifd.getElementsByTagName("textarea")[0].value;
				}
				success = true;
			}catch(e){ 
				// looks like we didn't get what we wanted!
				this._callError(req, "IframeTransport Error: " + e);
			}
		}

		// don't want to mix load function errors with processing errors, thus
		// a separate try..catch
		try {
			if(success && dojo.lang.isFunction(req["load"])){
				req.load("load", value, req);
			}
		} catch(e) {
			throw e;
		} finally {
			_this.currentRequest = null;
			_this.fireNextRequest();
		}
	}
	
	this._callError = function(req /* Object */, message /* String */){
		var errObj = new dojo.io.Error(message);
		if(dojo.lang.isFunction(req["error"])){
			req.error("error", errObj, req);
		}
	}

	dojo.io.transports.addTransport("IframeTransport");
}

__CPAN_FILE__ src/io/xip_client.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<title></title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
	<script type="text/javascript">
	// <!--
	/*
	This file is really focused on just sending one message to the server, and
	receiving one response. The code does not expect to be re-used for multiple messages.
	This might be reworked later if performance indicates a need for it.
	
	xip fragment identifier/hash values have the form:
	#id:cmd:realUrlEncodedMessage

	id: some ID that should be unique among messages. No inherent meaning,
	        just something to make sure the hash value is unique so the message
	        receiver knows a new message is available.
	        
	cmd: command to the receiver. Valid values are:
	         - loaded: the remote frame is loaded. Only sent from server to client.
	         - ok: the message that this page sent was received OK. The next message may
	               now be sent.
	         - start: the start message of a block of messages (a complete message may
	                  need to be segmented into many messages to get around the limitiations
	                  of the size of an URL that a browser accepts.
	         - part: indicates this is a part of a message.
	         - end: the end message of a block of messages. The message can now be acted upon.
	                If the message is small enough that it doesn't need to be segmented, then
	                just one hash value message can be sent with "end" as the command.
	
	To reassemble a segmented message, the realUrlEncodedMessage parts just have to be concatenated
	together.
	*/

	//Choosing 1024 as an arbitrary limit for the URL sizes.
	//Anecdotal info seems to indicate this is safe to use in all
	//modern browsers.
	xipUrlLimit = 1024;
	xipIdCounter = 1;

	function xipInit(){
		xipIsSending = false;
		xipServerUrl = null;
		xipStateId = null;
		xipRequestData = null;
		xipCurrentHash = "";
		xipResponseMessage = "";
		xipRequestParts = [];
		xipPartIndex = 0;
		xipServerWindow = null;
	}
	xipInit();
	
	function send(stateId, ifpServerUrl, urlEncodedData){
		if(!xipIsSending){
			xipIsSending = true;

			xipStateId = stateId;
			xipRequestData = urlEncodedData || "";

			//Modify the server URL if it is a local path and 
			//This is done for local/same domain testing.
			xipServerUrl = ifpServerUrl;
			if(ifpServerUrl.indexOf("..") == 0){
				var parts = ifpServerUrl.split("/");
				xipServerUrl = parts[parts.length - 1];
			}

			//Fix server URL to tell it about this page's URL. So that it can call us
			//back correctly. Use the fragment identifier to allow for caching of the server
			//page, and hey, we're using the fragment identifier for everything else.
			ifpServerUrl += "#" + encodeURIComponent(window.location);	

			//Start counter to inspect hash value.
			setInterval(pollHash, 10);

			//Loader server iframe, then wait for the server page to call us back.
			xipServerWindow = frames["xipServerFrame"];
			if (!xipServerWindow){
				xipServerWindow = document.getElementById("xipServerFrame").contentWindow;
			}

			xipServerWindow.location.replace(ifpServerUrl);
		}
	}

	function pollHash(){
		//Can't use location.hash because at least Firefox does a decodeURIComponent on it.
		var urlParts = window.location.href.split("#");
		if(urlParts.length == 2){
			var newHash = urlParts[1];
			if(newHash != xipCurrentHash){
				try{
					messageReceived(newHash);
				}catch(e){
					//Make sure to not keep processing the error hash value.
					xipCurrentHash = newHash;
					throw e;
				}
				xipCurrentHash = newHash;
			}
		}
	}

	function messageReceived(urlEncodedMessage){
		//Split off xip header.
		var parts = urlEncodedMessage.split(":");
		var command = parts[1];
		urlEncodedMessage = parts[2] || "";
		
		switch(command){
			case "loaded":
				sendRequestStart();
				break;
			case "ok":
				sendRequestPart();
				break;
			case "start":
				xipResponseMessage = "";
				xipResponseMessage += urlEncodedMessage;
				setServerUrl("ok");
				break;
			case "part":
				xipResponseMessage += urlEncodedMessage;			
				setServerUrl("ok");
				break;
			case "end":
				setServerUrl("ok");
				xipResponseMessage += urlEncodedMessage;
				parent.dojo.io.XhrIframeProxy.receive(xipStateId, xipResponseMessage);
				break;
		}
	}
	
	function sendRequestStart(){
		//Break the message into parts, if necessary.
		xipRequestParts = [];
		var reqData = xipRequestData;
		var urlLength = xipServerUrl.length;
		var partLength = xipUrlLimit - urlLength;
		var reqIndex = 0;

		while((reqData.length - reqIndex) + urlLength > xipUrlLimit){
			xipRequestParts.push(reqData.substring(reqIndex, reqIndex + partLength));
			reqIndex += partLength;
		}
		xipRequestParts.push(reqData.substring(reqIndex, reqData.length));
		
		xipPartIndex = 0;
		sendRequestPart();
		
	}
	
	function sendRequestPart(){
		if(xipPartIndex < xipRequestParts.length){
			//Get the message part.
			var partData = xipRequestParts[xipPartIndex];

			//Get the command.
			var cmd = "part";
			if(xipPartIndex + 1 == xipRequestParts.length){
				cmd = "end";
			}else if (xipPartIndex == 0){
				cmd = "start";
			}
			
			setServerUrl(cmd, partData);
			xipPartIndex++;
		}
	}
	
	function setServerUrl(cmd, message){
		var serverUrl = xipServerUrl + "#" + (xipIdCounter++) + ":" + cmd;
		if(message){
			serverUrl += ":" + message;
		}

		//Safari won't let us replace across domains.
		if(navigator.userAgent.indexOf("Safari") == -1){
			xipServerWindow.location.replace(serverUrl);
		}else{
			xipServerWindow.location = serverUrl;
		}

	}
	// -->
	</script>
</head>
<body>
	<h4>The Dojo Toolkit -- xip_client.html</h4>

	<p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used
	internally by dojo.io.XhrIframeProxy.</p>
	
	<iframe id="xipServerFrame"></iframe>
</body>
</html>

__CPAN_DIR__ src/charting
__CPAN_FILE__ src/charting/Plot.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.Plot");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.Axis");
dojo.require("dojo.charting.Series");

dojo.charting.RenderPlotSeries = { Singly:"single", Grouped:"grouped" };

dojo.charting.Plot = function(
	/* dojo.charting.Axis? */xaxis, 
	/* dojo.charting.Axis? */yaxis, 
	/* dojo.charting.Series[]? */series
){
	//	summary
	//	Creates a new instance of a Plot (X/Y Axis + n Series).
	var id = "dojo-charting-plot-"+dojo.charting.Plot.count++;
	this.getId=function(){ return id; };
	this.setId=function(key){ id = key; };
	this.axisX = null;
	this.axisY = null;
	this.series = [];
	this.dataNode = null;

	//	for bar charts, pie charts and stacked charts, change to Grouped.
	this.renderType = dojo.charting.RenderPlotSeries.Singly;
	if(xaxis){
		this.setAxis(xaxis,"x");
	}
	if(yaxis){
		this.setAxis(yaxis,"y");
	}
	if(series){
		for(var i=0; i<series.length; i++){ this.addSeries(series[i]); }
	}
}
dojo.charting.Plot.count=0;

dojo.extend(dojo.charting.Plot, {
	addSeries: function(
		/* dojo.charting.Series || object */series,
		/* function? */plotter
	){
		//	summary
		//	Add a new Series to this plot.  Can take the form of a Series, or an object
		//	of the form { series, plotter }
		if(series.plotter){
			this.series.push(series);
		} else {
			this.series.push({
				data: series,
				plotter: plotter || dojo.charting.Plotters["Default"]
			});
		}
	},
	setAxis: function(/* dojo.charting.Axis */axis, /* string */which){
		//	summary
		//	Set the axis on which plane.
		if(which.toLowerCase()=="x"){ this.axisX = axis; }
		else if(which.toLowerCase()=="y"){ this.axisY = axis; }
	},
	getRanges: function(){
		//	summary
		//	set the ranges on these axes.
		var xmin, xmax, ymin, ymax;
		xmin=ymin=Number.MAX_VALUE;
		xmax=ymax=Number.MIN_VALUE;
		for(var i=0; i<this.series.length; i++){
			var values = this.series[i].data.evaluate();	//	full data range.
			for(var j=0; j<values.length; j++){
				var comp=values[j];
				xmin=Math.min(comp.x, xmin);
				ymin=Math.min(comp.y, ymin);
				xmax=Math.max(comp.x, xmax);
				ymax=Math.max(comp.y, ymax);
			}
		}
		return {
			x:{ upper: xmax, lower:xmin },
			y:{ upper: ymax, lower:ymin },
			toString:function(){
				return "[ x:"+xmax+" - "+xmin+", y:"+ymax+" - "+ymin+"]";
			}
		};	//	object
	},
	destroy: function(){
		//	summary
		//	Clean out any existing DOM node references.
		var node=this.dataNode;
		while(node && node.childNodes && node.childNodes.length > 0){
			node.removeChild(node.childNodes[0]);
		}
		this.dataNode=null;
	}
});

__CPAN_FILE__ src/charting/README.txt
Dojo Charting Engine
=========================================================================
The Dojo Charting Engine is a (fairly) complex object structure, designed
to provide as much flexibility as possible in terms of chart construction.
To this end, the engine details the following structure:

Chart
---PlotArea[]
------Plot[]
---------Axis (axisX)
---------Axis (axisY)
---------Series[]


A Chart object is the main entity; it is the entire graphic.  A Chart may
have any number of PlotArea objects, which are the basic canvas against 
which data is plotted.  A PlotArea may have any number of Plot objects,
which is a container representing up to 2 axes and any number of series
to be plotted against those axes; a Series represents a binding against
two fields from a data source (initial rev, this data source is always of
type dojo.collections.Store but this will probably change once dojo.data
is in production).

The point of this structure is to allow for as much flexibility as possible
in terms of what kinds of charts can be represented by the engine.  The
current plan is to accomodate up to analytical financial charts, which tend
to have 3 plot areas and any number of different types of axes on each one.

The main exception to this is the pie chart, which will have it's own
custom codebase.  Also, 3D charts are not accounted for at this time,
although the only thing that will probably need to be altered to make
that work would be Plot and Series (to accomodate the additional Z axis).

Finally, a Plot will render its series[] through the use of Plotters, which
are custom methods to render specific types of charts.
-------------------------------------------------------------------------
In terms of widgets, the basic concept is that there is a central, super-
flexible Chart widget (Chart, oddly enough), and then any number of preset
chart type widgets, that are basically built to serve a simple, easy 
purpose.  For instance, if someone just needs to plot a series of lines,
they would be better off using the LineChart widget; but if someone needed
to plot a combo chart, that has 2 Y Axes (one linear, one log) against the
same X Axis, using lines and areas, then they will want to use a Chart widget.
Note also that unlike other widgets, the Charting engine *can* be called
directly from script *without* the need for the actual widget engine to be
loaded; the Chart widgets are thin wrappers around the charting engine.
__CPAN_FILE__ src/charting/PlotArea.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.PlotArea");
dojo.require("dojo.lang.common");
dojo.require("dojo.gfx.color");
dojo.require("dojo.gfx.color.hsl");
dojo.require("dojo.charting.Plot");

dojo.charting.PlotArea = function(){
	//	summary
	//	Creates a new PlotArea for drawing onto a Chart.
	var id="dojo-charting-plotarea-"+dojo.charting.PlotArea.count++;
	this.getId=function(){ return id; };
	this.setId=function(key){ id = key; };
	this.areaType = "standard"; 	//	standard || radar
	this.plots = [];	//	plots that will be drawn on this area

	this.size={ width:600, height:400 };
	this.padding={ top:10, right:10, bottom:20, left:20 };

	//	drawing node references.
	this.nodes = {
		main:null,
		area:null,
		background: null,
		axes: null,
		plots: null
	};

	//	this is preset for a limited color range (green to purple), 
	//	anticipating a max of 32 series on this plot area.
	//	if you need more flexibility, override these numbers.
	this._color = { h: 140, s: 120, l: 120, step: 27 };
};
dojo.charting.PlotArea.count = 0;

dojo.extend(dojo.charting.PlotArea, {
	nextColor: function(){
		//	summary
		//	Advances the internal HSV cursor and returns the next generated color.
		var rgb=dojo.gfx.color.hsl2rgb(this._color.h, this._color.s, this._color.l);
		this._color.h = (this._color.h + this._color.step)%360;
		while(this._color.h < 140){ 
			this._color.h += this._color.step; 
		}
		return dojo.gfx.color.rgb2hex(rgb[0], rgb[1], rgb[2]);	//	string
	},
	getArea:function(){
		//	summary
		//	Return an object describing the coordinates of the available area to plot on.
		return {
			left: this.padding.left,
			right: this.size.width - this.padding.right,
			top: this.padding.top,
			bottom: this.size.height - this.padding.bottom,
			toString:function(){ 
				var a=[ this.top, this.right, this.bottom, this.left ];
				return "["+a.join()+"]";
			}
		};	//	object
	},
	getAxes: function(){
		//	summary
		//	get the unique axes for this plot area.
		var axes={};
		for(var i=0; i<this.plots.length; i++){
			var plot=this.plots[i];
			axes[plot.axisX.getId()] = {
				axis: plot.axisX,
				drawAgainst: plot.axisY,
				plot: plot,
				plane: "x"
			};
			axes[plot.axisY.getId()] = {
				axis: plot.axisY,
				drawAgainst: plot.axisX,
				plot: plot,
				plane: "y"
			};
		}
		return axes;	//	object 
	},
	getLegendInfo: function(){
		//	summary
		//	return an array describing all data series on this plot area.
		var a=[];
		for(var i=0; i<this.plots.length; i++){
			for(var j=0; j<this.plots[i].series.length; j++){
				var data = this.plots[i].series[j].data;
				a.push({ label:data.label, color:data.color });
			}
		}
		return a;	//	array
	},
	setAxesRanges: function(){
		//	summary
		//	Find and set the ranges on all axes on this plotArea.
		//	We do this because plots may have axes in common; if you
		//	want to use this, make sure you do it *before* initialization.
		var ranges={};
		var axes={};
		for(var i=0; i<this.plots.length; i++){
			var plot = this.plots[i];
			var ranges=plot.getRanges();
			var x=ranges.x;
			var y=ranges.y;
			var ax, ay;
			if(!axes[plot.axisX.getId()]){
				axes[plot.axisX.getId()]=plot.axisX;
				ranges[plot.axisX.getId()]={upper: x.upper, lower:x.lower};
			}
			ax=ranges[plot.axisX.getId()];
			ax.upper=Math.max(ax.upper, x.upper);
			ax.lower=Math.min(ax.lower, x.lower);

			if(!axes[plot.axisY.getId()]){
				axes[plot.axisY.getId()]=plot.axisY;
				ranges[plot.axisY.getId()]={upper: y.upper, lower:y.lower};
			}
			ay=ranges[plot.axisY.getId()];
			ay.upper=Math.max(ay.upper, y.upper);
			ay.lower=Math.min(ay.lower, y.lower);
		}
		
		//	now that we have all the max/min ranges, set the axes
		for(var p in axes){
			axes[p].range=ranges[p];
		}
	},

	render: function(/* object? */kwArgs, /* function? */applyToData){
		//	summary
		//	Render this plotArea.  Optional kwArgs are the same as that taken for Series.evaluate;
		//	applyToData is a callback function used by plotters for customization.
		if(!this.nodes.main
			|| !this.nodes.area 
			|| !this.nodes.background 
			|| !this.nodes.plots 
			|| !this.nodes.axes
		){ this.initialize(); }

		//	plot it.
		for(var i=0; i<this.plots.length; i++){
			var plot=this.plots[i];
			this.nodes.plots.removeChild(plot.dataNode);
			var target = this.initializePlot(plot);
			switch(plot.renderType){
				case dojo.charting.RenderPlotSeries.Grouped:	{
					// ALWAYS plot using the first plotter, ignore any others.
					target.appendChild(plot.series[0].plotter(this, plot, kwArgs, applyToData));
					break;
				}
				case dojo.charting.RenderPlotSeries.Singly:
				default: {
					for(var j=0; j<plot.series.length; j++){
						var series = plot.series[j];
						var data = series.data.evaluate(kwArgs);
						target.appendChild(series.plotter(data, this, plot, applyToData));
					}
				}
			}
			this.nodes.plots.appendChild(target);
		}
	},
	destroy: function(){
		//	summary
		//	Clean out any existing DOM references.
		for(var i=0; i<this.plots.length; i++){
			this.plots[i].destroy();
		};
		//	clean out any child nodes.
		for(var p in this.nodes){
			var node=this.nodes[p];
			if(!node) continue;
			if(!node.childNodes) continue;
			while(node.childNodes.length > 0){ 
				node.removeChild(node.childNodes[0]); 
			}
			this.nodes[p]=null;
		}
	}
});

dojo["requireIf"](dojo.render.svg.capable, "dojo.charting.svg.PlotArea");
dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.charting.vml.PlotArea");

__CPAN_FILE__ src/charting/Series.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.Series");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.Plotters");

dojo.charting.Series = function(/* object? */kwArgs){
	//	summary
	//	Create an instance of data series for plotting.
	var args = kwArgs || { length:1 };
	this.dataSource = args.dataSource || null;
	this.bindings = { };
	this.color = args.color;
	this.label = args.label;

	if(args.bindings){
		for(var p in args.bindings){
			this.addBinding(p, args.bindings[p]);
		}
	}
};

dojo.extend(dojo.charting.Series, {
	bind:function(/* dojo.collections.Store */src, /* object */bindings){
		//	summary
		//	Bind this series to src, with bindings.
		this.dataSource = src;
		this.bindings = bindings;
	},
	addBinding:function(/* string */name, /* string */binding){
		//	summary
		//	Bind to field "binding" using "name".
		this.bindings[name] = binding;
	},
	evaluate:function(/* object? */kwArgs){
		//	summary
		//	Evaluate all bindings and return an array of objects describing the bind.
		var ret = [];
		var a = this.dataSource.getData();
		var l = a.length;
		var start = 0;
		var end = l;
		
		/*	Allow for ranges.  Can be done in one of two ways:
		 *	1. { from, to } as 0-based indices
		 *	2. { length } as num of data points to get; a negative
		 *		value will start from the end of the data set.
		 *	No kwArg object means the full data set will be evaluated
		 *		and returned.
		 */
		if(kwArgs){
			if(kwArgs.from){ 
				start = Math.max(kwArgs.from,0);
				if(kwArgs.to){ 
					end = Math.min(kwArgs.to, end);
				}
			}
			else if(kwArgs.length){
				if(kwArgs.length < 0){
					//	length points from end
					start = Math.max((end + length),0);
				} else {
					end = Math.min((start + length), end);
				}
			}
		}

		for(var i=start; i<end; i++){
			var o = { src: a[i], series: this };
			for(var p in this.bindings){
				o[p] = this.dataSource.getField(a[i], this.bindings[p]);
			}
			ret.push(o);
		}

		//	sort by the x axis, if available.
		if(typeof(ret[0].x) != "undefined"){
			ret.sort(function(a,b){
				if(a.x > b.x) return 1;
				if(a.x < b.x) return -1;
				return 0;
			});
		}
		return ret;	//	array
	},

	//	trends
	trends:{
		createRange: function(/* array */values, /* int */len){
			//	summary
			//	Creates the data range used for all trends.
			var idx = values.length-1;
			var length = (len||values.length);
			return { "index": idx, "length": length, "start":Math.max(idx-length,0) };	//	object
		},

		mean: function(/* array */values, /* int */len){
			//	summary
			//	Returns the mean or average over the set of values.
			var range = this.createRange(values, len);
			if(range.index<0){ return 0; }
			var total = 0;
			var count = 0;
			for(var i=range.index; i>=range.start; i--){
				total += values[i].y; 
				count++;
			}
			total /= Math.max(count,1);
			return total;	//	float
		},

		variance: function(/* array */values,/* int */len){
			//	summary
			//	Returns the variance of the set of values.
			var range = this.createRange(values,len);
			if(range.index < 0){ return 0; }
			var total = 0;
			var square = 0;
			var count = 0;
			for(var i=range.index; i>=range.start; i--){
				total += values[i].y;
				square += Math.pow(values[i].y, 2);
				count++;
			}
			return (square/count)-Math.pow(total/count,2);	//	float
		},

		standardDeviation: function(/* array */values, /* int */len){
			//	summary
			//	Returns the standard deviation of the set of values.
			return Math.sqrt(this.getVariance(values, len));	//	float
		},

		max: function(/* array */values, /* int */len){
			//	summary
			//	Returns the max number in the set of values.
			var range = this.createRange(values, len);
			if(range.index < 0){ return 0; }
			var max = Number.MIN_VALUE;
			for (var i=range.index; i>=range.start; i--){
				max = Math.max(values[i].y,max);
			}
			return max;	//	float
		},

		min: function(/* array */values, /* int */len){
			//	summary
			//	Returns the lowest number in the set of values.
			var range=this.createRange(values, len);
			if(range.index < 0){ return 0; }
			var min = Number.MAX_VALUE;
			for(var i=range.index; i>=range.start; i--){
				min = Math.min(values[i].y, min);
			}
			return min;	//	float
		},

		median: function(/* array */values, /* int */len){
			//	summary
			//	Returns the median in the set of values (number closest to the middle of a sorted set).
			var range = this.createRange(values, len);
			if(range.index<0){ return 0; }
			var a = [];
			for (var i=range.index; i>=range.start; i--){
				var b=false;
				for(var j=0; j<a.length; j++){
					if(values[i].y == a[j]){
						b = true;
						break;
					}
				}
				if(!b){ 
					a.push(values[i].y); 
				}
			}
			a.sort();
			if(a.length > 0){ 
				return a[Math.ceil(a.length / 2)]; 	//	float
			}
			return 0;	//	float
		},

		mode: function(/* array */values, /* int */len){
			//	summary
			//	Returns the mode in the set of values
			var range=this.createRange(values, len);
			if(range.index<0){ return 0; }
			var o = {};
			var ret = 0
			var median = Number.MIN_VALUE;
			for(var i=range.index; i>=range.start; i--){
				if (!o[values[i].y]){
					o[values[i].y] = 1;
				} else { 
					o[values[i].y]++;
				}
			}
			for(var p in o){
				if(median < o[p]){ 
					median = o[p]; 
					ret=p; 
				}
			}
			return ret;
		}
	}
});

__CPAN_FILE__ src/charting/Chart.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.Chart");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.PlotArea");

dojo.charting.Chart = function(
	/* HTMLElement? */node, 
	/* string? */title, 
	/* string? */description
){
	//	summary
	//	Create the basic Chart object.
	this.node = node || null;
	this.title = title || "Chart";			//	pure string.
	this.description = description || "";	//	HTML is allowed.
	this.plotAreas = [];
};

dojo.extend(dojo.charting.Chart, {
	//	methods
	addPlotArea: function(/* object */obj, /* bool? */doRender){
		//	summary
		//	Add a PlotArea to this chart; object should be in the
		//	form of: { plotArea, (x, y) or (top, left) }
		if(obj.x && !obj.left){ obj.left = obj.x; }
		if(obj.y && !obj.top){ obj.top = obj.y; }
		this.plotAreas.push(obj);
		if(doRender){ this.render(); }
	},
	
	//	events
	onInitialize:function(chart){ },
	onRender:function(chart){ },
	onDestroy:function(chart){ },

	//	standard build methods
	initialize: function(){
		//	summary
		//	Initialize the Chart by rendering it.
		if(!this.node){ 
			dojo.raise("dojo.charting.Chart.initialize: there must be a root node defined for the Chart."); 
		}
		this.destroy();
		this.render();
		this.onInitialize(this);
	},
	render:function(){
		//	summary
		//	Render the chart in its entirety.
		if(this.node.style.position != "absolute"){
			this.node.style.position = "relative";
		}
		for(var i=0; i<this.plotAreas.length; i++){
			var area = this.plotAreas[i].plotArea;
			var node = area.initialize();
			node.style.position = "absolute";
			node.style.top = this.plotAreas[i].top + "px";
			node.style.left = this.plotAreas[i].left + "px";
			this.node.appendChild(node);
			area.render();
		}
	},
	destroy: function(){
		//	summary
		//	Destroy any nodes that have maintained references.

		//	kill any existing plotAreas
		for(var i=0; i<this.plotAreas.length; i++){
			this.plotAreas[i].plotArea.destroy();
		};
		//	clean out any child nodes.
		while(this.node && this.node.childNodes && this.node.childNodes.length > 0){ 
			this.node.removeChild(this.node.childNodes[0]); 
		}
	}
});

__CPAN_FILE__ src/charting/Plotters.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.Plotters");

/*	
 *	Plotters is the placeholder; what will happen is that the proper renderer types
 *	will be mixed into this object (as opposed to creating a new one).
 */

dojo["requireIf"](dojo.render.svg.capable, "dojo.charting.svg.Plotters");
dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.charting.vml.Plotters");

__CPAN_FILE__ src/charting/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.*");

__CPAN_FILE__ src/charting/Axis.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.Axis");
dojo.require("dojo.lang.common");

dojo.charting.Axis = function(/* string? */label, /* string? */scale, /* array? */labels){
	var id = "dojo-charting-axis-"+dojo.charting.Axis.count++;
	this.getId=function(){ return id; };
	this.setId=function(key){ id = key; };
	this.scale = scale || "linear";		//	linear || log
	this.label = label || "";
	this.showLabel = true;		//	show axis label.
	this.showLabels = true;		//	show interval ticks.
	this.showLines = false;		//	if you want lines over the range of the plot area
	this.showTicks = false;		//	if you want tick marks on the axis.
	this.range = { upper : 0, lower : 0 };	//	range of individual axis.
	this.origin = "min"; 			//	this can be any number, "min" or "max". min/max is translated on init.

	this.labels = labels || [];
	this._labels = [];	//	what we really use to draw things.
	this.nodes={ main: null, axis: null, label: null, labels: null, lines: null, ticks: null };
};
dojo.charting.Axis.count = 0;

dojo.extend(dojo.charting.Axis, {
	//	TODO: implement log scaling.
	getCoord: function(
		/* float */val, 
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot
	){
		//	summary
		//	returns the coordinate of val based on this axis range, plot area and plot.
		val = parseFloat(val, 10);
		var area = plotArea.getArea();
		if(plot.axisX == this){
			var offset = 0 - this.range.lower;
			var min = this.range.lower + offset;	//	FIXME: check this.
			var max = this.range.upper + offset;
			val += offset;
			return (val*((area.right-area.left)/max))+area.left;	//	float
		} else {
			var max = this.range.upper;
			var min = this.range.lower;
			var offset = 0;
			if(min<0){
				offset += Math.abs(min);
			}
			max += offset; min += offset; val += offset;
			var pmin = area.bottom;
			var pmax = area.top;
			return (((pmin-pmax)/(max-min))*(max-val))+pmax;
		}
	},
	initializeOrigin: function(drawAgainst, plane){
		//	figure out the origin value.
		if(isNaN(this.origin)){
			if(this.origin.toLowerCase() == "max"){ 
				this.origin = drawAgainst.range[(plane=="y")?"upper":"lower"]; 
			}
			else if (this.origin.toLowerCase() == "min"){ 
				this.origin = drawAgainst.range[(plane=="y")?"lower":"upper"]; 
			}
			else { this.origin=0; }
		}
	},
	initializeLabels: function(){
		//	Translate the labels if needed.
		if(this.labels.length == 0){
			this.showLabels = false;
			this.showLines = false;
			this.showTicks = false;
		} else {
			if(this.labels[0].label && this.labels[0].value != null){
				for(var i=0; i<this.labels.length; i++){
					this._labels.push(this.labels[i]);
				}
			}
			else if(!isNaN(this.labels[0])){
				for(var i=0; i<this.labels.length; i++){
					this._labels.push({ label: this.labels[i], value: this.labels[i] });
				}
			}
			else {
				// clone me
				var a = [];
				for(var i=0; i<this.labels.length; i++){
					a.push(this.labels[i]);
				}

				//	do the bottom one.
				var s=a.shift();
				this._labels.push({ label: s, value: this.range.lower });

				//	do the top one.
				if(a.length>0){
					var s=a.pop();
					this._labels.push({ label: s, value: this.range.upper });
				}
				//	do the rest.
				if(a.length>0){
					var range = this.range.upper - this.range.lower;
					var step = range / (this.labels.length-1);
					for(var i=1; i<=a.length; i++){
						this._labels.push({
							label: a[i-1],
							value: this.range.lower+(step*i)
						});
					}
				}
			}
		}
	},
	initialize: function(plotArea, plot, drawAgainst, plane){
		//	summary
		//	Initialize the passed axis descriptor.  Note that this should always
		//	be the result of plotArea.getAxes, and not the axis directly!
		this.destroy();
		this.initializeOrigin(drawAgainst, plane);
		this.initializeLabels();
		var node = this.render(plotArea, plot, drawAgainst, plane);
		return node;
	},
	destroy: function(){
		for(var p in this.nodes){
			while(this.nodes[p] && this.nodes[p].childNodes.length > 0){
				this.nodes[p].removeChild(this.nodes[p].childNodes[0]);
			}
			if(this.nodes[p] && this.nodes[p].parentNode){
				this.nodes[p].parentNode.removeChild(this.nodes[p]);
			}
			this.nodes[p] = null;
		}
	}
});

dojo["requireIf"](dojo.render.svg.capable, "dojo.charting.svg.Axis");
dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.charting.vml.Axis");

__CPAN_DIR__ src/charting/svg
__CPAN_FILE__ src/charting/svg/PlotArea.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.svg.PlotArea");
dojo.require("dojo.lang.common");
dojo.require("dojo.svg");

dojo.extend(dojo.charting.PlotArea, {
	initializePlot: function(plot){
		//	summary
		//	Initialize the plot node for data rendering.
		plot.destroy();
		plot.dataNode = document.createElementNS(dojo.svg.xmlns.svg, "g");
		plot.dataNode.setAttribute("id", plot.getId());
		return plot.dataNode;	//	SVGGElement
	},
	initialize: function(){
		//	summary
		//	Initialize the PlotArea.
	
		this.destroy();	//	kill everything first.
		
		//	start with the background
		this.nodes.main = document.createElement("div");

		this.nodes.area = document.createElementNS(dojo.svg.xmlns.svg, "svg");
		this.nodes.area.setAttribute("id", this.getId());
		this.nodes.area.setAttribute("width", this.size.width);
		this.nodes.area.setAttribute("height", this.size.height);
		this.nodes.main.appendChild(this.nodes.area);

		var area=this.getArea();
		var defs = document.createElementNS(dojo.svg.xmlns.svg, "defs");
		var clip = document.createElementNS(dojo.svg.xmlns.svg, "clipPath");
		clip.setAttribute("id",this.getId()+"-clip");
		var rect = document.createElementNS(dojo.svg.xmlns.svg, "rect");		
		rect.setAttribute("x", area.left);
		rect.setAttribute("y", area.top);
		rect.setAttribute("width", area.right-area.left);
		rect.setAttribute("height", area.bottom-area.top);
		clip.appendChild(rect);
		defs.appendChild(clip);
		this.nodes.area.appendChild(defs);
		
		this.nodes.background = document.createElementNS(dojo.svg.xmlns.svg, "rect");
		this.nodes.background.setAttribute("id", this.getId()+"-background");
		this.nodes.background.setAttribute("width", this.size.width);
		this.nodes.background.setAttribute("height", this.size.height);
		this.nodes.background.setAttribute("fill", "#fff");
		this.nodes.area.appendChild(this.nodes.background);

		this.nodes.plots = document.createElementNS(dojo.svg.xmlns.svg, "g");
		this.nodes.plots.setAttribute("id", this.getId()+"-plots");
		this.nodes.plots.setAttribute("style","clip-path:url(#"+this.getId()+"-clip);");
		this.nodes.area.appendChild(this.nodes.plots);

		for(var i=0; i<this.plots.length; i++){
			this.nodes.plots.appendChild(this.initializePlot(this.plots[i]));
		}

		//	do the axes
		this.nodes.axes = document.createElementNS(dojo.svg.xmlns.svg, "g");
		this.nodes.axes.setAttribute("id", this.getId()+"-axes");
		this.nodes.area.appendChild(this.nodes.axes);
		var axes = this.getAxes();
		for(var p in axes){
			var obj = axes[p];
			this.nodes.axes.appendChild(obj.axis.initialize(this, obj.plot, obj.drawAgainst, obj.plane));
		}
		return this.nodes.main;	//	HTMLDivElement
	}
});

__CPAN_FILE__ src/charting/svg/Plotters.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.svg.Plotters");
dojo.require("dojo.lang.common");
dojo.require("dojo.svg");

//	TODO for 0.5: look at replacing manual plotting with dojo.gfx.

//	Mixin the SVG-specific plotter object.
dojo.mixin(dojo.charting.Plotters, {
	/*********************************************************
	 *	Grouped plotters: need all series on a plot at once.
	 *********************************************************/
	Bar: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of grouped bars.
		//	Bindings: y
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		
		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			data.push(tmp);
		}

		//	calculate the width of each bar.
		var space = 8;
		var nPoints = data[0].length;
		var width = ((area.right-area.left)-(space*(nPoints-1)))/nPoints;	//	the width of each group.
		var barWidth = width/n;	//	the width of each bar, no spaces.
		var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot);

		for(var i=0; i<nPoints; i++){
			//	calculate offset
			var xStart = area.left+(width*i)+(space*i);
			for(var j=0; j<n; j++){
				var value = data[j][i].y;
				var yA = yOrigin;
				var x = xStart + (barWidth*j);
				var y = plot.axisY.getCoord(value, plotarea, plot);
				var h = Math.abs(yA-y);
				if(value < plot.axisX.origin){
					yA = y;
					y = yOrigin;
				}
				
				var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
				bar.setAttribute("fill", data[j][i].series.color);
				bar.setAttribute("stroke-width", "0");
				bar.setAttribute("x", x);
				bar.setAttribute("y", y);
				bar.setAttribute("width", barWidth);
				bar.setAttribute("height", h);
				bar.setAttribute("fill-opacity", "0.6");
				if(applyTo){ applyTo(bar, data[j][i].src); }
				group.appendChild(bar);
			}
		}
		return group;	// SVGGElement
	},
	HorizontalBar: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots data in a set of grouped bars horizontally.
		//	Bindings: y
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		
		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			data.push(tmp);
		}

		var space = 6;
		var nPoints = data[0].length;
		var h = ((area.bottom-area.top)-(space*(nPoints-1)))/nPoints;
		var barH = h/n;
		var xOrigin = plot.axisX.getCoord(0, plotarea, plot);

		for(var i=0; i<nPoints; i++){
			//	calculate offset
			var yStart = area.top+(h*i)+(space*i);
			for(var j=0; j<n; j++){
				var value = data[j][i].y;
				var y = yStart + (barH*j);
				var xA = xOrigin;
				var x = plot.axisX.getCoord(value, plotarea, plot);
				var w = Math.abs(x-xA);
				if(value > 0){
					x = xOrigin;
				}
				
				var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
				bar.setAttribute("fill", data[j][i].series.color);
				bar.setAttribute("stroke-width", "0");
				bar.setAttribute("x", xA);
				bar.setAttribute("y", y);
				bar.setAttribute("width", w);
				bar.setAttribute("height", barH);
				bar.setAttribute("fill-opacity", "0.6");
				if(applyTo){ applyTo(bar, data[j][i].src); }
				group.appendChild(bar);
			}
		}
		return group;	//	SVGGElement
	},
	Gantt: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a grouped set of Gantt bars
		//	Bindings: high/low
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");

		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			data.push(tmp);
		}

		var space = 2;
		var nPoints = data[0].length;
		var h = ((area.bottom-area.top)-(space*(nPoints-1)))/nPoints;
		var barH = h/n;
		for(var i=0; i<nPoints; i++){
			//	calculate offset
			var yStart = area.top+(h*i)+(space*i);
			for(var j=0; j<n; j++){
				var high = data[j][i].high;
				var low = data[j][i].low;
				if(low > high){
					var t = high;
					high = low;
					low = t;
				}
				var x = plot.axisX.getCoord(low, plotarea, plot);
				var w = plot.axisX.getCoord(high, plotarea, plot) - x;
				var y = yStart + (barH*j);
				
				var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
				bar.setAttribute("fill", data[j][i].series.color);
				bar.setAttribute("stroke-width", "0");
				bar.setAttribute("x", x);
				bar.setAttribute("y", y);
				bar.setAttribute("width", w);
				bar.setAttribute("height", barH);
				bar.setAttribute("fill-opacity", "0.6");
				if(applyTo){ applyTo(bar, data[j][i].src); }
				group.appendChild(bar);
			}
		}
		return group;	//	SVGGElement
	},
	StackedArea: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of stacked areas.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");

		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		var totals = [];

		//	we're assuming that all series for this plot has the name x assignment for now.
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			//	run through and add current totals
			for(var j=0; j<tmp.length; j++){
				if(i==0){ totals.push(tmp[j].y); }
				else { totals[j] += tmp[j].y; }
				tmp[j].y = totals[j];
			}
			data.push(tmp);
		}

		for(var i=n-1; i>=0; i--){
			var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
			path.setAttribute("fill", data[i][0].series.color);
			path.setAttribute("fill-opacity", "0.4");
			path.setAttribute("stroke", data[i][0].series.color);
			path.setAttribute("stroke-width" , "1");
			path.setAttribute("stroke-opacity", "0.85");

			var cmd = [];
			var r=3;
			for(var j=0; j<data[i].length; j++){
				var values = data[i];
				var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
				var y = plot.axisY.getCoord(values[j].y, plotarea, plot);

				if(j==0){ cmd.push("M"); }
				else { cmd.push("L"); }
				cmd.push(x+","+y);
				
				//	points on the line
				var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
				c.setAttribute("cx",x);
				c.setAttribute("cy",y);
				c.setAttribute("r","3");
				c.setAttribute("fill", values[j].series.color);
				c.setAttribute("fill-opacity", "0.6");
				c.setAttribute("stroke-width", "1");
				c.setAttribute("stroke-opacity", "0.85");
				group.appendChild(c);
				if(applyTo){ applyTo(c, data[i].src); }
			}

			//	now run the path backwards from the previous series.
			if(i == 0){
				cmd.push("L");
				cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
				cmd.push("L");
				cmd.push(plot.axisX.getCoord(data[0][0].x, plotarea, plot) + "," +  plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
				cmd.push("Z");
			} else {
				var values = data[i-1];
				cmd.push("L");
				cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot)));
				for(var j=values.length-2; j>=0; j--){
					var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
					var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
					cmd.push("L");
					cmd.push(x+","+y);
				}
			}
			path.setAttribute("d", cmd.join(" ")+ " Z");
			group.appendChild(path);
		}
		return group;	//	SVGGElement
	},
	StackedCurvedArea: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of stacked areas, using a tensioning factor to soften points.
		//	Bindings: x/y
		var tension = 3;
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");

		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		var totals = [];

		//	we're assuming that all series for this plot has the name x assignment for now.
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			//	run through and add current totals
			for(var j=0; j<tmp.length; j++){
				if(i==0){ totals.push(tmp[j].y); }
				else { totals[j] += tmp[j].y; }
				tmp[j].y = totals[j];
			}
			data.push(tmp);
		}

		for(var i=n-1; i>=0; i--){
			var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
			path.setAttribute("fill", data[i][0].series.color);
			path.setAttribute("fill-opacity", "0.4");
			path.setAttribute("stroke", data[i][0].series.color);
			path.setAttribute("stroke-width" , "1");
			path.setAttribute("stroke-opacity", "0.85");

			var cmd = [];
			var r=3;
			for(var j=0; j<data[i].length; j++){
				var values = data[i];
				var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
				var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
				var dx = area.left + 1;
				var dy = area.bottom;
				if(j>0){
					dx = x - plot.axisX.getCoord(values[j-1].x, plotarea, plot);
					dy = plot.axisY.getCoord(values[j-1].y, plotarea, plot);
				}

				if(j==0){ cmd.push("M"); }
				else {
					cmd.push("C");
					var cx = x-(tension-1) * (dx/tension);
					cmd.push(cx + "," + dy);
					cx = x - (dx/tension);
					cmd.push(cx + "," + y);
				}
				cmd.push(x+","+y);
				
				//	points on the line
				var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
				c.setAttribute("cx",x);
				c.setAttribute("cy",y);
				c.setAttribute("r","3");
				c.setAttribute("fill", values[j].series.color);
				c.setAttribute("fill-opacity", "0.6");
				c.setAttribute("stroke-width", "1");
				c.setAttribute("stroke-opacity", "0.85");
				group.appendChild(c);
				if(applyTo){ applyTo(c, data[i].src); }
			}

			//	now run the path backwards from the previous series.
			if(i == 0){
				cmd.push("L");
				cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
				cmd.push("L");
				cmd.push(plot.axisX.getCoord(data[0][0].x, plotarea, plot) + "," +  plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
				cmd.push("Z");
			} else {
				var values = data[i-1];
				cmd.push("L");
				cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot)));
				for(var j=values.length-2; j>=0; j--){
					var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
					var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
					var dx = x - plot.axisX.getCoord(values[j+1].x, plotarea, plot);
					var dy = plot.axisY.getCoord(values[j+1].y, plotarea, plot);

					cmd.push("C");
					var cx = x-(tension-1) * (dx/tension);
					cmd.push(cx + "," + dy);
					cx = x - (dx/tension);
					cmd.push(cx + "," + y);
					cmd.push(x+","+y);
				}
			}
			path.setAttribute("d", cmd.join(" ")+ " Z");
			group.appendChild(path);
		}
		return group;	//	SVGGElement
	},

	/*********************************************************
	 *	Single plotters: one series at a time.
	 *********************************************************/
	DataBar: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of bars in relation to y==0.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		
		var n = data.length;
		var w = (area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower);	//	the width of each group.
		var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot);

		for(var i=0; i<n; i++){
			//	calculate offset
			var value = data[i].y;
			var yA = yOrigin;
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(value, plotarea, plot);
			var h = Math.abs(yA-y);
			if(value < plot.axisX.origin){
				yA = y;
				y = yOrigin;
			}
			var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
			bar.setAttribute("fill", data[i].series.color);
			bar.setAttribute("stroke-width", "0");
			bar.setAttribute("x", x);
			bar.setAttribute("y", y);
			bar.setAttribute("width", w);
			bar.setAttribute("height", h);
			bar.setAttribute("fill-opacity", "0.6");
			if(applyTo){ applyTo(bar, data[i].src); }
			group.appendChild(bar);
		}
		return group;	//	SVGGElement
	},
	Line: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a line.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
		var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
		line.appendChild(path);

		path.setAttribute("fill", "none");
		path.setAttribute("stroke", data[0].series.color);
		path.setAttribute("stroke-width" , "2");
		path.setAttribute("stroke-opacity", "0.85");
		if(data[0].series.label != null){
			path.setAttribute("title", data[0].series.label);
		}

		var cmd=[];
		for(var i=0; i<data.length; i++){
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
			var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
			if(i==0){ cmd.push("M"); }
			else { cmd.push("L"); }
			cmd.push(x+","+y);
			
			//	points on the line
			var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
			c.setAttribute("cx",x);
			c.setAttribute("cy",y);
			c.setAttribute("r","3");
			c.setAttribute("fill", data[i].series.color);
			c.setAttribute("fill-opacity", "0.6");
			c.setAttribute("stroke-width", "1");
			c.setAttribute("stroke-opacity", "0.85");
			line.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		path.setAttribute("d", cmd.join(" "));
		return line;	//	SVGGElement
	},
	CurvedLine: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a line with a tension factor for softening.
		//	Bindings: x/y
		var tension = 3;
		var area = plotarea.getArea();
		var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
		var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
		line.appendChild(path);

		path.setAttribute("fill", "none");
		path.setAttribute("stroke", data[0].series.color);
		path.setAttribute("stroke-width" , "2");
		path.setAttribute("stroke-opacity", "0.85");
		if(data[0].series.label != null){
			path.setAttribute("title", data[0].series.label);
		}

		var cmd=[];
		for(var i=0; i<data.length; i++){
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
			var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
			var dx = area.left + 1;
			var dy = area.bottom;
			if(i>0){
				dx = x - plot.axisX.getCoord(data[i-1].x, plotarea, plot);
				dy = plot.axisY.getCoord(data[i-1].y, plotarea, plot);
			}

			if(i==0){ cmd.push("M"); }
			else {
				cmd.push("C");
				var cx = x-(tension-1) * (dx/tension);
				cmd.push(cx + "," + dy);
				cx = x - (dx/tension);
				cmd.push(cx + "," + y);
			}
			cmd.push(x+","+y);
			
			//	points on the line
			var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
			c.setAttribute("cx",x);
			c.setAttribute("cy",y);
			c.setAttribute("r","3");
			c.setAttribute("fill", data[i].series.color);
			c.setAttribute("fill-opacity", "0.6");
			c.setAttribute("stroke-width", "1");
			c.setAttribute("stroke-opacity", "0.85");
			line.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		path.setAttribute("d", cmd.join(" "));
		return line;	// SVGGElement
	},
	Area: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as an area.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
		var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
		line.appendChild(path);

		path.setAttribute("fill", data[0].series.color);
		path.setAttribute("fill-opacity", "0.4");
		path.setAttribute("stroke", data[0].series.color);
		path.setAttribute("stroke-width" , "1");
		path.setAttribute("stroke-opacity", "0.85");
		if(data[0].series.label != null){
			path.setAttribute("title", data[0].series.label);
		}

		var cmd=[];
		for(var i=0; i<data.length; i++){
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
			var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
			if(i==0){ cmd.push("M"); }
			else { cmd.push("L"); }
			cmd.push(x+","+y);
			
			//	points on the line
			var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
			c.setAttribute("cx",x);
			c.setAttribute("cy",y);
			c.setAttribute("r","3");
			c.setAttribute("fill", data[i].series.color);
			c.setAttribute("fill-opacity", "0.6");
			c.setAttribute("stroke-width", "1");
			c.setAttribute("stroke-opacity", "0.85");
			line.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		//	finish it off
		cmd.push("L");
		cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
		cmd.push("L");
		cmd.push(plot.axisX.getCoord(data[0].x, plotarea, plot) + "," +  plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
		cmd.push("Z");
		path.setAttribute("d", cmd.join(" "));
		return line;	//	SVGGElement
	},
	CurvedArea: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as an area with a tension for softening.
		//	Bindings: x/y
		var tension = 3;
		var area = plotarea.getArea();
		var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
		var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
		line.appendChild(path);

		path.setAttribute("fill", data[0].series.color);
		path.setAttribute("fill-opacity", "0.4");
		path.setAttribute("stroke", data[0].series.color);
		path.setAttribute("stroke-width" , "1");
		path.setAttribute("stroke-opacity", "0.85");
		if(data[0].series.label != null){
			path.setAttribute("title", data[0].series.label);
		}

		var cmd=[];
		for(var i=0; i<data.length; i++){
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
			var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
			var dx = area.left + 1;
			var dy = area.bottom;
			if(i>0){
				dx = x - plot.axisX.getCoord(data[i-1].x, plotarea, plot);
				dy = plot.axisY.getCoord(data[i-1].y, plotarea, plot);
			}

			if(i==0){ cmd.push("M"); }
			else {
				cmd.push("C");
				var cx = x-(tension-1) * (dx/tension);
				cmd.push(cx + "," + dy);
				cx = x - (dx/tension);
				cmd.push(cx + "," + y);
			}
			cmd.push(x+","+y);
			
			//	points on the line
			var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
			c.setAttribute("cx",x);
			c.setAttribute("cy",y);
			c.setAttribute("r","3");
			c.setAttribute("fill", data[i].series.color);
			c.setAttribute("fill-opacity", "0.6");
			c.setAttribute("stroke-width", "1");
			c.setAttribute("stroke-opacity", "0.85");
			line.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		//	finish it off
		cmd.push("L");
		cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
		cmd.push("L");
		cmd.push(plot.axisX.getCoord(data[0].x, plotarea, plot) + "," +  plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
		cmd.push("Z");
		path.setAttribute("d", cmd.join(" "));
		return line;	//	SVGGElement
	},
	HighLow: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of high/low bars.
		//	Bindings: x/high/low
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		
		var n = data.length;
		var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
		var w = part*2;

		for(var i=0; i<n; i++){
			var high = data[i].high;
			var low = data[i].low;
			if(low > high){
				var t = low;
				low = high;
				high = t;
			}

			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(high, plotarea, plot);
			var h = plot.axisY.getCoord(low, plotarea, plot)-y;

			//	high + low
			var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
			bar.setAttribute("fill", data[i].series.color);
			bar.setAttribute("stroke-width", "0");
			bar.setAttribute("x", x);
			bar.setAttribute("y", y);
			bar.setAttribute("width", w);
			bar.setAttribute("height", h);
			bar.setAttribute("fill-opacity", "0.6");
			if(applyTo){ applyTo(bar, data[i].src); }
			group.appendChild(bar);
		}
		return group;	//	SVGGElement
	},
	HighLowClose: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of high/low bars with a close indicator.
		//	Bindings: x/high/low/close
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		
		var n = data.length;
		var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
		var w = part*2;

		for(var i=0; i<n; i++){
			var high = data[i].high;
			var low = data[i].low;
			if(low > high){
				var t = low;
				low = high;
				high = t;
			}
			var c = data[i].close;

			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(high, plotarea, plot);
			var h = plot.axisY.getCoord(low, plotarea, plot)-y;
			var close = plot.axisY.getCoord(c, plotarea, plot);

			var g = document.createElementNS(dojo.svg.xmlns.svg, "g");

			//	high + low
			var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
			bar.setAttribute("fill", data[i].series.color);
			bar.setAttribute("stroke-width", "0");
			bar.setAttribute("x", x);
			bar.setAttribute("y", y);
			bar.setAttribute("width", w);
			bar.setAttribute("height", h);
			bar.setAttribute("fill-opacity", "0.6");
			g.appendChild(bar);

			//	close
			var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
			line.setAttribute("x1", x);
			line.setAttribute("x2", x+w+(part*2));
			line.setAttribute("y1", close);
			line.setAttribute("y2", close);
			line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;");
			g.appendChild(line);

			if(applyTo){ applyTo(g, data[i].src); }
			group.appendChild(g);
		}
		return group;	//	SVGGElement
	},
	HighLowOpenClose: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of high/low bars with open and close indicators.
		//	Bindings: x/high/low/open/close
		var area = plotarea.getArea();
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		
		var n = data.length;
		var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
		var w = part*2;

		for(var i=0; i<n; i++){
			var high = data[i].high;
			var low = data[i].low;
			if(low > high){
				var t = low;
				low = high;
				high = t;
			}
			var o = data[i].open;
			var c = data[i].close;

			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(high, plotarea, plot);
			var h = plot.axisY.getCoord(low, plotarea, plot)-y;
			var open = plot.axisY.getCoord(o, plotarea, plot);
			var close = plot.axisY.getCoord(c, plotarea, plot);

			var g = document.createElementNS(dojo.svg.xmlns.svg, "g");

			//	high + low
			var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
			bar.setAttribute("fill", data[i].series.color);
			bar.setAttribute("stroke-width", "0");
			bar.setAttribute("x", x);
			bar.setAttribute("y", y);
			bar.setAttribute("width", w);
			bar.setAttribute("height", h);
			bar.setAttribute("fill-opacity", "0.6");
			g.appendChild(bar);

			//	open
			var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
			line.setAttribute("x1", x-(part*2));
			line.setAttribute("x2", x+w);
			line.setAttribute("y1", open);
			line.setAttribute("y2", open);
			line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;");
			g.appendChild(line);

			//	close
			var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
			line.setAttribute("x1", x);
			line.setAttribute("x2", x+w+(part*2));
			line.setAttribute("y1", close);
			line.setAttribute("y2", close);
			line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;");
			g.appendChild(line);

			if(applyTo){ applyTo(g, data[i].src); }
			group.appendChild(g);
		}
		return group;	//	SVGGElement
	},
	Scatter: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of points.
		//	Bindings: x/y
		var r=7;
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		for (var i=0; i<data.length; i++){
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
			var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
			var point = document.createElementNS(dojo.svg.xmlns.svg, "path");
			point.setAttribute("fill", data[i].series.color);
			point.setAttribute("stroke-width", "0");
			point.setAttribute("d",
				"M " + x + "," + (y-r) + " " +
				"Q " + x + "," + y + " " + (x+r) + "," + y + " " +
				"Q " + x + "," + y + " " + x + "," + (y+r) + " " +
				"Q " + x + "," + y + " " + (x-r) + "," + y + " " +
				"Q " + x + "," + y + " " + x + "," + (y-r) + " " +
				"Z"
			);
			if(applyTo){ applyTo(point, data[i].src); }
			group.appendChild(point);
		}
		return group;	//	SVGGElement
	},
	Bubble: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of points with a size factor.
		//	Bindings: x/y/size
		var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
		var sizeFactor=1;
		for (var i=0; i<data.length; i++){
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
			var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
			if(i==0){
				//	figure out the size factor, start with the axis with the greater range.
				var raw = data[i].size;
				var dy = plot.axisY.getCoord(data[i].y + raw, plotarea, plot)-y;
				sizeFactor = dy/raw;
			}
			if(sizeFactor<1) { sizeFactor = 1; }
			var point = document.createElementNS(dojo.svg.xmlns.svg, "circle");
			point.setAttribute("fill", data[i].series.color);
			point.setAttribute("fill-opacity", "0.8");
			point.setAttribute("stroke", data[i].series.color);
			point.setAttribute("stroke-width", "1");
			point.setAttribute("cx",x);
			point.setAttribute("cy",y);
			point.setAttribute("r", (data[i].size/2)*sizeFactor);
			if(applyTo){ applyTo(point, data[i].src); }
			group.appendChild(point);
		}
		return group;	//	SVGGElement
	}
});
dojo.charting.Plotters["Default"] = dojo.charting.Plotters.Line;

__CPAN_FILE__ src/charting/svg/Axis.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.svg.Axis");
dojo.require("dojo.lang.common");

dojo.extend(dojo.charting.Axis, {
	renderLines: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot, 
		/* string */plane
	){
		//	summary
		//	Renders any reference lines for this axis.
		if(this.nodes.lines){
			while(this.nodes.lines.childNodes.length > 0){
				this.nodes.lines.removeChild(this.nodes.lines.childNodes[0]);
			}
			if(this.nodes.lines.parentNode){
				this.nodes.lines.parentNode.removeChild(this.nodes.lines);
				this.nodes.lines = null;
			}
		}
		
		var area = plotArea.getArea();
		var g = this.nodes.lines = document.createElementNS(dojo.svg.xmlns.svg, "g");
		g.setAttribute("id", this.getId()+"-lines");
		for(var i=0; i<this._labels.length; i++){
			if (this._labels[i].value == this.origin){ continue; }

			var v = this.getCoord(this._labels[i].value, plotArea, plot);
			var l=document.createElementNS(dojo.svg.xmlns.svg, "line");
			l.setAttribute("style","stroke:#999;stroke-width:1px;stroke-dasharray:1,4;");
			if(plane == "x"){
				l.setAttribute("y1",area.top);
				l.setAttribute("y2",area.bottom);
				l.setAttribute("x1",v);
				l.setAttribute("x2",v);
			}
			else if (plane == "y"){
				l.setAttribute("y1",v);
				l.setAttribute("y2",v);
				l.setAttribute("x1",area.left);
				l.setAttribute("x2",area.right);
			}
			g.appendChild(l);
		}
		return g;	//	SVGGElement
	},
	renderTicks: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot, 
		/* string */plane,
		/* float */coord
	){
		//	summary
		//	Renders any tick lines for this axis.
		if(this.nodes.ticks){
			while(this.nodes.ticks.childNodes.length > 0){
				this.nodes.ticks.removeChild(this.nodes.ticks.childNodes[0]);
			}
			if(this.nodes.ticks.parentNode){
				this.nodes.ticks.parentNode.removeChild(this.nodes.ticks);
				this.nodes.ticks = null;
			}
		}
		
		var g = this.nodes.ticks = document.createElementNS(dojo.svg.xmlns.svg, "g");
		g.setAttribute("id", this.getId()+"-ticks");
		for(var i=0; i<this._labels.length; i++){
			var v = this.getCoord(this._labels[i].value, plotArea, plot);

			var l=document.createElementNS(dojo.svg.xmlns.svg, "line");
			l.setAttribute("style","stroke:#000;stroke-width:1pt;");
			if(plane == "x"){
				l.setAttribute("y1",coord);
				l.setAttribute("y2",coord+3);
				l.setAttribute("x1",v);
				l.setAttribute("x2",v);
			}
			else if (plane == "y"){
				l.setAttribute("y1",v);
				l.setAttribute("y2",v);
				l.setAttribute("x1",coord-2);
				l.setAttribute("x2",coord+2);
			}
			g.appendChild(l);
		}
		return g;	//	SVGGElement
	},
	renderLabels: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot, 
		/* string */plane,
		/* float */coord,
		/* int */textSize,
		/* string */anchor
	){
		//	summary
		//	Render all labels for this axis.
		function createLabel(label, x, y, textSize, anchor){
			var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
			text.setAttribute("x", x);
			text.setAttribute("y", (plane=="x"?y:y+2));
			text.setAttribute("style", "text-anchor:"+anchor+";font-family:sans-serif;font-size:"+textSize+"px;fill:#000;");
			text.appendChild(document.createTextNode(label));
			return text;
		};

		//	wipe if needed
		if(this.nodes.labels){
			while(this.nodes.labels.childNodes.length > 0){
				this.nodes.labels.removeChild(this.nodes.labels.childNodes[0]);
			}
			if(this.nodes.labels.parentNode){
				this.nodes.labels.parentNode.removeChild(this.nodes.labels);
				this.nodes.labels = null;
			}
		}
		var g = this.nodes.labels = document.createElementNS(dojo.svg.xmlns.svg, "g");
		g.setAttribute("id", this.getId()+"-labels");

		for(var i=0; i<this._labels.length; i++){
			var v = this.getCoord(this._labels[i].value, plotArea, plot);
			if(plane == "x"){
				g.appendChild(createLabel(this._labels[i].label, v, coord, textSize, anchor));
			}
			else if (plane == "y"){
				g.appendChild(createLabel(this._labels[i].label, coord, v, textSize, anchor));
			}
		}
		return g;	//	SVGGelement
	},
	render: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot,
		/* dojo.charting.Axis */drawAgainst,
		/* string */plane
	){
		//	summary
		//	Renders this axis to the given plot.
		
		//	get the origin plot point.
		var area = plotArea.getArea();
		var stroke = 1;
		var style = "stroke:#000;stroke-width:"+stroke+"px;";
		var textSize=10;
		var coord = drawAgainst.getCoord(this.origin, plotArea, plot);

		//	draw the axis.
		this.nodes.main = document.createElementNS(dojo.svg.xmlns.svg, "g");
		var g = this.nodes.main;
		g.setAttribute("id", this.getId());	//	need a handle if we have to kill parts of the axis def.
		var line = this.nodes.axis = document.createElementNS(dojo.svg.xmlns.svg, "line");
		if(plane == "x"){
			line.setAttribute("y1", coord);
			line.setAttribute("y2", coord);
			line.setAttribute("x1", area.left-stroke);
			line.setAttribute("x2", area.right+stroke);
			line.setAttribute("style", style);

			//	set up the labels
			var y = coord+textSize+2;
			if(this.showLines){
				g.appendChild(this.renderLines(plotArea, plot, plane, y));
			}
			if(this.showTicks){
				g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
			}
			if(this.showLabels){
				g.appendChild(this.renderLabels(plotArea, plot, plane, y, textSize, "middle"));
			}
			if(this.showLabel && this.label){
				var x = plotArea.size.width/2;
				var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
				text.setAttribute("x", x);
				text.setAttribute("y", (coord + (textSize*2) + (textSize/2)));
				text.setAttribute("style", "text-anchor:middle;font-family:sans-serif;font-weight:bold;font-size:"+(textSize+2)+"px;fill:#000;");
				text.appendChild(document.createTextNode(this.label));
				g.appendChild(text);
			}
		} else {
			line.setAttribute("x1", coord);
			line.setAttribute("x2", coord);
			line.setAttribute("y1", area.top);
			line.setAttribute("y2", area.bottom);
			line.setAttribute("style", style);

			//	set up the labels
			var isMax = this.origin == drawAgainst.range.upper;
			var x = coord + (isMax?4:-4);
			var anchor = isMax?"start":"end";
			if(this.showLines){
				g.appendChild(this.renderLines(plotArea, plot, plane, x));
			}
			if(this.showTicks){
				g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
			}
			if(this.showLabels){
				g.appendChild(this.renderLabels(plotArea, plot, plane, x, textSize, anchor));
			}
			if(this.showLabel && this.label){
				var x = isMax?(coord+(textSize*2)+(textSize/2)):(coord-(textSize*4));
				var y = plotArea.size.height / 2;
				var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
				text.setAttribute("x", x);
				text.setAttribute("y", y);
				text.setAttribute("transform", "rotate(90, " + x + ", " + y + ")");
				text.setAttribute("style", "text-anchor:middle;font-family:sans-serif;font-weight:bold;font-size:"+(textSize+2)+"px;fill:#000;");
				text.appendChild(document.createTextNode(this.label));
				g.appendChild(text);
			}
		}
		g.appendChild(line);
		return g;	// 	SVGGElement
	}
});

__CPAN_DIR__ src/charting/vml
__CPAN_FILE__ src/charting/vml/PlotArea.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.vml.PlotArea");
dojo.require("dojo.lang.common");

dojo.extend(dojo.charting.PlotArea, {
	initializePlot: function(plot){
		//	summary
		//	Initialize the plot node for data rendering.
		plot.destroy();
		plot.dataNode = document.createElement("div");
		plot.dataNode.id  = plot.getId();
		return plot.dataNode;	//	HTMLDivElement
	},
	initialize:function(){
		//	summary
		//	Initialize the PlotArea.
	
		this.destroy();	//	kill everything first.
		var main = this.nodes.main = document.createElement("div");
		
		//	start with the background
		var area = this.nodes.area = document.createElement("div");
		area.id = this.getId();
		area.style.width=this.size.width+"px";
		area.style.height=this.size.height+"px";
		area.style.position="absolute";
		main.appendChild(area);
	
		var bg = this.nodes.background = document.createElement("div");
		bg.id = this.getId()+"-background";
		bg.style.width=this.size.width+"px";
		bg.style.height=this.size.height+"px";
		bg.style.position="absolute";
		bg.style.top="0px";
		bg.style.left="0px";
		bg.style.backgroundColor="#fff";
		area.appendChild(bg);

		//	the plot group
		var a=this.getArea();
		var plots = this.nodes.plots = document.createElement("div");
		plots.id = this.getId()+"-plots";
		plots.style.width=this.size.width+"px";
		plots.style.height=this.size.height+"px";
		plots.style.position="absolute";
		plots.style.top="0px";
		plots.style.left="0px";
		plots.style.clip="rect("
			+ a.top+" "
			+ a.right+" "
			+ a.bottom+" "
			+ a.left
			+")";
		area.appendChild(plots);
		for(var i=0; i<this.plots.length; i++){
			plots.appendChild(this.initializePlot(this.plots[i]));
		}

		var axes = this.nodes.axes = document.createElement("div");
		axes.id = this.getId() + "-axes";
		area.appendChild(axes);
		var ax = this.getAxes();
		for(var p in ax){
			var obj = ax[p];
			axes.appendChild(obj.axis.initialize(this, obj.plot, obj.drawAgainst, obj.plane));
		}
		return main;	//	HTMLDivElement
	}
});

__CPAN_FILE__ src/charting/vml/Plotters.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.vml.Plotters");
dojo.require("dojo.lang.common");

dojo.mixin(dojo.charting.Plotters, {
	/*********************************************************
	 *	Grouped plotters: need all series on a plot at once.
	 *********************************************************/
	Bar: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of grouped bars.
		//	Bindings: y
		var area = plotarea.getArea();
		var group = document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			data.push(tmp);
		}

		//	calculate the width of each bar.
		var space = 8;
		var nPoints = data[0].length;
		var width = ((area.right-area.left)-(space*(nPoints-1)))/nPoints;	//	the width of each group.
		var barWidth = Math.round(width/n);	//	the width of each bar, no spaces.
		var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot);

		for(var i=0; i<nPoints; i++){
			//	calculate offset
			var xStart = area.left+(width*i)+(space*i);
			for(var j=0; j<n; j++){
				var value = data[j][i].y;
				var yA = yOrigin;
				var x = xStart + (barWidth*j);
				var y = plot.axisY.getCoord(value, plotarea, plot);
				var h = Math.abs(yA-y);
				if(value < plot.axisX.origin){
					yA = y;
					y = yOrigin;
				}
				
				var bar=document.createElement("v:rect");
				bar.style.position="absolute";
				bar.style.top=y+1+"px";
				bar.style.left=x+"px";
				bar.style.width=barWidth+"px";
				bar.style.height=h+"px";
				bar.setAttribute("fillColor", data[j][i].series.color);
				bar.setAttribute("stroked", "false");
				bar.style.antialias="false";
				var fill=document.createElement("v:fill");
				fill.setAttribute("opacity", "0.6");
				bar.appendChild(fill);
				if(applyTo){ applyTo(bar, data[j][i].src); }
				group.appendChild(bar);
			}
		}
		return group;	//	HTMLDivElement
	},
	HorizontalBar: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots data in a set of grouped bars horizontally.
		//	Bindings: y
		var area = plotarea.getArea();
		var group = document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			data.push(tmp);
		}

		var space = 6;
		var nPoints = data[0].length;
		var h = ((area.bottom-area.top)-(space*(nPoints-1)))/nPoints;
		var barH = h/n;
		var xOrigin = plot.axisX.getCoord(0, plotarea, plot);

		for(var i=0; i<nPoints; i++){
			//	calculate offset
			var yStart = area.top+(h*i)+(space*i);
			for(var j=0; j<n; j++){
				var value = data[j][i].y;
				var y = yStart + (barH*j);
				var xA = xOrigin;
				var x = plot.axisX.getCoord(value, plotarea, plot);
				var w = Math.abs(x-xA);
				if(value > 0){
					x = xOrigin;
				}
				
				var bar=document.createElement("v:rect");
				bar.style.position="absolute";
				bar.style.top=y+1+"px";
				bar.style.left=xA+"px";
				bar.style.width=w+"px";
				bar.style.height=barH+"px";
				bar.setAttribute("fillColor", data[j][i].series.color);
				bar.setAttribute("stroked", "false");
				bar.style.antialias="false";
				var fill=document.createElement("v:fill");
				fill.setAttribute("opacity", "0.6");
				bar.appendChild(fill);
				if(applyTo){ applyTo(bar, data[j][i].src); }
				group.appendChild(bar);
			}
		}

		//	calculate the width of each bar.
		var space = 4;
		var n = plot.series.length;
		var h = ((area.bottom-area.top)-(space*(n-1)))/n;
		var xOrigin = plot.axisX.getCoord(0, plotarea, plot);
		for(var i=0; i<n; i++){
			var series = plot.series[i];
			var data = series.data.evaluate(kwArgs);
			var y = area.top+(h*i)+(space*i);
			var value = data[data.length-1].y;

			var xA = xOrigin;
			var x = plot.axisX.getCoord(value, plotarea, plot);
			var w = Math.abs(xA-x);
			if(value > 0){
				xA = x;
				x = xOrigin;
			}
			
		}
		return group;	//	HTMLDivElement
	},
	Gantt: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a grouped set of Gantt bars
		//	Bindings: high/low
		var area = plotarea.getArea();
		var group = document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			data.push(tmp);
		}

		var space = 2;
		var nPoints = data[0].length;
		var h = ((area.bottom-area.top)-(space*(nPoints-1)))/nPoints;
		var barH = h/n;
		for(var i=0; i<nPoints; i++){
			//	calculate offset
			var yStart = area.top+(h*i)+(space*i);
			for(var j=0; j<n; j++){
				var high = data[j][i].high;
				var low = data[j][i].low;
				if(low > high){
					var t = high;
					high = low;
					low = t;
				}
				var x = plot.axisX.getCoord(low, plotarea, plot);
				var w = plot.axisX.getCoord(high, plotarea, plot) - x;
				var y = yStart + (barH*j);
				
				var bar=document.createElement("v:rect");
				bar.style.position="absolute";
				bar.style.top=y+1+"px";
				bar.style.left=x+"px";
				bar.style.width=w+"px";
				bar.style.height=barH+"px";
				bar.setAttribute("fillColor", data[j][i].series.color);
				bar.setAttribute("stroked", "false");
				bar.style.antialias="false";
				var fill=document.createElement("v:fill");
				fill.setAttribute("opacity", "0.6");
				bar.appendChild(fill);
				if(applyTo){ applyTo(bar, data[j][i].src); }
				group.appendChild(bar);
			}
		}
		return group;	//	HTMLDivElement
	},
	StackedArea: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of stacked areas.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		var totals = [];

		//	we're assuming that all series for this plot has the name x assignment for now.
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			//	run through and add current totals
			for(var j=0; j<tmp.length; j++){
				if(i==0){ totals.push(tmp[j].y); }
				else { totals[j] += tmp[j].y; }
				tmp[j].y = totals[j];
			}
			data.push(tmp);
		}

		for(var i=n-1; i>=0; i--){
			var path=document.createElement("v:shape");
			path.setAttribute("strokeweight", "1px");
			path.setAttribute("strokecolor", data[i][0].series.color);
			path.setAttribute("fillcolor", data[i][0].series.color);
			path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top));
			path.style.position="absolute";
			path.style.top="0px";
			path.style.left="0px";
			path.style.width=area.right-area.left+"px";
			path.style.height=area.bottom-area.top+"px";
			var stroke=document.createElement("v:stroke");
			stroke.setAttribute("opacity", "0.8");
			path.appendChild(stroke);
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.4");
			path.appendChild(fill);

			var cmd = [];
			var r=3;
			for(var j=0; j<data[i].length; j++){
				var values = data[i];
				var x = Math.round(plot.axisX.getCoord(values[j].x, plotarea, plot));
				var y = Math.round(plot.axisY.getCoord(values[j].y, plotarea, plot));

				if (j==0){
					cmd.push("m");
					cmd.push(x+","+y);
				}else{
					cmd.push("l");
					cmd.push(x+","+y);
				}

				//	add the circle.
				var c = document.createElement("v:oval");
				c.setAttribute("strokeweight", "1px");
				c.setAttribute("strokecolor", values[j].series.color);
				c.setAttribute("fillcolor", values[j].series.color);
				var str=document.createElement("v:stroke");
				str.setAttribute("opacity","0.8");
				c.appendChild(str);
				str=document.createElement("v:fill");
				str.setAttribute("opacity","0.6");
				c.appendChild(str);
				var s=c.style;
				s.position="absolute";
				s.top=(y-r)+"px";
				s.left=(x-r)+"px";
				s.width=(r*2)+"px";
				s.height=(r*2)+"px";
				group.appendChild(c);
				if(applyTo){ applyTo(c, data[j].src); }
			}

			//	now run the path backwards from the previous series.
			if(i == 0){
				cmd.push("l");
				cmd.push(x + "," + Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
				cmd.push("l");
				cmd.push(Math.round(plot.axisX.getCoord(data[0][0].x, plotarea, plot)) + "," +  Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
			} else {
				var values = data[i-1];
				cmd.push("l");
				cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot)));
				for(var j=values.length-2; j>=0; j--){
					var x = Math.round(plot.axisX.getCoord(values[j].x, plotarea, plot));
					var y = Math.round(plot.axisY.getCoord(values[j].y, plotarea, plot));
					
					cmd.push("l");
					cmd.push(x+","+y);
				}
			}
			path.setAttribute("path", cmd.join(" ")+" x e");
			group.appendChild(path);
		}
		return group;	//	HTMLDivElement
	},
	StackedCurvedArea: function(
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* object? */kwArgs,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of stacked areas, using a tensioning factor to soften points.
		//	Bindings: x/y
		var tension = 3;
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		//	precompile the data
		var n = plot.series.length;	//	how many series
		var data = [];
		var totals = [];

		//	we're assuming that all series for this plot has the name x assignment for now.
		for(var i=0; i<n; i++){
			var tmp = plot.series[i].data.evaluate(kwArgs);
			//	run through and add current totals
			for(var j=0; j<tmp.length; j++){
				if(i==0){ totals.push(tmp[j].y); }
				else { totals[j] += tmp[j].y; }
				tmp[j].y = totals[j];
			}
			data.push(tmp);
		}

		for(var i=n-1; i>=0; i--){
			var path=document.createElement("v:shape");
			path.setAttribute("strokeweight", "1px");
			path.setAttribute("strokecolor", data[i][0].series.color);
			path.setAttribute("fillcolor", data[i][0].series.color);
			path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top));
			path.style.position="absolute";
			path.style.top="0px";
			path.style.left="0px";
			path.style.width=area.right-area.left+"px";
			path.style.height=area.bottom-area.top+"px";
			var stroke=document.createElement("v:stroke");
			stroke.setAttribute("opacity", "0.8");
			path.appendChild(stroke);
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.4");
			path.appendChild(fill);

			var cmd = [];
			var r=3;
			for(var j=0; j<data[i].length; j++){
				var values = data[i];
				var x = Math.round(plot.axisX.getCoord(values[j].x, plotarea, plot));
				var y = Math.round(plot.axisY.getCoord(values[j].y, plotarea, plot));

				if (j==0){
					cmd.push("m");
					cmd.push(x+","+y);
				}else{
					var lastx = Math.round(plot.axisX.getCoord(values[j-1].x, plotarea, plot));
					var lasty = Math.round(plot.axisY.getCoord(values[j-1].y, plotarea, plot));
					var dx=x-lastx;
					var dy=y-lasty;
					
					cmd.push("c");
					var cx=Math.round((x-(tension-1)*(dx/tension)));
					cmd.push(cx+","+lasty);
					cx=Math.round((x-(dx/tension)));
					cmd.push(cx+","+y);
					cmd.push(x+","+y);
				}

				//	add the circle.
				var c = document.createElement("v:oval");
				c.setAttribute("strokeweight", "1px");
				c.setAttribute("strokecolor", values[j].series.color);
				c.setAttribute("fillcolor", values[j].series.color);
				var str=document.createElement("v:stroke");
				str.setAttribute("opacity","0.8");
				c.appendChild(str);
				str=document.createElement("v:fill");
				str.setAttribute("opacity","0.6");
				c.appendChild(str);
				var s=c.style;
				s.position="absolute";
				s.top=(y-r)+"px";
				s.left=(x-r)+"px";
				s.width=(r*2)+"px";
				s.height=(r*2)+"px";
				group.appendChild(c);
				if(applyTo){ applyTo(c, data[j].src); }
			}

			//	now run the path backwards from the previous series.
			if(i == 0){
				cmd.push("l");
				cmd.push(x + "," + Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
				cmd.push("l");
				cmd.push(Math.round(plot.axisX.getCoord(data[0][0].x, plotarea, plot)) + "," +  Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
			} else {
				var values = data[i-1];
				cmd.push("l");
				cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot)));
				for(var j=values.length-2; j>=0; j--){
					var x = Math.round(plot.axisX.getCoord(values[j].x, plotarea, plot));
					var y = Math.round(plot.axisY.getCoord(values[j].y, plotarea, plot));

					var lastx = Math.round(plot.axisX.getCoord(values[j+1].x, plotarea, plot));
					var lasty = Math.round(plot.axisY.getCoord(values[j+1].y, plotarea, plot));
					var dx=x-lastx;
					var dy=y-lasty;
					
					cmd.push("c");
					var cx=Math.round((x-(tension-1)*(dx/tension)));
					cmd.push(cx+","+lasty);
					cx=Math.round((x-(dx/tension)));
					cmd.push(cx+","+y);
					cmd.push(x+","+y);
				}
			}
			path.setAttribute("path", cmd.join(" ")+" x e");
			group.appendChild(path);
		}
		return group;	//	HTMLDivElement
	},

	/*********************************************************
	 *	Single plotters: one series at a time.
	 *********************************************************/
	DataBar: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots a set of bars in relation to y==0.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var group = document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		var n = data.length;
		var w = (area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower);	//	the width of each group.
		var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot);

		for(var i=0; i<n; i++){
			//	calculate offset
			var value = data[i].y;
			var yA = yOrigin;
			var x = plot.axisX.getCoord(data[i].x, plotarea, plot)-(w/2)+1;
			var y = plot.axisY.getCoord(value, plotarea, plot);
			var h = Math.abs(yA-y);
			if(value < plot.axisX.origin){
				yA = y;
				y = yOrigin;
			}
			var bar=document.createElement("v:rect");
			bar.style.position="absolute";
			bar.style.top=y+1+"px";
			bar.style.left=x+"px";
			bar.style.width=w+"px";
			bar.style.height=h+"px";
			bar.setAttribute("fillColor", data[i].series.color);
			bar.setAttribute("stroked", "false");
			bar.style.antialias="false";
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.6");
			bar.appendChild(fill);
			if(applyTo){ applyTo(bar, data[i].src); }
			group.appendChild(bar);
		}
		return group;	//	HTMLDivElement
	},
	Line: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a line.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		var path=document.createElement("v:shape");
		path.setAttribute("strokeweight", "2px");
		path.setAttribute("strokecolor", data[0].series.color);
		path.setAttribute("fillcolor", "none");
		path.setAttribute("filled", "false");
		path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top));
		path.style.position="absolute";
		path.style.top="0px";
		path.style.left="0px";
		path.style.width=area.right-area.left+"px";
		path.style.height=area.bottom-area.top+"px";
		var stroke=document.createElement("v:stroke");
		stroke.setAttribute("opacity", "0.8");
		path.appendChild(stroke);

		var cmd = [];
		var r=3;
		for(var i=0; i<data.length; i++){
			var x = Math.round(plot.axisX.getCoord(data[i].x, plotarea, plot));
			var y = Math.round(plot.axisY.getCoord(data[i].y, plotarea, plot));

			if (i==0){
				cmd.push("m");
				cmd.push(x+","+y);
			}else{
				cmd.push("l");
				cmd.push(x+","+y);
			}

			//	add the circle.
			var c = document.createElement("v:oval");
			c.setAttribute("strokeweight", "1px");
			c.setAttribute("strokecolor", data[i].series.color);
			c.setAttribute("fillcolor", data[i].series.color);
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.8");
			c.appendChild(str);
			str=document.createElement("v:fill");
			str.setAttribute("opacity","0.6");
			c.appendChild(str);
			var s=c.style;
			s.position="absolute";
			s.top=(y-r)+"px";
			s.left=(x-r)+"px";
			s.width=(r*2)+"px";
			s.height=(r*2)+"px";
			group.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		path.setAttribute("path", cmd.join(" ")+" e");
		group.appendChild(path);
		return group;	//	HTMLDivElement
	},
	CurvedLine: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a line with a tension factor for softening.
		//	Bindings: x/y
		var tension = 3;
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		var path=document.createElement("v:shape");
		path.setAttribute("strokeweight", "2px");
		path.setAttribute("strokecolor", data[0].series.color);
		path.setAttribute("fillcolor", "none");
		path.setAttribute("filled", "false");
		path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top));
		path.style.position="absolute";
		path.style.top="0px";
		path.style.left="0px";
		path.style.width=area.right-area.left+"px";
		path.style.height=area.bottom-area.top+"px";
		var stroke=document.createElement("v:stroke");
		stroke.setAttribute("opacity", "0.8");
		path.appendChild(stroke);

		var cmd = [];
		var r=3;
		for(var i=0; i<data.length; i++){
			var x = Math.round(plot.axisX.getCoord(data[i].x, plotarea, plot));
			var y = Math.round(plot.axisY.getCoord(data[i].y, plotarea, plot));

			if (i==0){
				cmd.push("m");
				cmd.push(x+","+y);
			}else{
				var lastx = Math.round(plot.axisX.getCoord(data[i-1].x, plotarea, plot));
				var lasty = Math.round(plot.axisY.getCoord(data[i-1].y, plotarea, plot));
				var dx=x-lastx;
				var dy=y-lasty;
				
				cmd.push("c");
				var cx=Math.round((x-(tension-1)*(dx/tension)));
				cmd.push(cx+","+lasty);
				cx=Math.round((x-(dx/tension)));
				cmd.push(cx+","+y);
				cmd.push(x+","+y);
			}

			//	add the circle.
			var c = document.createElement("v:oval");
			c.setAttribute("strokeweight", "1px");
			c.setAttribute("strokecolor", data[i].series.color);
			c.setAttribute("fillcolor", data[i].series.color);
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.8");
			c.appendChild(str);
			str=document.createElement("v:fill");
			str.setAttribute("opacity","0.6");
			c.appendChild(str);
			var s=c.style;
			s.position="absolute";
			s.top=(y-r)+"px";
			s.left=(x-r)+"px";
			s.width=(r*2)+"px";
			s.height=(r*2)+"px";
			group.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		path.setAttribute("path", cmd.join(" ")+" e");
		group.appendChild(path);
		return group;	//	HTMLDivElement
	},
	Area: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as an area.
		//	Bindings: x/y
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		var path=document.createElement("v:shape");
		path.setAttribute("strokeweight", "1px");
		path.setAttribute("strokecolor", data[0].series.color);
		path.setAttribute("fillcolor", data[0].series.color);
		path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top));
		path.style.position="absolute";
		path.style.top="0px";
		path.style.left="0px";
		path.style.width=area.right-area.left+"px";
		path.style.height=area.bottom-area.top+"px";
		var stroke=document.createElement("v:stroke");
		stroke.setAttribute("opacity", "0.8");
		path.appendChild(stroke);
		var fill=document.createElement("v:fill");
		fill.setAttribute("opacity", "0.4");
		path.appendChild(fill);

		var cmd = [];
		var r=3;
		for(var i=0; i<data.length; i++){
			var x = Math.round(plot.axisX.getCoord(data[i].x, plotarea, plot));
			var y = Math.round(plot.axisY.getCoord(data[i].y, plotarea, plot));

			if (i==0){
				cmd.push("m");
				cmd.push(x+","+y);
			}else{
				cmd.push("l");
				cmd.push(x+","+y);
			}

			//	add the circle.
			var c = document.createElement("v:oval");
			c.setAttribute("strokeweight", "1px");
			c.setAttribute("strokecolor", data[i].series.color);
			c.setAttribute("fillcolor", data[i].series.color);
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.8");
			c.appendChild(str);
			str=document.createElement("v:fill");
			str.setAttribute("opacity","0.6");
			c.appendChild(str);
			var s=c.style;
			s.position="absolute";
			s.top=(y-r)+"px";
			s.left=(x-r)+"px";
			s.width=(r*2)+"px";
			s.height=(r*2)+"px";
			group.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		cmd.push("l");
		cmd.push(x + "," + Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
		cmd.push("l");
		cmd.push(Math.round(plot.axisX.getCoord(data[0].x, plotarea, plot)) + "," +  Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
		path.setAttribute("path", cmd.join(" ")+" x e");
		group.appendChild(path);
		return group;	//	HTMLDivElement
	},
	CurvedArea: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as an area with a tension for softening.
		//	Bindings: x/y
		var tension = 3;
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		var path=document.createElement("v:shape");
		path.setAttribute("strokeweight", "1px");
		path.setAttribute("strokecolor", data[0].series.color);
		path.setAttribute("fillcolor", data[0].series.color);
		path.setAttribute("coordsize", (area.right-area.left) + "," + (area.bottom-area.top));
		path.style.position="absolute";
		path.style.top="0px";
		path.style.left="0px";
		path.style.width=area.right-area.left+"px";
		path.style.height=area.bottom-area.top+"px";
		var stroke=document.createElement("v:stroke");
		stroke.setAttribute("opacity", "0.8");
		path.appendChild(stroke);
		var fill=document.createElement("v:fill");
		fill.setAttribute("opacity", "0.4");
		path.appendChild(fill);

		var cmd = [];
		var r=3;
		for(var i=0; i<data.length; i++){
			var x = Math.round(plot.axisX.getCoord(data[i].x, plotarea, plot));
			var y = Math.round(plot.axisY.getCoord(data[i].y, plotarea, plot));

			if (i==0){
				cmd.push("m");
				cmd.push(x+","+y);
			}else{
				var lastx = Math.round(plot.axisX.getCoord(data[i-1].x, plotarea, plot));
				var lasty = Math.round(plot.axisY.getCoord(data[i-1].y, plotarea, plot));
				var dx=x-lastx;
				var dy=y-lasty;
				
				cmd.push("c");
				var cx=Math.round((x-(tension-1)*(dx/tension)));
				cmd.push(cx+","+lasty);
				cx=Math.round((x-(dx/tension)));
				cmd.push(cx+","+y);
				cmd.push(x+","+y);
			}

			//	add the circle.
			var c = document.createElement("v:oval");
			c.setAttribute("strokeweight", "1px");
			c.setAttribute("strokecolor", data[i].series.color);
			c.setAttribute("fillcolor", data[i].series.color);
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.8");
			c.appendChild(str);
			str=document.createElement("v:fill");
			str.setAttribute("opacity","0.6");
			c.appendChild(str);
			var s=c.style;
			s.position="absolute";
			s.top=(y-r)+"px";
			s.left=(x-r)+"px";
			s.width=(r*2)+"px";
			s.height=(r*2)+"px";
			group.appendChild(c);
			if(applyTo){ applyTo(c, data[i].src); }
		}
		cmd.push("l");
		cmd.push(x + "," + Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
		cmd.push("l");
		cmd.push(Math.round(plot.axisX.getCoord(data[0].x, plotarea, plot)) + "," +  Math.round(plot.axisY.getCoord(plot.axisX.origin, plotarea, plot)));
		path.setAttribute("path", cmd.join(" ")+" x e");
		group.appendChild(path);
		return group;	//	HTMLDivElement
	},
	HighLow: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of high/low bars.
		//	Bindings: x/high/low
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		var n = data.length;
		var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
		var w = part*2;

		for(var i=0; i<n; i++){
			var high = data[i].high;
			var low = data[i].low;
			if(low > high){
				var t = low;
				low = high;
				high = t;
			}

			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(high, plotarea, plot);
			var h = plot.axisY.getCoord(low, plotarea, plot)-y;

			//	high + low
			var bar=document.createElement("v:rect");
			bar.style.position="absolute";
			bar.style.top=y+1+"px";
			bar.style.left=x+"px";
			bar.style.width=w+"px";
			bar.style.height=h+"px";
			bar.setAttribute("fillColor", data[i].series.color);
			bar.setAttribute("stroked", "false");
			bar.style.antialias="false";
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.6");
			bar.appendChild(fill);
			if(applyTo){ applyTo(bar, data[i].src); }
			group.appendChild(bar);
		}
		return group;	//	HTMLDivElement
	},	
	HighLowClose: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of high/low bars with a close indicator.
		//	Bindings: x/high/low/close
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		var n = data.length;
		var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
		var w = part*2;

		for(var i=0; i<n; i++){
			var high = data[i].high;
			var low = data[i].low;
			if(low > high){
				var t = low;
				low = high;
				high = t;
			}
			var c = data[i].close;

			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(high, plotarea, plot);
			var h = plot.axisY.getCoord(low, plotarea, plot)-y;
			var close = plot.axisY.getCoord(c, plotarea, plot);

			var g = document.createElement("div");

			//	high + low
			var bar=document.createElement("v:rect");
			bar.style.position="absolute";
			bar.style.top=y+1+"px";
			bar.style.left=x+"px";
			bar.style.width=w+"px";
			bar.style.height=h+"px";
			bar.setAttribute("fillColor", data[i].series.color);
			bar.setAttribute("stroked", "false");
			bar.style.antialias="false";
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.6");
			bar.appendChild(fill);
			g.appendChild(bar);

			var line = document.createElement("v:line");
			line.setAttribute("strokecolor", data[i].series.color);
			line.setAttribute("strokeweight", "1px");
			line.setAttribute("from", x+"px,"+close+"px");
			line.setAttribute("to", (x+w+(part*2)-2)+"px,"+close+"px");
			var s=line.style;
			s.position="absolute";
			s.top="0px";
			s.left="0px";
			s.antialias="false";
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.6");
			line.appendChild(str);
			g.appendChild(line);

			if(applyTo){ applyTo(g, data[i].src); }
			group.appendChild(g);
		}
		return group;	//	HTMLDivElement
	},	
	HighLowOpenClose: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of high/low bars with open and close indicators.
		//	Bindings: x/high/low/open/close
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";
		
		var n = data.length;
		var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
		var w = part*2;

		for(var i=0; i<n; i++){
			var high = data[i].high;
			var low = data[i].low;
			if(low > high){
				var t = low;
				low = high;
				high = t;
			}
			var o = data[i].open;
			var c = data[i].close;

			var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
			var y = plot.axisY.getCoord(high, plotarea, plot);
			var h = plot.axisY.getCoord(low, plotarea, plot)-y;
			var open = plot.axisY.getCoord(o, plotarea, plot);
			var close = plot.axisY.getCoord(c, plotarea, plot);

			var g = document.createElement("div");

			//	high + low
			var bar=document.createElement("v:rect");
			bar.style.position="absolute";
			bar.style.top=y+1+"px";
			bar.style.left=x+"px";
			bar.style.width=w+"px";
			bar.style.height=h+"px";
			bar.setAttribute("fillColor", data[i].series.color);
			bar.setAttribute("stroked", "false");
			bar.style.antialias="false";
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity", "0.6");
			bar.appendChild(fill);
			g.appendChild(bar);

			var line = document.createElement("v:line");
			line.setAttribute("strokecolor", data[i].series.color);
			line.setAttribute("strokeweight", "1px");
			line.setAttribute("from", (x-(part*2))+"px,"+open+"px");
			line.setAttribute("to", (x+w-2)+"px,"+open+"px");
			var s=line.style;
			s.position="absolute";
			s.top="0px";
			s.left="0px";
			s.antialias="false";
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.6");
			line.appendChild(str);
			g.appendChild(line);
			
			var line = document.createElement("v:line");
			line.setAttribute("strokecolor", data[i].series.color);
			line.setAttribute("strokeweight", "1px");
			line.setAttribute("from", x+"px,"+close+"px");
			line.setAttribute("to", (x+w+(part*2)-2)+"px,"+close+"px");
			var s=line.style;
			s.position="absolute";
			s.top="0px";
			s.left="0px";
			s.antialias="false";
			var str=document.createElement("v:stroke");
			str.setAttribute("opacity","0.6");
			line.appendChild(str);
			g.appendChild(line);

			if(applyTo){ applyTo(g, data[i].src); }
			group.appendChild(g);
		}
		return group;	//	HTMLDivElement
	},	
	Scatter: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of points.
		//	Bindings: x/y
		var r=6;
		var mod=r/2;

		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		for(var i=0; i<data.length; i++){
			var x = Math.round(plot.axisX.getCoord(data[i].x, plotarea, plot));
			var y = Math.round(plot.axisY.getCoord(data[i].y, plotarea, plot));

			var point = document.createElement("v:rect");
			point.setAttribute("strokecolor", data[i].series.color);
			point.setAttribute("fillcolor", data[i].series.color);
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity","0.6");
			point.appendChild(fill);

			var s=point.style;
			s.position="absolute";
			s.rotation="45";
			s.top=(y-mod)+"px";
			s.left=(x-mod)+"px";
			s.width=r+"px";
			s.height=r+"px";
			group.appendChild(point);
			if(applyTo){ applyTo(point, data[i].src); }
		}
		return group;	//	HTMLDivElement
	},
	Bubble: function(
		/* array */data, 
		/* dojo.charting.PlotArea */plotarea,
		/* dojo.charting.Plot */plot,
		/* function? */applyTo
	){
		//	summary
		//	Plots the series as a set of points with a size factor.
		//	Bindings: x/y/size
		var sizeFactor=1;
		var area = plotarea.getArea();
		var group=document.createElement("div");
		group.style.position="absolute";
		group.style.top="0px";
		group.style.left="0px";
		group.style.width=plotarea.size.width+"px";
		group.style.height=plotarea.size.height+"px";

		for(var i=0; i<data.length; i++){
			var x = Math.round(plot.axisX.getCoord(data[i].x, plotarea, plot));
			var y = Math.round(plot.axisY.getCoord(data[i].y, plotarea, plot));
			if(i==0){
				//	figure out the size factor, start with the axis with the greater range.
				var raw = data[i].size;
				var dy = plot.axisY.getCoord(data[i].y + raw, plotarea, plot)-y;
				sizeFactor = dy/raw;
			}
			if(sizeFactor<1) { sizeFactor = 1; }
			var r = (data[i].size/2)*sizeFactor;

			var point = document.createElement("v:oval");
			point.setAttribute("strokecolor", data[i].series.color);
			point.setAttribute("fillcolor", data[i].series.color);
			var fill=document.createElement("v:fill");
			fill.setAttribute("opacity","0.6");
			point.appendChild(fill);

			var s=point.style;
			s.position="absolute";
			s.rotation="45";
			s.top=(y-r)+"px";
			s.left=(x-r)+"px";
			s.width=(r*2)+"px";
			s.height=(r*2)+"px";
			group.appendChild(point);
			if(applyTo){ applyTo(point, data[i].src); }
		}
		return group;	//	HTMLDivElement
	}
});
dojo.charting.Plotters["Default"] = dojo.charting.Plotters.Line;

__CPAN_FILE__ src/charting/vml/Axis.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.charting.vml.Axis");
dojo.require("dojo.lang.common");

dojo.extend(dojo.charting.Axis, {
	renderLines: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot, 
		/* string */plane
	){
		//	summary
		//	Renders any reference lines for this axis.
		if(this.nodes.lines){
			while(this.nodes.lines.childNodes.length > 0){
				this.nodes.lines.removeChild(this.nodes.lines.childNodes[0]);
			}
			if(this.nodes.lines.parentNode){
				this.nodes.lines.parentNode.removeChild(this.nodes.lines);
				this.nodes.lines = null;
			}
		}
		
		var area = plotArea.getArea();
		var g = this.nodes.lines = document.createElement("div");
		g.setAttribute("id", this.getId()+"-lines");
		for(var i=0; i<this._labels.length; i++){
			if (this._labels[i].value == this.origin){ continue; }

			var v = this.getCoord(this._labels[i].value, plotArea, plot);
			var l=document.createElement("v:line");
			var str=document.createElement("v:stroke");
			str.dashstyle="dot";
			l.appendChild(str);
			l.setAttribute("strokecolor", "#666");
			l.setAttribute("strokeweight", "1px");
			var s=l.style;
			s.position="absolute";
			s.top="0px";
			s.left="0px";
			s.antialias="false";
			if(plane == "x"){
				l.setAttribute("from", v+"px,"+area.top+"px");
				l.setAttribute("to", v+"px,"+area.bottom+"px");
			}
			else if (plane == "y"){
				l.setAttribute("from", area.left+"px,"+v+"px");
				l.setAttribute("to", area.right+"px,"+v+"px");
			}
			g.appendChild(l);
		}
		return g;	//	HTMLDivElement
	},
	renderTicks: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot, 
		/* string */plane,
		/* float */coord
	){
		//	summary
		//	Renders any tick lines for this axis.
		if(this.nodes.ticks){
			while(this.nodes.ticks.childNodes.length > 0){
				this.nodes.ticks.removeChild(this.nodes.ticks.childNodes[0]);
			}
			if(this.nodes.ticks.parentNode){
				this.nodes.ticks.parentNode.removeChild(this.nodes.ticks);
				this.nodes.ticks = null;
			}
		}
		
		var g = this.nodes.ticks = document.createElement("div");
		g.setAttribute("id", this.getId()+"-ticks");
		for(var i=0; i<this._labels.length; i++){
			var v = this.getCoord(this._labels[i].value, plotArea, plot);

			var l=document.createElement("v:line");
			l.setAttribute("strokecolor", "#000");
			l.setAttribute("strokeweight", "1px");
			var s=l.style;
			s.position="absolute";
			s.top="0px";
			s.left="0px";
			s.antialias="false";
			if(plane == "x"){
				l.setAttribute("from", v+"px,"+coord+"px");
				l.setAttribute("to", v+"px,"+(coord+3)+"px");
			}
			else if (plane == "y"){
				l.setAttribute("from", (coord-2)+"px,"+v+"px");
				l.setAttribute("to", (coord+2)+"px,"+v+"px");
			}
			g.appendChild(l);
		}
		return g;	//	HTMLDivElement
	},
	renderLabels: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot, 
		/* string */plane,
		/* float */coord,
		/* int */textSize,
		/* string */anchor
	){
		//	summary
		//	Render all labels for this axis.
		function createLabel(label, x, y, textSize, anchor){
			var text = document.createElement("div");
			var s=text.style;
			text.innerHTML=label;
			s.fontSize=textSize+"px";
			s.fontFamily="sans-serif";
			s.position="absolute";
			s.top = y+"px";
			if(anchor == "center"){
				s.left = x + "px";
				s.textAlign="center";
			} else if (anchor == "left"){
				s.left = x + "px";
				s.textAlign="left";
			} else if (anchor == "right"){
				s.right = x + "px";
				s.textAlign="right";
			}
			return text;
		};

		//	wipe if needed
		if(this.nodes.labels){
			while(this.nodes.labels.childNodes.length > 0){
				this.nodes.labels.removeChild(this.nodes.labels.childNodes[0]);
			}
			if(this.nodes.labels.parentNode){
				this.nodes.labels.parentNode.removeChild(this.nodes.labels);
				this.nodes.labels = null;
			}
		}
		var g = this.nodes.labels = document.createElement("div");
		g.setAttribute("id", this.getId()+"-labels");

		for(var i=0; i<this._labels.length; i++){
			var v = this.getCoord(this._labels[i].value, plotArea, plot);
			if(plane == "x"){
				//	ugly hack but it works.
				var node=createLabel(this._labels[i].label, v, coord, textSize, anchor);
				document.body.appendChild(node);
				node.style.left = v-(node.offsetWidth/2)+"px";
				g.appendChild(node);
			}
			else if (plane == "y"){
				var node = createLabel(this._labels[i].label, coord, v, textSize, anchor);
				document.body.appendChild(node);
				node.style.top = v-(node.offsetHeight/2)+"px";
				g.appendChild(node);
			}
		}
		return g;	//	HTMLDivElement
	},
	render: function(
		/* dojo.charting.PlotArea */plotArea, 
		/* dojo.charting.Plot */plot,
		/* dojo.charting.Axis */drawAgainst,
		/* string */plane
	){
		//	summary
		//	Renders this axis to the given plot.

		//	get the origin plot point.
		var area = plotArea.getArea();
		var stroke = 1;
		var style = "stroke:#000;stroke-width:"+stroke+"px;";
		var textSize=10;
		var coord = drawAgainst.getCoord(this.origin, plotArea, plot);

		//	draw the axis.
		var g = this.nodes.main = document.createElement("div");
		g.setAttribute("id", this.getId());	//	need a handle if we have to kill parts of the axis def.
		var line = this.nodes.axis = document.createElement("v:line");
		line.setAttribute("strokecolor", "#000");
		line.setAttribute("strokeweight", stroke+"px");
		var s=line.style;
		s.position="absolute";
		s.top="0px";
		s.left="0px";
		s.antialias="false";
		if(plane == "x"){
			line.setAttribute("from", area.left+"px,"+coord+"px");
			line.setAttribute("to", area.right+"px,"+coord+"px");

			//	set up the labels
			var y = coord + Math.floor(textSize/2);
			if(this.showLines){
				g.appendChild(this.renderLines(plotArea, plot, plane, y));
			}
			if(this.showTicks){
				g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
			}
			if(this.showLabels){
				g.appendChild(this.renderLabels(plotArea, plot, plane, y, textSize, "center"));
			}
			if(this.showLabel && this.label){
				var x = plotArea.size.width/2;
				var y = coord + Math.round(textSize*1.5); 
				var text = document.createElement("div");
				var s=text.style;
				text.innerHTML=this.label;
				s.fontSize=(textSize+2)+"px";
				s.fontFamily="sans-serif";
				s.fontWeight="bold";
				s.position="absolute";
				s.top = y+"px";
				s.left = x + "px";
				s.textAlign="center";
				document.body.appendChild(text);
				text.style.left = x-(text.offsetWidth/2)+"px";
				g.appendChild(text);
			}
		} else {
			line.setAttribute("from", coord+"px,"+area.top+"px");
			line.setAttribute("to", coord+"px,"+area.bottom+"px");

			//	set up the labels
			var isMax = this.origin == drawAgainst.range.upper;
			var x = coord+4;
			var anchor = "left";
			if(!isMax){
				x = area.right-coord+textSize+4;
				anchor = "right";
				if(coord == area.left){ x += (textSize*2)-(textSize/2); }
			}
			if(this.showLines){
				g.appendChild(this.renderLines(plotArea, plot, plane, x));
			}
			if(this.showTicks){
				g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
			}
			if(this.showLabels){
				g.appendChild(this.renderLabels(plotArea, plot, plane, x, textSize, anchor));
			}
			if(this.showLabel && this.label){
				x += (textSize*2)-2;
				var y = plotArea.size.height/2;
				var text = document.createElement("div");
				var s=text.style;
				text.innerHTML=this.label;
				s.fontSize=(textSize+2)+"px";
				s.fontFamily="sans-serif";
				s.fontWeight="bold";
				s.position="absolute";
				s.height = plotArea.size.height+"px";
				s.writingMode = "tb-rl";
				s.textAlign="center";
				s[anchor] = x+"px";
				document.body.appendChild(text);
				s.top = y-(text.offsetHeight/2)+"px";
				g.appendChild(text);
			}
		}
		g.appendChild(line);
		return g;	//	HTMLDivElement
	}
});

__CPAN_DIR__ src/uri
__CPAN_FILE__ src/uri/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [["dojo.uri.Uri", false, false]]
});
dojo.provide("dojo.uri.*");

__CPAN_FILE__ src/uri/Uri.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uri.Uri");

dojo.uri = new function() {
	this.dojoUri = function (/*dojo.uri.Uri||String*/uri) {
		// summary: returns a Uri object resolved relative to the dojo root
		return new dojo.uri.Uri(dojo.hostenv.getBaseScriptUri(), uri);
	}
	
	this.moduleUri = function(/*String*/module, /*dojo.uri.Uri||String*/uri){
		// summary: returns a Uri object relative to a (top-level) module
		// description: Examples: dojo.uri.moduleUri("dojo","Editor"), or dojo.uri.moduleUri("acme","someWidget")
		var loc = dojo.hostenv.getModulePrefix(module);
		if(!loc){return null;}
		if(loc.lastIndexOf("/") != loc.length-1){loc += "/";}
		return new dojo.uri.Uri(dojo.hostenv.getBaseScriptUri()+loc,uri);
	}

	this.Uri = function (/*dojo.uri.Uri||String...*/) {
		// summary: Constructor to create an object representing a URI.
		// description: 
		//  Each argument is evaluated in order relative to the next until
		//  a canonical uri is produced. To get an absolute Uri relative
		//  to the current document use
		//      new dojo.uri.Uri(document.baseURI, uri)

		// TODO: support for IPv6, see RFC 2732

		// resolve uri components relative to each other
		var uri = arguments[0];
		for (var i = 1; i < arguments.length; i++) {
			if(!arguments[i]) { continue; }

			// Safari doesn't support this.constructor so we have to be explicit
			var relobj = new dojo.uri.Uri(arguments[i].toString());
			var uriobj = new dojo.uri.Uri(uri.toString());

			if ((relobj.path=="")&&(relobj.scheme==null)&&(relobj.authority==null)&&(relobj.query==null)) {
				if (relobj.fragment != null) { uriobj.fragment = relobj.fragment; }
				relobj = uriobj;
			} else if (relobj.scheme == null) {
				relobj.scheme = uriobj.scheme;
			
				if (relobj.authority == null) {
					relobj.authority = uriobj.authority;
					
					if (relobj.path.charAt(0) != "/") {
						var path = uriobj.path.substring(0,
							uriobj.path.lastIndexOf("/") + 1) + relobj.path;

						var segs = path.split("/");
						for (var j = 0; j < segs.length; j++) {
							if (segs[j] == ".") {
								if (j == segs.length - 1) { segs[j] = ""; }
								else { segs.splice(j, 1); j--; }
							} else if (j > 0 && !(j == 1 && segs[0] == "") &&
								segs[j] == ".." && segs[j-1] != "..") {

								if (j == segs.length - 1) { segs.splice(j, 1); segs[j - 1] = ""; }
								else { segs.splice(j - 1, 2); j -= 2; }
							}
						}
						relobj.path = segs.join("/");
					}
				}
			}

			uri = "";
			if (relobj.scheme != null) { uri += relobj.scheme + ":"; }
			if (relobj.authority != null) { uri += "//" + relobj.authority; }
			uri += relobj.path;
			if (relobj.query != null) { uri += "?" + relobj.query; }
			if (relobj.fragment != null) { uri += "#" + relobj.fragment; }
		}

		this.uri = uri.toString();

		// break the uri into its main components
		var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
	  var r = this.uri.match(new RegExp(regexp));

		this.scheme = r[2] || (r[1] ? "" : null);
		this.authority = r[4] || (r[3] ? "" : null);
		this.path = r[5]; // can never be undefined
		this.query = r[7] || (r[6] ? "" : null);
		this.fragment  = r[9] || (r[8] ? "" : null);
		
		if (this.authority != null) {
			// server based naming authority
			regexp = "^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$";
			r = this.authority.match(new RegExp(regexp));
			
			this.user = r[3] || null;
			this.password = r[4] || null;
			this.host = r[5];
			this.port = r[7] || null;
		}
	
		this.toString = function(){ return this.uri; }
	}
};

__CPAN_DIR__ src/math
__CPAN_FILE__ src/math/points.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.math.points");
dojo.require("dojo.math");

dojo.math.points = {
	translate: function(/* array */a, /* array */b) {
		//	summary
		//	translate a by b, and return the result.
		if( a.length != b.length ) {
			dojo.raise("dojo.math.translate: points not same size (a:[" + a + "], b:[" + b + "])");
		}
		var c = new Array(a.length);
		for(var i = 0; i < a.length; i++) {
			c[i] = a[i] + b[i];
		}
		return c;	//	array
	},

	midpoint: function(/* array */a, /* array */b) {
		//	summary
		//	Find the point midway between a and b
		if( a.length != b.length ) {
			dojo.raise("dojo.math.midpoint: points not same size (a:[" + a + "], b:[" + b + "])");
		}
		var c = new Array(a.length);
		for(var i = 0; i < a.length; i++) {
			c[i] = (a[i] + b[i]) / 2;
		}
		return c;	//	array
	},

	invert: function(/* array */a) {
		//	summary
		//	invert the values in a and return it.
		var b = new Array(a.length);
		for(var i = 0; i < a.length; i++) { b[i] = -a[i]; }
		return b;	//	array
	},

	distance: function(/* array */a, /* array */b) {
		//	summary
		//	Calculate the distance between point a and point b
		return Math.sqrt(Math.pow(b[0]-a[0], 2) + Math.pow(b[1]-a[1], 2));	// 	float
	}
};

__CPAN_FILE__ src/math/matrix.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.math.matrix");

// some of this code is based on
// http://www.mkaz.com/math/MatrixCalculator.java
// (published under a BSD Open Source License)
//
// the rest is from my vague memory of matricies in school [cal]
//
// the copying of arguments is a little excessive, and could be trimmed back in
// the case where a function doesn't modify them at all (but some do!)
//
// 2006-06-25: Some enhancements submitted by Erel Segal:
// * addition: a tolerance constant for determinant calculations.
// * performance fix: removed unnecessary argument copying.
// * addition: function "product" for multiplying more than 2 matrices
// * addition: function "sum" for adding any number of matrices
// * bug fix: inversion of a 1x1 matrix without using the adjoint
// * performance fixes: upperTriangle
// * addition: argument "value" to function create, to initialize the matrix with a custom val
// * addition: functions "ones" and "zeros" - like Matlab[TM] functions with the same name.
// * addition: function "identity" for creating an identity matrix of a given size.
// * addition: argument "decimal_points" to function format
// * bug fix: adjoint of a 0-size matrix
// * performance fixes: adjoint
//

dojo.math.matrix.iDF = 0;

// Erel: values lower than this value are considered zero (in detereminant calculations).
// It is analogous to Maltab[TM]'s "eps".
dojo.math.matrix.ALMOST_ZERO = 1e-10;
dojo.math.matrix.multiply = function(a, b){
	var ay = a.length;
	var ax = a[0].length;
	var by = b.length;
	var bx = b[0].length;

	if (ax != by){
		dojo.debug("Can't multiply matricies of sizes "+ax+','+ay+' and '+bx+','+by);
		return [[0]];
	}

	var c = [];
	for(var k=0; k<ay; k++){
		c[k] = [];
		for(var i=0; i<bx; i++){
			c[k][i] = 0;
			for(var m=0; m<ax; m++){
				c[k][i] += a[k][m]*b[m][i];
			}
		}
	}
	return c;
}

// Erel: added a "product" function to calculate product of more than 2 matrices:
dojo.math.matrix.product = function() {
	if (arguments.length==0) {
		dojo.debug ("can't multiply 0 matrices!");
		return 1;
	}
	var result = arguments[0];
	for (var i=1; i<arguments.length; i++){
		result = dojo.math.matrix.multiply(result,arguments[i]);
	}
	return result;
}

// Erel: added a "sum" function to calculate sum of more than 2 matrices:
dojo.math.matrix.sum = function() {
	if (arguments.length==0) {
		dojo.debug ("can't sum 0 matrices!");
		return 0;
	}
	var result = dojo.math.matrix.copy(arguments[0]);
	var rows = result.length;
	if (rows==0) {
		dojo.debug ("can't deal with matrices of 0 rows!");
		return 0;
	}
	var cols = result[0].length;
	if (cols==0) {
		dojo.debug ("can't deal with matrices of 0 cols!");
		return 0;
	}
	for (var i=1; i<arguments.length; ++i) {
		var arg = arguments[i];
		if (arg.length!=rows || arg[0].length!=cols) {
			dojo.debug ("can't add matrices of different dimensions: first dimensions were " + rows + "x" + cols + ", current dimensions are "+arg.length + "x" + arg[0].length);
			return 0;
		}
		
		// The actual addition:
		for (var r=0; r<rows; r++){
			for (var c=0; c<cols; c++){
				result[r][c] += arg[r][c];
			}
		}
	}
	return result;
}


dojo.math.matrix.inverse = function(a){
	// Erel: added special case: inverse of a 1x1 matrix can't be calculated by adjoint
	if (a.length==1 && a[0].length==1){
		return [[ 1 / a[0][0] ]];
	}

	// Formula used to Calculate Inverse:
	// inv(A) = 1/det(A) * adj(A)
	
	var tms = a.length;
	var m = dojo.math.matrix.create(tms, tms);
	var mm = dojo.math.matrix.adjoint(a);
	var det = dojo.math.matrix.determinant(a);
	var dd = 0;

	if(det == 0){
		dojo.debug("Determinant Equals 0, Not Invertible.");
		return [[0]];
	}else{
		dd = 1 / det;
	}

	for (var i = 0; i < tms; i++){
		for (var j = 0; j < tms; j++) {
			m[i][j] = dd * mm[i][j];
		}
	}
	return m;
}

dojo.math.matrix.determinant = function(a){
	if (a.length != a[0].length){
		dojo.debug("Can't calculate the determiant of a non-squre matrix!");
		return 0;
	}

	var tms = a.length;
	var det = 1;
	var b = dojo.math.matrix.upperTriangle(a);

	for (var i=0; i < tms; i++){
		var bii = b[i][i];
		if (Math.abs(bii) < dojo.math.matrix.ALMOST_ZERO){
			return 0;
		}
		det *= bii;
	}
	det = det * dojo.math.matrix.iDF;
	return det;
}

dojo.math.matrix.upperTriangle = function(m){
	m = dojo.math.matrix.copy(m);     // Copy m, because m is changed!
	var f1 = 0;
	var temp = 0;
	var tms = m.length;
	var v = 1;

	//Erel: why use a global variable and not a local variable?
	dojo.math.matrix.iDF = 1;

	for (var col = 0; col < tms - 1; col++) {
		if (typeof m[col][col] != 'number'){
			dojo.debug("non-numeric entry found in a numeric matrix: m["+col+"]["+col+"]="+m[col][col]);
		}
		v = 1;
		var stop_loop = 0;
		
		// check if there is a 0 in diagonal
		while ((m[col][col] == 0) && !stop_loop) {
			// if so,  switch rows until there is no 0 in diagonal:
			if (col + v >= tms){
				// check if switched all rows
				dojo.math.matrix.iDF = 0;
				stop_loop = 1;
			}else{
				for (var r = 0; r < tms; r++) {
					temp = m[col][r];
					m[col][r] = m[col + v][r]; // switch rows
					m[col + v][r] = temp;
				}
				v++; // count row switchs
				dojo.math.matrix.iDF *= -1; // each switch changes determinant factor
			}
		}
		
		// loop over lower-right triangle (where row>col):
		// for each row, make m[row][col] = 0 by linear operations that don't change the determinant:
		for (var row = col + 1; row < tms; row++) {
			if (typeof m[row][col] != 'number'){
				dojo.debug("non-numeric entry found in a numeric matrix: m["+row+"]["+col+"]="+m[row][col]);
			}
			if (typeof m[col][row] != 'number'){
				dojo.debug("non-numeric entry found in a numeric matrix: m["+col+"]["+row+"]="+m[col][row]);
			}
			if (m[col][col] != 0) {
				var f1 = (-1) * m[row][col] / m[col][col];
				// this should make m[row][col] zero:
				// 	m[row] += f1 * m[col];
				for (var i = col; i < tms; i++) {
					m[row][i] = f1 * m[col][i] + m[row][i];
				}
			}
		}
	}
	return m;
}

// Erel: added parameter "value" - a custom default value to fill the matrix with.
dojo.math.matrix.create = function(a, b, value){
	if(!value){
		value = 0;
	}
	var m = [];
	for(var i=0; i<b; i++){
		m[i] = [];
		for(var j=0; j<a; j++){
			m[i][j] = value;
		}
	}
	return m;
}

// Erel implement Matlab[TM] functions "ones" and "zeros"
dojo.math.matrix.ones = function(a,b) { 
	return dojo.math.matrix.create(a,b,1); 
}
dojo.math.matrix.zeros = function(a,b) { 
	return dojo.math.matrix.create(a,b,0); 
}

// Erel: added function that returns identity matrix.
//	size = number of rows and cols in the matrix.
//	scale = an optional value to multiply the matrix by (default is 1).
dojo.math.matrix.identity = function(size, scale){
	if (!scale){
		scale = 1;
	}
	var m = [];
	for(var i=0; i<size; i++){
		m[i] = [];
		for(var j=0; j<size; j++){
			m[i][j] = (i==j? scale: 0);
		}
	}
	return m;
}

dojo.math.matrix.adjoint = function(a){
	var tms = a.length;

	// Erel: added "<=" to catch zero-size matrix
	if (tms <= 1){
		dojo.debug("Can't find the adjoint of a matrix with a dimension less than 2");
		return [[0]];
	}

	if (a.length != a[0].length){
		dojo.debug("Can't find the adjoint of a non-square matrix");
		return [[0]];
	}

	var m = dojo.math.matrix.create(tms, tms);

	var ii = 0;
	var jj = 0;
	var ia = 0;
	var ja = 0;
	var det = 0;
	var ap = dojo.math.matrix.create(tms-1, tms-1);

	for (var i = 0; i < tms; i++){
		for (var j = 0; j < tms; j++){
			ia = 0;
			for (ii = 0; ii < tms; ii++) {   // create a temporary matrix for determinant calc
				if (ii==i){
					continue;       // skip current row
				}
				ja = 0;
				for (jj = 0; jj < tms; jj++) {
					if (jj==j){
						continue;       // skip current col
					}
					ap[ia][ja] = a[ii][jj];
					ja++;
				}
				ia++;
			}
		
			det = dojo.math.matrix.determinant(ap);
			m[i][j] = Math.pow(-1 , (i + j)) * det;
		}
	}
	m = dojo.math.matrix.transpose(m);
	return m;
}

dojo.math.matrix.transpose = function(a){
	var m = dojo.math.matrix.create(a.length, a[0].length);
	for (var i = 0; i < a.length; i++){
		for (var j = 0; j < a[i].length; j++){
			m[j][i] = a[i][j];
		}
	}
	return m;
}

// Erel: added decimal_points argument
dojo.math.matrix.format = function(a, decimal_points){
	if (arguments.length<=1){
		decimal_points = 5;
	}

	function format_int(x, dp){
		var fac = Math.pow(10 , dp);
		var a = Math.round(x*fac)/fac;
		var b = a.toString();
		if (b.charAt(0) != '-'){ b = ' ' + b;}
		var has_dp = 0;
		for(var i=1; i<b.length; i++){
			if (b.charAt(i) == '.'){ has_dp = 1; }
		}
		if (!has_dp){ b += '.'; }
		while(b.length < dp+3){ b += '0'; }
		return b;
	}

	var ya = a.length;
	var xa = ya>0? a[0].length: 0;
	var buffer = '';
	for (var y=0; y<ya; y++){
		buffer += '| ';
		for (var x=0; x<xa; x++){
			buffer += format_int(a[y][x], decimal_points) + ' ';
		}
		buffer += '|\n';
	}
	return buffer;
}

dojo.math.matrix.copy = function(a){
	var ya = a.length;
	var xa = a[0].length;
	var m = dojo.math.matrix.create(xa, ya);
	for (var y=0; y<ya; y++){
		for (var x=0; x<xa; x++){
			m[y][x] = a[y][x];
		}
	}
	return m;
}

dojo.math.matrix.scale = function(k, a){
	a = dojo.math.matrix.copy(a);  // Copy a because a is changed!
	var ya = a.length;
	var xa = a[0].length;

	for (var y=0; y<ya; y++){
		for (var x=0; x<xa; x++){
			a[y][x] *= k;
		}
	}
	return a;
}

__CPAN_FILE__ src/math/curves.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.math.curves");
dojo.require("dojo.math");

/* Curves from Dan's 13th lib stuff.
 * See: http://pupius.co.uk/js/Toolkit.Drawing.js
 *      http://pupius.co.uk/dump/dojo/Dojo.Math.js
 */

dojo.math.curves = {
	Line: function(/* array */start, /* array */end) {
		//	summary
		//	Creates a straight line object
		this.start = start;
		this.end = end;
		this.dimensions = start.length;

		for(var i = 0; i < start.length; i++) {
			start[i] = Number(start[i]);
		}

		for(var i = 0; i < end.length; i++) {
			end[i] = Number(end[i]);
		}

		//simple function to find point on an n-dimensional, straight line
		this.getValue = function(/* float */n){
			//	summary
			//	Returns the point at point N (in terms of percentage) on this line.
			var retVal = new Array(this.dimensions);
			for(var i=0;i<this.dimensions;i++)
				retVal[i] = ((this.end[i] - this.start[i]) * n) + this.start[i];
			return retVal;	//	array
		}
		return this;	//	dojo.math.curves.Line
	},

	Bezier: function(/* array */pnts) {
		//	summary
		//	Creates a bezier curve
		//	Takes an array of points, the first is the start point, the last is end point and the ones in
		//	between are the Bezier control points.
		this.getValue = function(/* float */step) {
			//	summary
			//	Returns the point at point N (in terms of percentage) on this curve.
			if(step >= 1) return this.p[this.p.length-1];	// if step>=1 we must be at the end of the curve
			if(step <= 0) return this.p[0];					// if step<=0 we must be at the start of the curve
			var retVal = new Array(this.p[0].length);
			for(var k=0;j<this.p[0].length;k++) { retVal[k]=0; }
			for(var j=0;j<this.p[0].length;j++) {
				var C=0; var D=0;
				for(var i=0;i<this.p.length;i++) {
					C += this.p[i][j] * this.p[this.p.length-1][0]
						* dojo.math.bernstein(step,this.p.length,i);
				}
				for(var l=0;l<this.p.length;l++) {
					D += this.p[this.p.length-1][0] * dojo.math.bernstein(step,this.p.length,l);
				}
				retVal[j] = C/D;
			}
			return retVal;	//	array
		}
		this.p = pnts;
		return this;	//	dojo.math.curves.Bezier
	},

	CatmullRom : function(/* array */pnts, /* float */c) {
		//	summary
		//	Creates a catmull-rom spline curve with c tension.
		this.getValue = function(/* float */step) {
			//	summary
			//	Returns the point at point N (in terms of percentage) on this curve.
			var percent = step * (this.p.length-1);
			var node = Math.floor(percent);
			var progress = percent - node;

			var i0 = node-1; if(i0 < 0) i0 = 0;
			var i = node;
			var i1 = node+1; if(i1 >= this.p.length) i1 = this.p.length-1;
			var i2 = node+2; if(i2 >= this.p.length) i2 = this.p.length-1;

			var u = progress;
			var u2 = progress*progress;
			var u3 = progress*progress*progress;

			var retVal = new Array(this.p[0].length);
			for(var k=0;k<this.p[0].length;k++) {
				var x1 = ( -this.c * this.p[i0][k] ) + ( (2 - this.c) * this.p[i][k] ) + ( (this.c-2) * this.p[i1][k] ) + ( this.c * this.p[i2][k] );
				var x2 = ( 2 * this.c * this.p[i0][k] ) + ( (this.c-3) * this.p[i][k] ) + ( (3 - 2 * this.c) * this.p[i1][k] ) + ( -this.c * this.p[i2][k] );
				var x3 = ( -this.c * this.p[i0][k] ) + ( this.c * this.p[i1][k] );
				var x4 = this.p[i][k];

				retVal[k] = x1*u3 + x2*u2 + x3*u + x4;
			}
			return retVal;	//	array
		}

		if(!c) this.c = 0.7;
		else this.c = c;
		this.p = pnts;

		return this;	//	dojo.math.curves.CatmullRom
	},

	// FIXME: This is the bad way to do a partial-arc with 2 points. We need to have the user
	// supply the radius, otherwise we always get a half-circle between the two points.
	Arc : function(/* array */start, /* array */end, /* boolean? */ccw) {
		//	summary
		//	Creates an arc with a counter clockwise switch
		var center = dojo.math.points.midpoint(start, end);
		var sides = dojo.math.points.translate(dojo.math.points.invert(center), start);
		var rad = Math.sqrt(Math.pow(sides[0], 2) + Math.pow(sides[1], 2));
		var theta = dojo.math.radToDeg(Math.atan(sides[1]/sides[0]));
		if( sides[0] < 0 ) {
			theta -= 90;
		} else {
			theta += 90;
		}
		dojo.math.curves.CenteredArc.call(this, center, rad, theta, theta+(ccw?-180:180));
	},

	CenteredArc : function(/* array */center, /* float */radius, /* array */start, /* array */end) {
		//	summary
		// 	Creates an arc object, with center and radius (Top of arc = 0 degrees, increments clockwise)
		//  center => 2D point for center of arc
		//  radius => scalar quantity for radius of arc
		//  start  => to define an arc specify start angle (default: 0)
		//  end    => to define an arc specify start angle
		this.center = center;
		this.radius = radius;
		this.start = start || 0;
		this.end = end;

		this.getValue = function(/* float */n) {
			//	summary
			//	Returns the point at point N (in terms of percentage) on this curve.
			var retVal = new Array(2);
			var theta = dojo.math.degToRad(this.start+((this.end-this.start)*n));

			retVal[0] = this.center[0] + this.radius*Math.sin(theta);
			retVal[1] = this.center[1] - this.radius*Math.cos(theta);
	
			return retVal;	//	array
		}

		return this;	//	dojo.math.curves.CenteredArc
	},

	Circle : function(/* array */center, /* float */radius) {
		//	summary
		// Special case of Arc (start = 0, end = 360)
		dojo.math.curves.CenteredArc.call(this, center, radius, 0, 360);
		return this;	//	dojo.math.curves.Circle
	},

	Path : function() {
		//	summary
		// 	Generic path shape, created from curve segments
		var curves = [];
		var weights = [];
		var ranges = [];
		var totalWeight = 0;

		this.add = function(/* dojo.math.curves.* */curve, /* float */weight) {
			//	summary
			//	Add a curve segment to this path
			if( weight < 0 ) { dojo.raise("dojo.math.curves.Path.add: weight cannot be less than 0"); }
			curves.push(curve);
			weights.push(weight);
			totalWeight += weight;
			computeRanges();
		}

		this.remove = function(/* dojo.math.curves.* */curve) {
			//	summary
			//	Remove a curve segment from this path
			for(var i = 0; i < curves.length; i++) {
				if( curves[i] == curve ) {
					curves.splice(i, 1);
					totalWeight -= weights.splice(i, 1)[0];
					break;
				}
			}
			computeRanges();
		}

		this.removeAll = function() {
			//	summary
			//	Remove all curve segments
			curves = [];
			weights = [];
			totalWeight = 0;
		}

		this.getValue = function(/* float */n) {
			//	summary
			//	Returns the point at point N (in terms of percentage) on this curve.
			var found = false, value = 0;
			for(var i = 0; i < ranges.length; i++) {
				var r = ranges[i];
				//w(r.join(" ... "));
				if( n >= r[0] && n < r[1] ) {
					var subN = (n - r[0]) / r[2];
					value = curves[i].getValue(subN);
					found = true;
					break;
				}
			}

			// FIXME: Do we want to assume we're at the end?
			if( !found ) {
				value = curves[curves.length-1].getValue(1);
			}

			for(var j = 0; j < i; j++) {
				value = dojo.math.points.translate(value, curves[j].getValue(1));
			}
			return value;	//	array
		}

		function computeRanges() {
			var start = 0;
			for(var i = 0; i < weights.length; i++) {
				var end = start + weights[i] / totalWeight;
				var len = end - start;
				ranges[i] = [start, end, len];
				start = end;
			}
		}

		return this;	//	dojo.math.curves.Path
	}
};

__CPAN_FILE__ src/math/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		["dojo.math", false, false],
		["dojo.math.curves", false, false],
		["dojo.math.points", false, false]
	]
});
dojo.provide("dojo.math.*");

__CPAN_DIR__ src/collections
__CPAN_FILE__ src/collections/Set.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Set");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.collections.ArrayList");

dojo.collections.Set = new function(){
	//	summary
	//	Singleton for dealing with common set operations.
	this.union = function(/* array */setA, /* array */setB){
		//	summary
		//	Return the union of the two passed sets.
		if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
		if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
		if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
		var result = new dojo.collections.ArrayList(setA.toArray());
		var e = setB.getIterator();
		while(!e.atEnd()){
			var item=e.get();
			if(!result.contains(item)){
				result.add(item);
			}
		}
		return result;	//	dojo.collections.ArrayList
	};
	this.intersection = function(/* array */setA, /* array */setB){
		//	summary
		//	Return the intersection of the two passed sets.
		if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
		if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
		if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
		var result = new dojo.collections.ArrayList();
		var e = setB.getIterator();
		while(!e.atEnd()){
			var item=e.get();
			if(setA.contains(item)){
				result.add(item);
			}
		}
		return result;	//	dojo.collections.ArrayList
	};
	this.difference = function(/* array */setA, /* array */setB){
		//	summary
		//	Returns everything in setA that is not in setB.
		if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
		if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
		if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
		var result = new dojo.collections.ArrayList();
		var e=setA.getIterator();
		while(!e.atEnd()){
			var item=e.get();
			if(!setB.contains(item)){
				result.add(item);
			}
		}
		return result;	//	dojo.collections.ArrayList
	};
	this.isSubSet = function(/* array */setA, /* array */setB) {
		//	summary
		//	Returns if set B is a subset of set A.
		if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
		if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
		if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
		var e = setA.getIterator();
		while(!e.atEnd()){
			if(!setB.contains(e.get())){
				return false;	//	boolean
			}
		}
		return true;	//	boolean
	};
	this.isSuperSet = function(/* array */setA, /* array */setB){
		//	summary
		//	Returns if set B is a superset of set A.
		if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
		if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
		if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
		var e = setB.getIterator();
		while(!e.atEnd()){
			if(!setA.contains(e.get())){
				return false;	//	boolean
			}
		}
		return true;	//	boolean
	};
}();

__CPAN_FILE__ src/collections/Collections.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Collections");

dojo.collections.DictionaryEntry=function(/* string */k, /* object */v){
	//	summary
	//	return an object of type dojo.collections.DictionaryEntry
	this.key=k;
	this.value=v;
	this.valueOf=function(){ 
		return this.value; 	//	object
	};
	this.toString=function(){ 
		return String(this.value);	//	string 
	};
}

/*	Iterators
 *	The collections.Iterators (Iterator and DictionaryIterator) are built to
 *	work with the Collections included in this module.  However, they *can*
 *	be used with arrays and objects, respectively, should one choose to do so.
 */
dojo.collections.Iterator=function(/* array */arr){
	//	summary
	//	return an object of type dojo.collections.Iterator
	var a=arr;
	var position=0;
	this.element=a[position]||null;
	this.atEnd=function(){
		//	summary
		//	Test to see if the internal cursor has reached the end of the internal collection.
		return (position>=a.length);	//	bool
	};
	this.get=function(){
		//	summary
		//	Test to see if the internal cursor has reached the end of the internal collection.
		if(this.atEnd()){
			return null;		//	object
		}
		this.element=a[position++];
		return this.element;	//	object
	};
	this.map=function(/* function */fn, /* object? */scope){
		//	summary
		//	Functional iteration with optional scope.
		var s=scope||dj_global;
		if(Array.map){
			return Array.map(a,fn,s);	//	array
		}else{
			var arr=[];
			for(var i=0; i<a.length; i++){
				arr.push(fn.call(s,a[i]));
			}
			return arr;		//	array
		}
	};
	this.reset=function(){
		//	summary
		//	reset the internal cursor.
		position=0;
		this.element=a[position];
	};
}

/*	Notes:
 *	The DictionaryIterator no longer supports a key and value property;
 *	the reality is that you can use this to iterate over a JS object
 *	being used as a hashtable.
 */
dojo.collections.DictionaryIterator=function(/* object */obj){
	//	summary
	//	return an object of type dojo.collections.DictionaryIterator
	var a=[];	//	Create an indexing array
	var testObject={};
	for(var p in obj){
		if(!testObject[p]){
			a.push(obj[p]);	//	fill it up
		}
	}
	var position=0;
	this.element=a[position]||null;
	this.atEnd=function(){
		//	summary
		//	Test to see if the internal cursor has reached the end of the internal collection.
		return (position>=a.length);	//	bool
	};
	this.get=function(){
		//	summary
		//	Test to see if the internal cursor has reached the end of the internal collection.
		if(this.atEnd()){
			return null;		//	object
		}
		this.element=a[position++];
		return this.element;	//	object
	};
	this.map=function(/* function */fn, /* object? */scope){
		//	summary
		//	Functional iteration with optional scope.
		var s=scope||dj_global;
		if(Array.map){
			return Array.map(a,fn,s);	//	array
		}else{
			var arr=[];
			for(var i=0; i<a.length; i++){
				arr.push(fn.call(s,a[i]));
			}
			return arr;		//	array
		}
	};
	this.reset=function() { 
		//	summary
		//	reset the internal cursor.
		position=0; 
		this.element=a[position];
	};
};

__CPAN_FILE__ src/collections/Store.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Store");
dojo.require("dojo.lang.common");

/*	Store
 *	Designed to be a simple store of data with access methods...
 *	specifically to be mixed into other objects (such as widgets).
 */
dojo.collections.Store = function(/* array? */jsonArray){
	//	summary
	//	Data Store with accessor methods.
	var data = [];
	this.keyField = "Id";

	this.get = function(){
		//	summary
		//	Get the internal data array, should not be used.
		return data;	//	array
	};
	this.getByKey = function(/* string */key){
		//	summary
		//	Find the internal data object by key.
		for(var i=0; i<data.length; i++){
			if(data[i].key==key){
				return data[i];	// object
			}
		}
		return null;	// null
	};
	this.getByIndex = function(/*number*/idx){ 
		//	summary
		//	Get the internal data object by index.
		return data[idx]; 	// object
	};
	
	this.getData = function(){
		//	summary
		//	Get an array of source objects.
		var arr = [];
		for(var i=0; i<data.length; i++){
			arr.push(data[i].src);
		}
		return arr;	//	array
	};
	this.getDataByKey = function(/*string*/key){
		//	summary
		//	Get the source object by key.
		for(var i=0; i<data.length; i++){
			if(data[i].key==key){
				return data[i].src; //	object
			}
		}
		return null;	//	null
	};
	this.getDataByIndex = function(/*number*/idx){ 
		//	summary
		//	Get the source object at index idx.
		return data[idx].src; 	//	object
	};

	this.update = function(/* Object */obj, /* string */fieldPath, /* Object */val){
		var parts=fieldPath.split("."), i=0, o=obj, field;
		if(parts.length>1) {
			field = parts.pop();
			do{ 
				if(parts[i].indexOf("()")>-1){
					var temp=parts[i++].split("()")[0];
					if(!o[temp]){
						dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + temp + "' is not a property of the passed object.");
					} else {
						//	this *will* throw an error if the method in question can't be invoked without arguments.
						o = o[temp]();
					}
				} else {
					o = o[parts[i++]];
				}
			} while (i<parts.length && o != null);
		} else {
			field = parts[0];
		}

		obj[field] = val;
		this.onUpdateField(obj, fieldPath, val);
	};

	this.forEach = function(/* function */fn){
		//	summary
		//	Functional iteration directly on the internal data array.
		if(Array.forEach){
			Array.forEach(data, fn, this);
		}else{
			for(var i=0; i<data.length; i++){
				fn.call(this, data[i]);
			}
		}
	};
	this.forEachData = function(/* function */fn){
		//	summary
		//	Functional iteration on source objects in internal data array.
		if(Array.forEach){
			Array.forEach(this.getData(), fn, this);
		}else{
			var a=this.getData();
			for(var i=0; i<a.length; i++){
				fn.call(this, a[i]);
			}
		}
	};

	this.setData = function(/*array*/arr){
		//	summary
		//	Set up the internal data.
		data = []; 	//	don't fire onClearData
		for(var i=0; i<arr.length; i++){
			data.push({ 
				key:arr[i][this.keyField], 
				src:arr[i]
			});
		}
		this.onSetData();
	};
	
	this.clearData = function(){
		//	summary
		//	Clears the internal data array.
		data = [];
		this.onClearData();
	};

	this.addData = function(/*obj*/obj,/*string?*/key){ 
		//	summary
		//	Add an object with optional key to the internal data array.
		var k = key || obj[this.keyField];
		if(this.getByKey(k)){
			var o = this.getByKey(k);
			o.src = obj;
		} else {
			var o={ key:k, src:obj };
			data.push(o);
		}
		this.onAddData(o);
	};
	this.addDataRange = function(/*array*/arr){
		//	summary
		//	Add a range of objects to the internal data array.
		var objects=[];
		for(var i=0; i<arr.length; i++){
			var k = arr[i][this.keyField];
			if(this.getByKey(k)){
				var o = this.getByKey(k);
				o.src = obj;
			} else {
				var o = { key:k, src:arr[i] };
				data.push(o);
			}
			objects.push(o);
		}
		this.onAddDataRange(objects);
	};
	
	this.removeData = function(/*obj*/obj){
		//	summary
		//	remove the passed object from the internal data array.
		var idx=-1;
		var o=null;
		for(var i=0; i<data.length; i++){
			if(data[i].src==obj){
				idx=i;
				o=data[i];
				break;
			}
		}
		this.onRemoveData(o);
		if(idx>-1){
			data.splice(idx,1);
		}
	};
	this.removeDataByKey = function(/*string*/key){
		//	summary
		//	remove the object at key from the internal data array.
		this.removeData(this.getDataByKey(key));
	};
	this.removeDataByIndex = function(/*number*/idx){
		//	summary
		//	remove the object at idx from the internal data array.
		this.removeData(this.getDataByIndex(idx));
	};

	if(jsonArray && jsonArray.length && jsonArray[0]){
		this.setData(jsonArray);
	}
};

dojo.extend(dojo.collections.Store, {
	getField:function(/*object*/obj, /*string*/field){
		//	helper to get the nested value if needed.
		var parts=field.split("."), i=0, o=obj;
		do{ 
			if(parts[i].indexOf("()")>-1){
				var temp=parts[i++].split("()")[0];
				if(!o[temp]){
					dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + temp + "' is not a property of the passed object.");
				} else {
					//	this *will* throw an error if the method in question can't be invoked without arguments.
					o = o[temp]();
				}
			} else {
				o = o[parts[i++]];
			}
		} while (i<parts.length && o != null);
		
		if(i < parts.length){
			dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + field + "' is not a property of the passed object.");
		}
		return o; // object
	},
	getFromHtml:function(/* array */meta, /* HTMLTableBody */body, /* function? */fnMod){
		//	summary
		//	Parse HTML data into native JSON structure for the store.
		var rows = body.rows;

		//	create a data constructor.
		var ctor=function(row){
			var obj = {};
			for(var i=0; i<meta.length; i++){
				var o = obj;
				var data = row.cells[i].innerHTML;
				var p = meta[i].getField();
				if(p.indexOf(".") > -1){
					p = p.split(".");
					while(p.length>1){
						var pr = p.shift();
						o[pr] = {};
						o = o[pr];
					}
					p = p[0];
				}

				var type = meta[i].getType();
				if(type == String){
					o[p] = data;
				} else {
					if(data){
						o[p] = new type(data);
					} else {
						o[p] = new type();
					}
				}
			}
			return obj;
		};

		//	we have initialization data, let's parse it.
		var arr=[];
		for(var i=0; i<rows.length; i++){
			var o = ctor(rows[i]);
			if(fnMod){
				fnMod(o, rows[i]);	//	apply any modifiers.
			}
			arr.push(o);
		}
		return arr;	//	array
	},
	onSetData:function(){ },
	onClearData:function(){ },
	onAddData:function(obj){ },
	onAddDataRange:function(arr){ },
	onRemoveData:function(obj){ },
	onUpdateField:function(obj, field, val){ }
});

__CPAN_FILE__ src/collections/Queue.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Queue");
dojo.require("dojo.collections.Collections");

dojo.collections.Queue=function(/* array? */arr){
	//	summary
	//	return an object of type dojo.collections.Queue
	var q=[];
	if (arr){
		q=q.concat(arr);
	}
	this.count=q.length;
	this.clear=function(){
		//	summary
		//	clears the internal collection
		q=[];
		this.count=q.length;
	};
	this.clone=function(){
		//	summary
		//	creates a new Queue based on this one
		return new dojo.collections.Queue(q);	//	dojo.collections.Queue
	};
	this.contains=function(/* object */ o){
		//	summary
		//	Check to see if the passed object is an element in this queue
		for(var i=0; i<q.length; i++){
			if (q[i]==o){
				return true;	//	bool
			}
		}
		return false;	//	bool
	};
	this.copyTo=function(/* array */ arr, /* int */ i){
		//	summary
		//	Copy the contents of this queue into the passed array at index i.
		arr.splice(i,0,q);
	};
	this.dequeue=function(){
		//	summary
		//	shift the first element off the queue and return it
		var r=q.shift();
		this.count=q.length;
		return r;	//	object
	};
	this.enqueue=function(/* object */ o){
		//	summary
		//	put the passed object at the end of the queue
		this.count=q.push(o);
	};
	this.forEach=function(/* function */ fn, /* object? */ scope){
		//	summary
		//	functional iterator, following the mozilla spec.
		var s=scope||dj_global;
		if(Array.forEach){
			Array.forEach(q, fn, s);
		}else{
			for(var i=0; i<q.length; i++){
				fn.call(s, q[i], i, q);
			}
		}
	};
	this.getIterator=function(){
		//	summary
		//	get an Iterator based on this queue.
		return new dojo.collections.Iterator(q);	//	dojo.collections.Iterator
	};
	this.peek=function(){
		//	summary
		//	get the next element in the queue without altering the queue.
		return q[0];
	};
	this.toArray=function(){
		//	summary
		//	return an array based on the internal array of the queue.
		return [].concat(q);
	};
};

__CPAN_FILE__ src/collections/Stack.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Stack");
dojo.require("dojo.collections.Collections");

dojo.collections.Stack=function(/* array? */arr){
	//	summary
	//	returns an object of type dojo.collections.Stack
	var q=[];
	if (arr) q=q.concat(arr);
	this.count=q.length;
	this.clear=function(){
		//	summary
		//	Clear the internal array and reset the count
		q=[];
		this.count=q.length;
	};
	this.clone=function(){
		//	summary
		//	Create and return a clone of this Stack
		return new dojo.collections.Stack(q);
	};
	this.contains=function(/* object */o){
		//	summary
		//	check to see if the stack contains object o
		for (var i=0; i<q.length; i++){
			if (q[i] == o){
				return true;	//	bool
			}
		}
		return false;	//	bool
	};
	this.copyTo=function(/* array */ arr, /* int */ i){
		//	summary
		//	copy the stack into array arr at index i
		arr.splice(i,0,q);
	};
	this.forEach=function(/* function */ fn, /* object? */ scope){
		//	summary
		//	functional iterator, following the mozilla spec.
		var s=scope||dj_global;
		if(Array.forEach){
			Array.forEach(q, fn, s);
		}else{
			for(var i=0; i<q.length; i++){
				fn.call(s, q[i], i, q);
			}
		}
	};
	this.getIterator=function(){
		//	summary
		//	get an iterator for this collection
		return new dojo.collections.Iterator(q);	//	dojo.collections.Iterator
	};
	this.peek=function(){
		//	summary
		//	Return the next item without altering the stack itself.
		return q[(q.length-1)];	//	object
	};
	this.pop=function(){
		//	summary
		//	pop and return the next item on the stack
		var r=q.pop();
		this.count=q.length;
		return r;	//	object
	};
	this.push=function(/* object */ o){
		//	summary
		//	Push object o onto the stack
		this.count=q.push(o);
	};
	this.toArray=function(){
		//	summary
		//	create and return an array based on the internal collection
		return [].concat(q);	//	array
	};
}

__CPAN_FILE__ src/collections/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.collections.Collections",
		"dojo.collections.SortedList", 
		"dojo.collections.Dictionary", 
		"dojo.collections.Queue", 
		"dojo.collections.ArrayList", 
		"dojo.collections.Stack",
		"dojo.collections.Set"
	]
});
dojo.provide("dojo.collections.*");

__CPAN_FILE__ src/collections/Dictionary.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Dictionary");
dojo.require("dojo.collections.Collections");

dojo.collections.Dictionary=function(/* dojo.collections.Dictionary? */dictionary){
	//	summary
	//	Returns an object of type dojo.collections.Dictionary
	var items={};
	this.count=0;

	//	comparator for property addition and access.
	var testObject={};

	this.add=function(/* string */k, /* object */v){
		//	summary
		//	Add a new item to the Dictionary.
		var b=(k in items);
		items[k]=new dojo.collections.DictionaryEntry(k,v);
		if(!b){
			this.count++;
		}
	};
	this.clear=function(){
		//	summary
		//	Clears the internal dictionary.
		items={};
		this.count=0;
	};
	this.clone=function(){
		//	summary
		//	Returns a new instance of dojo.collections.Dictionary; note the the dictionary is a clone but items might not be.
		return new dojo.collections.Dictionary(this);	//	dojo.collections.Dictionary
	};
	this.contains=this.containsKey=function(/* string */k){
		//	summary
		//	Check to see if the dictionary has an entry at key "k".
		if(testObject[k]){
			return false;			// bool
		}
		return (items[k]!=null);	//	bool
	};
	this.containsValue=function(/* object */v){
		//	summary
		//	Check to see if the dictionary has an entry with value "v".
		var e=this.getIterator();
		while(e.get()){
			if(e.element.value==v){
				return true;	//	bool
			}
		}
		return false;	//	bool
	};
	this.entry=function(/* string */k){
		//	summary
		//	Accessor method; similar to dojo.collections.Dictionary.item but returns the actual Entry object.
		return items[k];	//	dojo.collections.DictionaryEntry
	};
	this.forEach=function(/* function */ fn, /* object? */ scope){
		//	summary
		//	functional iterator, following the mozilla spec.
		var a=[];	//	Create an indexing array
		for(var p in items) {
			if(!testObject[p]){
				a.push(items[p]);	//	fill it up
			}
		}
		var s=scope||dj_global;
		if(Array.forEach){
			Array.forEach(a, fn, s);
		}else{
			for(var i=0; i<a.length; i++){
				fn.call(s, a[i], i, a);
			}
		}
	};
	this.getKeyList=function(){
		//	summary
		//	Returns an array of the keys in the dictionary.
		return (this.getIterator()).map(function(entry){ 
			return entry.key; 
		});	//	array
	};
	this.getValueList=function(){
		//	summary
		//	Returns an array of the values in the dictionary.
		return (this.getIterator()).map(function(entry){ 
			return entry.value; 
		});	//	array
	};
	this.item=function(/* string */k){
		//	summary
		//	Accessor method.
		if(k in items){
			return items[k].valueOf();	//	object
		}
		return undefined;	//	object
	};
	this.getIterator=function(){
		//	summary
		//	Gets a dojo.collections.DictionaryIterator for iteration purposes.
		return new dojo.collections.DictionaryIterator(items);	//	dojo.collections.DictionaryIterator
	};
	this.remove=function(/* string */k){
		//	summary
		//	Removes the item at k from the internal collection.
		if(k in items && !testObject[k]){
			delete items[k];
			this.count--;
			return true;	//	bool
		}
		return false;	//	bool
	};

	if (dictionary){
		var e=dictionary.getIterator();
		while(e.get()) {
			 this.add(e.element.key, e.element.value);
		}
	}
};

__CPAN_FILE__ src/collections/SortedList.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.SortedList");
dojo.require("dojo.collections.Collections");

dojo.collections.SortedList=function(/* object? */ dictionary){
	//	summary
	//	creates a collection that acts like a dictionary but is also internally sorted.
	//	Note that the act of adding any elements forces an internal resort, making this object potentially slow.
	var _this=this;
	var items={};
	var q=[];
	var sorter=function(a,b){
		if (a.key > b.key) return 1;
		if (a.key < b.key) return -1;
		return 0;
	};
	var build=function(){
		q=[];
		var e=_this.getIterator();
		while (!e.atEnd()){
			q.push(e.get());
		}
		q.sort(sorter);
	};
	var testObject={};

	this.count=q.length;
	this.add=function(/* string */ k,/* object */v){
		//	summary
		//	add the passed value to the dictionary at location k
		if (!items[k]) {
			items[k]=new dojo.collections.DictionaryEntry(k,v);
			this.count=q.push(items[k]);
			q.sort(sorter);
		}
	};
	this.clear=function(){
		//	summary
		//	clear the internal collections
		items={};
		q=[];
		this.count=q.length;
	};
	this.clone=function(){
		//	summary
		//	create a clone of this sorted list
		return new dojo.collections.SortedList(this);	//	dojo.collections.SortedList
	};
	this.contains=this.containsKey=function(/* string */ k){
		//	summary
		//	Check to see if the list has a location k
		if(testObject[k]){
			return false;			//	bool
		}
		return (items[k]!=null);	//	bool
	};
	this.containsValue=function(/* object */ o){
		//	summary
		//	Check to see if this list contains the passed object
		var e=this.getIterator();
		while (!e.atEnd()){
			var item=e.get();
			if(item.value==o){ 
				return true;	//	bool
			}
		}
		return false;	//	bool
	};
	this.copyTo=function(/* array */ arr, /* int */ i){
		//	summary
		//	copy the contents of the list into array arr at index i
		var e=this.getIterator();
		var idx=i;
		while(!e.atEnd()){
			arr.splice(idx,0,e.get());
			idx++;
		}
	};
	this.entry=function(/* string */ k){
		//	summary
		//	return the object at location k
		return items[k];	//	dojo.collections.DictionaryEntry
	};
	this.forEach=function(/* function */ fn, /* object? */ scope){
		//	summary
		//	functional iterator, following the mozilla spec.
		var s=scope||dj_global;
		if(Array.forEach){
			Array.forEach(q, fn, s);
		}else{
			for(var i=0; i<q.length; i++){
				fn.call(s, q[i], i, q);
			}
		}
	};
	this.getByIndex=function(/* int */ i){
		//	summary
		//	return the item at index i
		return q[i].valueOf();	//	object
	};
	this.getIterator=function(){
		//	summary
		//	get an iterator for this object
		return new dojo.collections.DictionaryIterator(items);	//	dojo.collections.DictionaryIterator
	};
	this.getKey=function(/* int */ i){
		//	summary
		//	return the key of the item at index i
		return q[i].key;
	};
	this.getKeyList=function(){
		//	summary
		//	return an array of the keys set in this list
		var arr=[];
		var e=this.getIterator();
		while (!e.atEnd()){
			arr.push(e.get().key);
		}
		return arr;	//	array
	};
	this.getValueList=function(){
		//	summary
		//	return an array of values in this list
		var arr=[];
		var e=this.getIterator();
		while (!e.atEnd()){
			arr.push(e.get().value);
		}
		return arr;	//	array
	};
	this.indexOfKey=function(/* string */ k){
		//	summary
		//	return the index of the passed key.
		for (var i=0; i<q.length; i++){
			if (q[i].key==k){
				return i;	//	int
			}
		}
		return -1;	//	int
	};
	this.indexOfValue=function(/* object */ o){
		//	summary
		//	return the first index of object o
		for (var i=0; i<q.length; i++){
			if (q[i].value==o){
				return i;	//	int
			}
		}
		return -1;	//	int
	};
	this.item=function(/* string */ k){
		// 	summary
		//	return the value of the object at location k.
		if(k in items && !testObject[k]){
			return items[k].valueOf();	//	object
		}
		return undefined;	//	object
	};
	this.remove=function(/* string */k){
		// 	summary
		//	remove the item at location k and rebuild the internal collections.
		delete items[k];
		build();
		this.count=q.length;
	};
	this.removeAt=function(/* int */ i){
		//	summary
		//	remove the item at index i, and rebuild the internal collections.
		delete items[q[i].key];
		build();
		this.count=q.length;
	};
	this.replace=function(/* string */ k, /* object */ v){
		//	summary
		//	Replace an existing item if it's there, and add a new one if not.
		if (!items[k]){
			//	we're adding a new object, return false
			this.add(k,v);
			return false; // bool
		}else{
			//	we're replacing an object, return true
			items[k]=new dojo.collections.DictionaryEntry(k,v);
			q.sort(sorter);
			return true; // bool
		}
	};
	this.setByIndex=function(/* int */ i, /* object */ o){
		//	summary
		//	set an item by index
		items[q[i].key].value=o;
		build();
		this.count=q.length;
	};
	if (dictionary){
		var e=dictionary.getIterator();
		while (!e.atEnd()){
			var item=e.get();
			q[q.length]=items[item.key]=new dojo.collections.DictionaryEntry(item.key,item.value);
		}
		q.sort(sorter);
	}
}

__CPAN_FILE__ src/collections/Graph.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.Graph");
dojo.require("dojo.collections.Collections");

dojo.experimental("dojo.collections.Graph");

dojo.collections.Graph=function(nodes){
	function node(key, data, neighbors) {
		this.key=key;
		this.data=data;
		this.neighbors=neighbors||new adjacencyList();
		this.addDirected=function(){
			if (arguments[0].constructor==edgeToNeighbor){
				this.neighbors.add(arguments[0]);
			}else{
				var n=arguments[0];
				var cost=arguments[1]||0;
				this.neighbors.add(new edgeToNeighbor(n, cost));
			}
		}
	}
	function nodeList(){
		var d=new dojo.collections.Dictionary();
		function nodelistiterator(){
			var o=[] ;	//	Create an indexing array
			var e=d.getIterator();
			while(e.get()){
				o[o.length]=e.element;
			}

			var position=0;
			this.element=o[position]||null;
			this.atEnd=function(){
				return (position>=o.length);
			}
			this.get=function(){
				if(this.atEnd()){
					return null;		//	object
				}
				this.element=o[position++];
				return this.element;	//	object
			};
			this.map=function(/* function */fn, /* object? */scope){
				var s=scope||dj_global;
				if(Array.map){
					return Array.map(o,fn,s);	//	array
				}else{
					var arr=[];
					for(var i=0; i<o.length; i++){
						arr.push(fn.call(s,o[i]));
					}
					return arr;		//	array
				}
			};
			this.reset=function(){
				position=0;
				this.element=o[position];
			};
		}
		
		this.add=function(node){
			d.add(node.key, node);
		};
		this.clear=function(){
			d.clear();
		};
		this.containsKey=function(key){
			return d.containsKey(key);
		};
		this.getIterator=function(){
			return new nodelistiterator(this);
		};
		this.item=function(key){
			return d.item(key);
		};
		this.remove=function(node){
			d.remove(node.key);
		};
	}
	function edgeToNeighbor(node, cost){
		this.neighbor=node;
		this.cost=cost;
	}
	function adjacencyList(){
		var d=[];
		this.add=function(o){
			d.push(o);
		};
		this.item=function(i){
			return d[i];
		};
		this.getIterator=function(){
			return new dojo.collections.Iterator([].concat(d));
		};
	}

	this.nodes=nodes||new nodeList();
	this.count=this.nodes.count;
	this.clear=function(){
		this.nodes.clear();
		this.count=0;
	};
	this.addNode=function(){
		var n=arguments[0];
		if(arguments.length > 1){
			n=new node(arguments[0],arguments[1]);
		}
		if(!this.nodes.containsKey(n.key)){
			this.nodes.add(n);
			this.count++;
		}
	};
	this.addDirectedEdge=function(uKey, vKey, cost){
		var uNode,vNode;
		if(uKey.constructor!= node){
			uNode=this.nodes.item(uKey);
			vNode=this.nodes.item(vKey);
		}else{
			uNode=uKey;
			vNode=vKey;
		}
		var c=cost||0;
		uNode.addDirected(vNode,c);
	};
	this.addUndirectedEdge=function(uKey, vKey, cost){
		var uNode, vNode;
		if(uKey.constructor!=node){
			uNode=this.nodes.item(uKey);
			vNode=this.nodes.item(vKey);
		}else{
			uNode=uKey;
			vNode=vKey;
		}
		var c=cost||0;
		uNode.addDirected(vNode,c);
		vNode.addDirected(uNode,c);
	};
	this.contains=function(n){
		return this.nodes.containsKey(n.key);
	};
	this.containsKey=function(k){
		return this.nodes.containsKey(k);
	};
}

__CPAN_FILE__ src/collections/SkipList.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.SkipList");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.experimental");

dojo.experimental("dojo.collections.SkipList");

dojo.collections.SkipList = function(){
	function node(height, val){
		this.value = val;
		this.height = height;
		this.nodes = new nodeList(height);
		this.compare = function(val){
			if (this.value > val) return 1;
			if (this.value < val) return -1;
			return 0;
		}
		this.incrementHeight = function(){
			this.nodes.incrementHeight();
			this.height++;
		};
		this.decrementHeight = function(){
			this.nodes.decrementHeight();
			this.height--;
		};
	}
	function nodeList(height){
		var arr = [];
		this.height = height;
		for (var i = 0; i < height; i++) arr[i] = null;
		this.item = function(i){
			return arr[i];
		};
		this.incrementHeight = function(){
			this.height++;
			arr[this.height] = null;
		};
		this.decrementHeight = function(){
			arr.splice(arr.length - 1, 1);
			this.height--;
		};
	}
	function iterator(list){
		this.element = list.head;
		this.atEnd = function(){
			return (this.element==null);
		}
		this.get = function(){
			if(this.atEnd()){
				return null;
			}
			this.element=this.element.nodes[0];
			return this.element;
		}
		this.reset = function(){
			this.element = list.head;
		}
	}

	function chooseRandomHeight(max){
		var level = 1;
		while (Math.random() < PROB && level < max) level++;
		return level;
	}

	var PROB = 0.5;
	var comparisons = 0;

	this.head = new node(1);
	this.count = 0;
	this.add = function(val){
		var updates = [];
		var current = this.head;
		for (var i = this.head.height; i >= 0; i--){
			if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) comparisons++;
			while (current.nodes[i] != null && current.nodes[i].compare(val) < 0){
				current = current.nodes[i];
				comparisons++;
			}
			updates[i] = current;
		}
		if (current.nodes[0] != null && current.nodes[0].compare(val) == 0) return;
		var n = new node(val, chooseRandomHeight(this.head.height + 1));
		this.count++;
		if (n.height > this.head.height){
			this.head.incrementHeight();
			this.head.nodes[this.head.height - 1] = n;
		}
		for (i = 0; i < n.height; i++){
			if (i < updates.length) {
				n.nodes[i] = updates[i].nodes[i];
				updates[i].nodes[i] = n;
			}
		}
	};
	
	this.contains = function(val){
		var current = this.head;
		var i;
		for (i = this.head.height - 1; i >= 0; i--) {
			while (current.item(i) != null) {
				comparisons++;
				var result = current.nodes[i].compare(val);
				if (result == 0) return true;
				else if (result < 0) current = current.nodes[i];
				else break;
			}
		}
		return false;
	};
	this.getIterator = function(){
		return new iterator(this);
	};

	this.remove = function(val){
		var updates = [];
		var current = this.head;
		for (var i = this.head.height - 1; i >= 0; i--){
			if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) comparisons++;
			while (current.nodes[i] != null && current.nodes[i].compare(val) < 0) {
				current = current.nodes[i];
				comparisons++;
			}
			updates[i] = current;
		}
		
		current = current.nodes[0];
		if (current != null && current.compare(val) == 0){
			this.count--;
			for (var i = 0; i < this.head.height; i++){
				if (updates[i].nodes[i] != current) break;
				else updates[i].nodes[i] = current.nodes[i];
			}
			if (this.head.nodes[this.head.height - 1] == null) this.head.decrementHeight();
		}
	};
	this.resetComparisons = function(){ 
		comparisons = 0; 
	};
}

__CPAN_FILE__ src/collections/BinaryTree.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.BinaryTree");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.experimental");

dojo.experimental("dojo.collections.BinaryTree");

dojo.collections.BinaryTree=function(data){
	function node(data, rnode, lnode){
		this.value=data||null;
		this.right=rnode||null;
		this.left=lnode||null;
		this.clone=function(){
			var c=new node();
			if (this.value.value) c.value=this.value.clone();
			else c.value=this.value;
			if (this.left) c.left=this.left.clone();
			if (this.right) c.right=this.right.clone();
		}
		this.compare=function(n){
			if (this.value > n.value) return 1;
			if (this.value < n.value) return -1;
			return 0;
		}
		this.compareData=function(d){
			if (this.value > d) return 1;
			if (this.value < d) return -1;
			return 0;
		}
	}

	function inorderTraversalBuildup(current, a){
		if (current){
			inorderTraversalBuildup(current.left, a);
			a.add(current);
			inorderTraversalBuildup(current.right, a);
		}
	}

	function preorderTraversal(current, sep){
		var s="";
		if (current){
			s=current.value.toString() + sep;
			s += preorderTraversal(current.left, sep);
			s += preorderTraversal(current.right, sep);
		}
		return s;
	}
	function inorderTraversal(current, sep){
		var s="";
		if (current){
			s=inorderTraversal(current.left, sep);
			s += current.value.toString() + sep;
			s += inorderTraversal(current.right, sep);
		}
		return s;
	}
	function postorderTraversal(current, sep){
		var s="";
		if (current){
			s=postorderTraversal(current.left, sep);
			s += postorderTraversal(current.right, sep);
			s += current.value.toString() + sep;
		}
		return s;
	}
	
	function searchHelper(current, data){
		if (!current) return null;
		var i=current.compareData(data);
		if (i==0) return current;
		if (i>0) return searchHelper(current.left, data);
		else return searchHelper(current.right, data);
	}

	this.add=function(data){
		var n=new node(data);
		var i;
		var current=root;
		var parent=null;
		while (current){
			i=current.compare(n);
			if (i == 0) return;
			parent=current;
			if (i > 0) current=current.left;
			else current=current.right;
		}
		this.count++;
		if (!parent) root=n;
		else {
			i=parent.compare(n);
			if (i > 0) parent.left=n;
			else parent.right=n;
		}
	};
	this.clear=function(){
		root=null;
		this.count=0;
	};
	this.clone=function(){
		var c=new dojo.collections.BinaryTree();
		c.root=root.clone();
		c.count=this.count;
		return c;
	};
	this.contains=function(data){
		return this.search(data) != null;
	};
	this.deleteData=function(data){
		var current=root;
		var parent=null;
		var i=current.compareData(data);
		while (i != 0 && current != null){
			if (i > 0){
				parent=current;
				current=current.left;
			} else if (i < 0) {
				parent=current;
				current=current.right;
			}
			i=current.compareData(data);
		}
		if (!current) return;
		this.count--;
		if (!current.right) {
			if (!parent) root=current.left;
			else {
				i=parent.compare(current);
				if (i > 0) parent.left=current.left;
				else if (i < 0) parent.right=current.left;
			}
		} else if (!current.right.left){
			if (!parent) root=current.right;
			else {
				i=parent.compare(current);
				if (i > 0) parent.left=current.right;
				else if (i < 0) parent.right=current.right;
			}
		} else {
			var leftmost=current.right.left;
			var lmParent=current.right;
			while (leftmost.left != null){
				lmParent=leftmost;
				leftmost=leftmost.left;
			}
			lmParent.left=leftmost.right;
			leftmost.left=current.left;
			leftmost.right=current.right;
			if (!parent) root=leftmost;
			else {
				i=parent.compare(current);
				if (i > 0) parent.left=leftmost;
				else if (i < 0) parent.right=leftmost;
			}
		}
	};
	this.getIterator=function(){
		var a=[];
		inorderTraversalBuildup(root, a);
		return new dojo.collections.Iterator(a);
	};
	this.search=function(data){
		return searchHelper(root, data);
	};
	this.toString=function(order, sep){
		if (!order) var order=dojo.collections.BinaryTree.TraversalMethods.Inorder;
		if (!sep) var sep=" ";
		var s="";
		switch (order){
			case dojo.collections.BinaryTree.TraversalMethods.Preorder:
				s=preorderTraversal(root, sep);
				break;
			case dojo.collections.BinaryTree.TraversalMethods.Inorder:
				s=inorderTraversal(root, sep);
				break;
			case dojo.collections.BinaryTree.TraversalMethods.Postorder:
				s=postorderTraversal(root, sep);
				break;
		};
		if (s.length == 0) return "";
		else return s.substring(0, s.length - sep.length);
	};

	this.count=0;
	var root=this.root=null;
	if (data) {
		this.add(data);
	}
}
dojo.collections.BinaryTree.TraversalMethods={
	Preorder : 1,
	Inorder : 2,
	Postorder : 3
};

__CPAN_FILE__ src/collections/ArrayList.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.ArrayList");
dojo.require("dojo.collections.Collections");

dojo.collections.ArrayList=function(/* array? */arr){
	//	summary
	//	Returns a new object of type dojo.collections.ArrayList
	var items=[];
	if(arr) items=items.concat(arr);
	this.count=items.length;
	this.add=function(/* object */obj){
		//	summary
		//	Add an element to the collection.
		items.push(obj);
		this.count=items.length;
	};
	this.addRange=function(/* array */a){
		//	summary
		//	Add a range of objects to the ArrayList
		if(a.getIterator){
			var e=a.getIterator();
			while(!e.atEnd()){
				this.add(e.get());
			}
			this.count=items.length;
		}else{
			for(var i=0; i<a.length; i++){
				items.push(a[i]);
			}
			this.count=items.length;
		}
	};
	this.clear=function(){
		//	summary
		//	Clear all elements out of the collection, and reset the count.
		items.splice(0, items.length);
		this.count=0;
	};
	this.clone=function(){
		//	summary
		//	Clone the array list
		return new dojo.collections.ArrayList(items);	//	dojo.collections.ArrayList
	};
	this.contains=function(/* object */obj){
		//	summary
		//	Check to see if the passed object is a member in the ArrayList
		for(var i=0; i < items.length; i++){
			if(items[i] == obj) {
				return true;	//	bool
			}
		}
		return false;	//	bool
	};
	this.forEach=function(/* function */ fn, /* object? */ scope){
		//	summary
		//	functional iterator, following the mozilla spec.
		var s=scope||dj_global;
		if(Array.forEach){
			Array.forEach(items, fn, s);
		}else{
			for(var i=0; i<items.length; i++){
				fn.call(s, items[i], i, items);
			}
		}
	};
	this.getIterator=function(){
		//	summary
		//	Get an Iterator for this object
		return new dojo.collections.Iterator(items);	//	dojo.collections.Iterator
	};
	this.indexOf=function(/* object */obj){
		//	summary
		//	Return the numeric index of the passed object; will return -1 if not found.
		for(var i=0; i < items.length; i++){
			if(items[i] == obj) {
				return i;	//	int
			}
		}
		return -1;	// int
	};
	this.insert=function(/* int */ i, /* object */ obj){
		//	summary
		//	Insert the passed object at index i
		items.splice(i,0,obj);
		this.count=items.length;
	};
	this.item=function(/* int */ i){
		//	summary
		//	return the element at index i
		return items[i];	//	object
	};
	this.remove=function(/* object */obj){
		//	summary
		//	Look for the passed object, and if found, remove it from the internal array.
		var i=this.indexOf(obj);
		if(i >=0) {
			items.splice(i,1);
		}
		this.count=items.length;
	};
	this.removeAt=function(/* int */ i){
		//	summary
		//	return an array with function applied to all elements
		items.splice(i,1);
		this.count=items.length;
	};
	this.reverse=function(){
		//	summary
		//	Reverse the internal array
		items.reverse();
	};
	this.sort=function(/* function? */ fn){
		//	summary
		//	sort the internal array
		if(fn){
			items.sort(fn);
		}else{
			items.sort();
		}
	};
	this.setByIndex=function(/* int */ i, /* object */ obj){
		//	summary
		//	Set an element in the array by the passed index.
		items[i]=obj;
		this.count=items.length;
	};
	this.toArray=function(){
		//	summary
		//	Return a new array with all of the items of the internal array concatenated.
		return [].concat(items);
	}
	this.toString=function(/* string */ delim){
		//	summary
		//	implementation of toString, follows [].toString();
		return items.join((delim||","));
	};
};

__CPAN_DIR__ src/xml
__CPAN_FILE__ src/xml/svgUtil.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.xml.svgUtil");
// FIXME: add imports for deps!

dojo.xml.svgUtil = new function(){

	this.getInnerWidth = function(node){
		// FIXME: need to find out from dylan how to 
	}

	this.getOuterWidth = function(node){
		
	}

	this.getInnerHeight = function(node){
		
	}

	this.getOuterHeight = function(node){
		
	}

}

__CPAN_FILE__ src/xml/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.xml.Parse");
dojo.kwCompoundRequire({
	common:		["dojo.dom"],
    browser: 	["dojo.html.*"],
    dashboard: 	["dojo.html.*"],
    svg: 		["dojo.xml.svgUtil"]
});
dojo.provide("dojo.xml.*");

__CPAN_FILE__ src/xml/XslTransform.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.xml.XslTransform");

dojo.xml.XslTransform = function(/*String*/ xsltUri) {
	//	summary:
	//	dojo.xml.XslTransform is a convenience object that takes the URI String 
	//		of an XSL file as a constructor argument.
	//	After each transformation all parameters will be cleared.

	//	Note this is supported by IE and Mozilla ONLY.

	dojo.debug("XslTransform is supported by Internet Explorer and Mozilla, with limited support in Opera 9 (no document function support).");
	var IS_IE = window.ActiveXObject ? true : false;
	var ACTIVEX_DOMS = [
		"Msxml2.DOMDocument.5.0", 
		"Msxml2.DOMDocument.4.0", 
		"Msxml2.DOMDocument.3.0", 
		"MSXML2.DOMDocument", 
		"MSXML.DOMDocument", 
		"Microsoft.XMLDOM"
	];
	var ACTIVEX_FT_DOMS = [
		"Msxml2.FreeThreadedDOMDocument.5.0", 
		"MSXML2.FreeThreadedDOMDocument.4.0", 
		"MSXML2.FreeThreadedDOMDocument.3.0"
	];
	var ACTIVEX_TEMPLATES = [
		"Msxml2.XSLTemplate.5.0", 
		"Msxml2.XSLTemplate.4.0", 
		"MSXML2.XSLTemplate.3.0"
	];
  
	function getActiveXImpl(activeXArray) {
		for (var i=0; i < activeXArray.length; i++) {
			try {
				var testObj = new ActiveXObject(activeXArray[i]);
				if (testObj) {
					return activeXArray[i];
				}
			} catch (e) {}
		}
		dojo.raise("Could not find an ActiveX implementation in:\n\n " + activeXArray);
	}
    
    if (xsltUri == null || xsltUri == undefined) {
        dojo.raise("You must pass the URI String for the XSL file to be used!");
        return false;
    }
    
    var xsltDocument = null;
    var xsltProcessor = null;
    if (IS_IE) {
        xsltDocument = new ActiveXObject(getActiveXImpl(ACTIVEX_FT_DOMS));
        xsltDocument.async = false;
    } else {
        xsltProcessor = new XSLTProcessor();
        xsltDocument = document.implementation.createDocument("", "", null);
        xsltDocument.addEventListener("load", onXslLoad, false);
    }
    xsltDocument.load(xsltUri);
    
    if (IS_IE) {
        var xslt = new ActiveXObject(getActiveXImpl(ACTIVEX_TEMPLATES));
        xslt.stylesheet = xsltDocument;  
        xsltProcessor = xslt.createProcessor();
    }
      
    function onXslLoad() {
        xsltProcessor.importStylesheet(xsltDocument); 
    }
  
    function getResultDom(xmlDoc, params) {
      if (IS_IE) {
          addIeParams(params);
          var result = getIeResultDom(xmlDoc);
          removeIeParams(params);   
          return result;
      } else {
          return getMozillaResultDom(xmlDoc, params);
      }
    }
    
    function addIeParams(params) {
        if (params != null) {
          for (var i=0; i<params.length; i++) 
              xsltProcessor.addParameter(params[i][0], params[i][1]);
        }
    }
    
    function removeIeParams(params) {
        if (params != null) {
            for (var i=0; i<params.length; i++) 
                xsltProcessor.addParameter(params[i][0], "");
        }
    }
    
    function getIeResultDom(xmlDoc) {
        xsltProcessor.input = xmlDoc;
        var outDoc = new ActiveXObject(getActiveXImpl(ACTIVEX_DOMS));
        outDoc.async = false;  
        outDoc.validateOnParse = false;
        xsltProcessor.output = outDoc;
        xsltProcessor.transform();
        if (outDoc.parseError.errorCode != 0) {
            var err = outDoc.parseError;
			dojo.raise("err.errorCode: " + err.errorCode + "\n\nerr.reason: " + err.reason + "\n\nerr.url: " + err.url + "\n\nerr.srcText: " + err.srcText);
        }
        return outDoc;
    }
    
    function getIeResultStr(xmlDoc, params) {
        xsltProcessor.input = xmlDoc;
        xsltProcessor.transform();    
        return xsltProcessor.output;
    }
    
    function addMozillaParams(params) {
        if (params != null) {
            for (var i=0; i<params.length; i++) 
                xsltProcessor.setParameter(null, params[i][0], params[i][1]);
        }
    }
    
    function getMozillaResultDom(xmlDoc, params) {
        addMozillaParams(params);
        var resultDoc = xsltProcessor.transformToDocument(xmlDoc);
        xsltProcessor.clearParameters();
        return resultDoc;
    }
    
    function getMozillaResultStr(xmlDoc, params, parentDoc) {
        addMozillaParams(params);
        var resultDoc = xsltProcessor.transformToFragment(xmlDoc, parentDoc);
        var serializer = new XMLSerializer();
        xsltProcessor.clearParameters();
        return serializer.serializeToString(resultDoc);
    }
  
    this.getResultString = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*HTMLDocument*/parentDoc) {
        var content = null;
        if (IS_IE) {
            addIeParams(params);
            content = getIeResultStr(xmlDoc, params);
            removeIeParams(params);  
        } else {
            content = getMozillaResultStr(xmlDoc, params, parentDoc);
        } 
        //dojo.debug(content);
        return content;
    };
  
    this.transformToContentPane = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*ContentPane*/contentPane, /*HTMLDocument*/parentDoc) {
        var content = this.getResultString(xmlDoc, params, parentDoc);
        contentPane.setContent(content);
    };
      
    this.transformToRegion = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*HTMLElement*/region, /*HTMLDocument*/parentDoc) {
        try {
            var content = this.getResultString(xmlDoc, params, parentDoc);
            region.innerHTML = content;
        } catch (e) {
            dojo.raise(e.message + "\n\n xsltUri: " + xsltUri)
        }
    };
  
    this.transformToDocument = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params) {
        return getResultDom(xmlDoc, params);
    }
  
    this.transformToWindow = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*HTMLDocument*/windowDoc, /*HTMLDocument*/parentDoc) {
        try {
            windowDoc.open();
            windowDoc.write(this.getResultString(xmlDoc, params, parentDoc));
            windowDoc.close();
        } catch (e) {
            dojo.raise(e.message + "\n\n xsltUri: " + xsltUri)
        }
    };
};

__CPAN_FILE__ src/xml/Parse.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.xml.Parse");
dojo.require("dojo.dom");

//TODO: determine dependencies
// currently has dependency on dojo.xml.DomUtil nodeTypes constants...

/* 
  generic class for taking a node and parsing it into an object
*/

// using documentFragment nomenclature to generalize in case we don't want to require passing a collection of nodes with a single parent

dojo.xml.Parse = function(){

	// supported dojoTagName's:
	// 
	// <prefix:tag> => prefix:tag
	// <dojo:tag> => dojo:tag
	// <dojoTag> => dojo:tag
	// <tag dojoType="type"> => dojo:type
	// <tag dojoType="prefix:type"> => prefix:type
	// <tag dojo:type="type"> => dojo:type
	// <tag class="classa dojo-type classb"> => dojo:type	

	// get normalized (lowercase) tagName
	// some browsers report tagNames in lowercase no matter what
	function getTagName(node){
		return ((node)&&(node.tagName) ? node.tagName.toLowerCase() : '');
	}

	// locate dojo qualified tag name
	function getDojoTagName(node){
		var tagName = getTagName(node);
		if (!tagName){
				return '';
		}
		// any registered tag
		if((dojo.widget)&&(dojo.widget.tags[tagName])){
			return tagName;
		}
		// <prefix:tag> => prefix:tag
		var p = tagName.indexOf(":");
		if(p>=0){
			return tagName;
		}
		// <dojo:tag> => dojo:tag
		if(tagName.substr(0,5) == "dojo:"){
			return tagName;
		}
		if(dojo.render.html.capable && dojo.render.html.ie && node.scopeName != 'HTML'){
			return node.scopeName.toLowerCase() + ':' + tagName;
		}
		// <dojoTag> => dojo:tag
		if(tagName.substr(0,4) == "dojo"){
			// FIXME: this assumes tag names are always lower case
			return "dojo:" + tagName.substring(4);
		}
		// <tag dojoType="prefix:type"> => prefix:type
		// <tag dojoType="type"> => dojo:type
		var djt = node.getAttribute("dojoType") || node.getAttribute("dojotype");
		if(djt){
			if (djt.indexOf(":")<0){
				djt = "dojo:"+djt;
			}
			return djt.toLowerCase();
		}
		// <tag dojo:type="type"> => dojo:type
		djt = node.getAttributeNS && node.getAttributeNS(dojo.dom.dojoml,"type");
		if(djt){
			return "dojo:" + djt.toLowerCase();
		}
		// <tag dojo:type="type"> => dojo:type
		try{
			// FIXME: IE really really doesn't like this, so we squelch errors for it
			djt = node.getAttribute("dojo:type");
		}catch(e){ 
			// FIXME: log?  
		}
		if(djt){ return "dojo:"+djt.toLowerCase(); }
		// <tag class="classa dojo-type classb"> => dojo:type	
		if((!dj_global["djConfig"])|| (djConfig["ignoreClassNames"])){ 
			// FIXME: should we make this optionally enabled via djConfig?
			var classes = node.className||node.getAttribute("class");
			// FIXME: following line, without check for existence of classes.indexOf
			// breaks firefox 1.5's svg widgets
			if((classes )&&(classes.indexOf)&&(classes.indexOf("dojo-")!=-1)){
		    var aclasses = classes.split(" ");
		    for(var x=0, c=aclasses.length; x<c; x++){
	        if(aclasses[x].slice(0, 5) == "dojo-"){
            return "dojo:"+aclasses[x].substr(5).toLowerCase(); 
					}
				}
			}
		}
		// no dojo-qualified name
		return '';
	}

	this.parseElement = function(node, hasParentNodeSet, optimizeForDojoML, thisIdx){

		var parsedNodeSet = {};
		
		var tagName = getTagName(node);
		//There's a weird bug in IE where it counts end tags, e.g. </dojo:button> as nodes that should be parsed.  Ignore these
		if((tagName)&&(tagName.indexOf("/")==0)){
			return null;
		}
		
		// look for a dojoml qualified name
		// process dojoml only when optimizeForDojoML is true
		var process = true;
		if(optimizeForDojoML){
			var dojoTagName = getDojoTagName(node);
			tagName = dojoTagName || tagName;
			process = Boolean(dojoTagName);
		}
		
		if(node && node.getAttribute && node.getAttribute("parseWidgets") && node.getAttribute("parseWidgets") == "false") {
			return {};
		}

		parsedNodeSet[tagName] = [];
		var pos = tagName.indexOf(":");
		if(pos>0){
			var ns = tagName.substring(0,pos);
			parsedNodeSet["ns"] = ns;
			// honor user namespace filters
			if((dojo.ns)&&(!dojo.ns.allow(ns))){process=false;}
		}

		if(process){
			var attributeSet = this.parseAttributes(node);
			for(var attr in attributeSet){
				if((!parsedNodeSet[tagName][attr])||(typeof parsedNodeSet[tagName][attr] != "array")){
					parsedNodeSet[tagName][attr] = [];
				}
				parsedNodeSet[tagName][attr].push(attributeSet[attr]);
			}	
			// FIXME: we might want to make this optional or provide cloning instead of
			// referencing, but for now, we include a node reference to allow
			// instantiated components to figure out their "roots"
			parsedNodeSet[tagName].nodeRef = node;
			parsedNodeSet.tagName = tagName;
			parsedNodeSet.index = thisIdx||0;
		}

		var count = 0;
		for(var i = 0; i < node.childNodes.length; i++){
			var tcn = node.childNodes.item(i);
			switch(tcn.nodeType){
				case  dojo.dom.ELEMENT_NODE: // element nodes, call this function recursively
					count++;
					var ctn = getDojoTagName(tcn) || getTagName(tcn);
					if(!parsedNodeSet[ctn]){
						parsedNodeSet[ctn] = [];
					}
					parsedNodeSet[ctn].push(this.parseElement(tcn, true, optimizeForDojoML, count));
					if(	(tcn.childNodes.length == 1)&&
						(tcn.childNodes.item(0).nodeType == dojo.dom.TEXT_NODE)){
						parsedNodeSet[ctn][parsedNodeSet[ctn].length-1].value = tcn.childNodes.item(0).nodeValue;
					}
					break;
				case  dojo.dom.TEXT_NODE: // if a single text node is the child, treat it as an attribute
					if(node.childNodes.length == 1){
						parsedNodeSet[tagName].push({ value: node.childNodes.item(0).nodeValue });
					}
					break;
				default: break;
				/*
				case  dojo.dom.ATTRIBUTE_NODE: // attribute node... not meaningful here
					break;
				case  dojo.dom.CDATA_SECTION_NODE: // cdata section... not sure if this would ever be meaningful... might be...
					break;
				case  dojo.dom.ENTITY_REFERENCE_NODE: // entity reference node... not meaningful here
					break;
				case  dojo.dom.ENTITY_NODE: // entity node... not sure if this would ever be meaningful
					break;
				case  dojo.dom.PROCESSING_INSTRUCTION_NODE: // processing instruction node... not meaningful here
					break;
				case  dojo.dom.COMMENT_NODE: // comment node... not not sure if this would ever be meaningful 
					break;
				case  dojo.dom.DOCUMENT_NODE: // document node... not sure if this would ever be meaningful
					break;
				case  dojo.dom.DOCUMENT_TYPE_NODE: // document type node... not meaningful here
					break;
				case  dojo.dom.DOCUMENT_FRAGMENT_NODE: // document fragment node... not meaningful here
					break;
				case  dojo.dom.NOTATION_NODE:// notation node... not meaningful here
					break;
				*/
			}
		}
		//return (hasParentNodeSet) ? parsedNodeSet[node.tagName] : parsedNodeSet;
		//if(parsedNodeSet.tagName)dojo.debug("parseElement: RETURNING NODE WITH TAGNAME "+parsedNodeSet.tagName);
		return parsedNodeSet;
	};

	/* parses a set of attributes on a node into an object tree */
	this.parseAttributes = function(node){
		var parsedAttributeSet = {};
		var atts = node.attributes;
		// TODO: should we allow for duplicate attributes at this point...
		// would any of the relevant dom implementations even allow this?
		var attnode, i=0;
		while((attnode=atts[i++])){
			if((dojo.render.html.capable)&&(dojo.render.html.ie)){
				if(!attnode){ continue; }
				if((typeof attnode == "object")&&
					(typeof attnode.nodeValue == 'undefined')||
					(attnode.nodeValue == null)||
					(attnode.nodeValue == '')){ 
					continue; 
				}
			}

			var nn = attnode.nodeName.split(":");
			nn = (nn.length == 2) ? nn[1] : attnode.nodeName;
						
			parsedAttributeSet[nn] = { 
				value: attnode.nodeValue 
			};
		}
		return parsedAttributeSet;
	};
};

__CPAN_DIR__ src/gfx
__CPAN_FILE__ src/gfx/matrix.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.matrix");

dojo.require("dojo.lang.common");
dojo.require("dojo.math.*");

dojo.gfx.matrix.Matrix2D = function(/* Matrix2D */ arg){
	// summary: a constructor for 2D matrix
	// arg: a matrix-like object
	if(arg){
		if(arg instanceof Array){
			if(arg.length > 0){
				var m = dojo.gfx.matrix.normalize(arg[0]);
				// combine matrices
				for(var i = 1; i < arg.length; ++i){
					var l = m;
					var r = dojo.gfx.matrix.normalize(arg[i]);
					m = new dojo.gfx.matrix.Matrix2D();
					m.xx = l.xx * r.xx + l.xy * r.yx;
					m.xy = l.xx * r.xy + l.xy * r.yy;
					m.yx = l.yx * r.xx + l.yy * r.yx;
					m.yy = l.yx * r.xy + l.yy * r.yy;
					m.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
					m.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
				}
				dojo.mixin(this, m);
			}
		}else{
			dojo.mixin(this, arg);
		}
	}
};

// the default (identity) matrix, which is used to fill in missing values
dojo.extend(dojo.gfx.matrix.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});

dojo.mixin(dojo.gfx.matrix, {
	// summary: class constants, and methods of dojo.gfx.matrix.Matrix2D
	
	// matrix constants
	identity: new dojo.gfx.matrix.Matrix2D(),
	flipX:    new dojo.gfx.matrix.Matrix2D({xx: -1}),
	flipY:    new dojo.gfx.matrix.Matrix2D({yy: -1}),
	flipXY:   new dojo.gfx.matrix.Matrix2D({xx: -1, yy: -1}),
	
	// matrix creators
	translate: function(/* Number||Point */ a, /* Number, optional */ b){
		// summary: forms a translation matrix
		// a: an X coordinate value (a number), or a point object
		// b: an optional Y coordinate value
		return arguments.length > 1 ? new dojo.gfx.matrix.Matrix2D({dx: a, dy: b}) : new dojo.gfx.matrix.Matrix2D({dx: a.x, dy: a.y}); // dojo.gfx.matrix.Matrix2D
	},
	scale: function(/* Number||Point */ a, /* Number||Nothing */ b){
		// summary: forms a scaling matrix
		// a: a scaling factor used for X, or a point object
		// b: an optional scaling factor for Y
		return arguments.length > 1 ? new dojo.gfx.matrix.Matrix2D({xx: a, yy: b}) : typeof a == "number" ? new dojo.gfx.matrix.Matrix2D({xx: a, yy: a}) : new dojo.gfx.matrix.Matrix2D({xx: a.x, yy: a.y}); // dojo.gfx.matrix.Matrix2D
	},
	rotate: function(/* Number */ angle){
		// summary: forms a rotating matrix
		// angle: an angle of rotation in radians (>0 for CCW)
		var c = Math.cos(angle);
		var s = Math.sin(angle);
		return new dojo.gfx.matrix.Matrix2D({xx: c, xy: s, yx: -s, yy: c}); // dojo.gfx.matrix.Matrix2D
	},
	rotateg: function(/* Number */ degree){
		// summary: forms a rotating matrix
		// degree: an angle of rotation in degrees (>0 for CCW)
		return dojo.gfx.matrix.rotate(dojo.math.degToRad(degree)); // dojo.gfx.matrix.Matrix2D
	},
	skewX: function(/* Number */ angle) {
		// summary: forms an X skewing matrix
		// angle: an skewing angle in radians
		return new dojo.gfx.matrix.Matrix2D({xy: Math.tan(angle)}); // dojo.gfx.matrix.Matrix2D
	},
	skewXg: function(/* Number */ degree){
		// summary: forms an X skewing matrix
		// degree: an skewing angle in degrees
		return dojo.gfx.matrix.skewX(dojo.math.degToRad(degree)); // dojo.gfx.matrix.Matrix2D
	},
	skewY: function(/* Number */ angle){
		// summary: forms a Y skewing matrix
		// angle: an skewing angle in radians
		return new dojo.gfx.matrix.Matrix2D({yx: -Math.tan(angle)}); // dojo.gfx.matrix.Matrix2D
	},
	skewYg: function(/* Number */ degree){
		// summary: forms a Y skewing matrix
		// degree: an skewing angle in degrees
		return dojo.gfx.matrix.skewY(dojo.math.degToRad(degree)); // dojo.gfx.matrix.Matrix2D
	},
	
	// ensure matrix 2D conformance
	normalize: function(/* Matrix2D */ matrix){
		// summary: converts an object to a matrix, if necessary
		// matrix: an object, which is converted to a matrix, if necessary
		return (matrix instanceof dojo.gfx.matrix.Matrix2D) ? matrix : new dojo.gfx.matrix.Matrix2D(matrix); // dojo.gfx.matrix.Matrix2D
	},
	
	// common operations
	clone: function(/* Matrix2D */ matrix){
		// summary: creates a copy of a matrix
		// matrix: a matrix object to be cloned
		var obj = new dojo.gfx.matrix.Matrix2D();
		for(var i in matrix){
			if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
		}
		return obj; // dojo.gfx.matrix.Matrix2D
	},
	invert: function(/* Matrix2D */ matrix){
		// summary: inverts a matrix
		// matrix: a matrix object to be inverted
		var m = dojo.gfx.matrix.normalize(matrix);
		var D = m.xx * m.yy - m.xy * m.yx;
		return new dojo.gfx.matrix.Matrix2D({xx: m.yy/D, xy: -m.xy/D, yx: -m.yx/D, yy: m.xx/D, dx: (m.yx * m.dy - m.yy * m.dx) / D, dy: (m.xy * m.dx - m.xx * m.dy) / D}); // dojo.gfx.matrix.Matrix2D
	},
	_multiplyPoint: function(/* Matrix2D */ m, /* Number */ x, /* Number */ y){
		// summary: applies a matrix to a point
		// matrix: a matrix object to be applied
		// a: an X coordinate of a point
		// b: a Y coordinate of a point
		return {x: m.xx * x + m.xy * y + m.dx, y: m.yx * x + m.yy * y + m.dy}; // Point
	},
	multiplyPoint: function(/* Matrix */ matrix, /* Number||Point */ a, /* Number, optional */ b){
		// summary: applies a matrix to a point
		// matrix: a matrix-like object to be applied
		// a: an X coordinate of a point, or a point object
		// b: an optional Y coordinate of a point
		var m = dojo.gfx.matrix.normalize(matrix);
		if(typeof a == "number" && typeof b == "number"){
			return dojo.gfx.matrix._multiplyPoint(m, a, b);
		}
		return dojo.gfx.matrix._multiplyPoint(m, a.x, a.y); // Point
	},
	multiply: function(/* Matrix */ matrix){
		// summary: combines matrices by multiplying them
		// matrix: a matrix-like object, all subsequent arguments are matrix-like objects too.
		var m = dojo.gfx.matrix.normalize(matrix);
		// combine matrices
		for(var i = 1; i < arguments.length; ++i){
			var l = m;
			var r = dojo.gfx.matrix.normalize(arguments[i]);
			m = new dojo.gfx.matrix.Matrix2D();
			m.xx = l.xx * r.xx + l.xy * r.yx;
			m.xy = l.xx * r.xy + l.xy * r.yy;
			m.yx = l.yx * r.xx + l.yy * r.yx;
			m.yy = l.yx * r.xy + l.yy * r.yy;
			m.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
			m.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
		}
		return m; // dojo.gfx.matrix.Matrix2D
	},
	
	// high level operations
	_sandwich: function(/* Matrix */ m, /* Number */ x, /* Number */ y){
		// summary: applies a matrix at a centrtal point
		// m: a matrix-like object, which is applied at the point
		// x: an X component of the point
		// y: a Y component of the point
		return dojo.gfx.matrix.multiply(dojo.gfx.matrix.translate(x, y), m, dojo.gfx.matrix.translate(-x, -y)); // dojo.gfx.matrix.Matrix2D
	},
	scaleAt: function(/* Number */ a, /* Number, optional */ b, /* Number||Point */ c, /* Number, optional */ d){
		// summary: scales a picture using a specified point as a center of scaling
		
		// accepts several signatures:
		//	1) uniform scale factor, Point
		//	2) uniform scale factor, x, y
		//	3) x scale, y scale, Point
		//	4) x scale, y scale, x, y
		switch(arguments.length){
			case 2:
				// a is a scale factor, b is a point
				return dojo.gfx.matrix._sandwich(dojo.gfx.matrix.scale(a), b.x, b.y); // dojo.gfx.matrix.Matrix2D
			case 3:
				if(typeof c == "number"){
					// a is scale factor, b and c are x and y components of a point
					return dojo.gfx.matrix._sandwich(dojo.gfx.matrix.scale(a), b, c); // dojo.gfx.matrix.Matrix2D
				}
				// a and b are scale factor components, c is a point
				return dojo.gfx.matrix._sandwich(dojo.gfx.matrix.scale(a, b), c.x, c.y); // dojo.gfx.matrix.Matrix2D
		}
		// a and b are scale factor components, c and d are components of a point
		return dojo.gfx.matrix._sandwich(dojo.gfx.matrix.scale(a, b), c, d); // dojo.gfx.matrix.Matrix2D
	},
	rotateAt: function(/* Number */ angle, /* Number||Point */ a, /* Number, optional */ b){
		// summary: rotates a picture using a specified point as a center of rotation
		
		// accepts several signatures:
		//	1) rotation angle in radians, Point
		//	2) rotation angle in radians, x, y
		return arguments.length > 1 ? dojo.gfx.matrix._sandwich(dojo.gfx.matrix.rotate(angle), a, b) : dojo.gfx.matrix._sandwich(dojo.gfx.matrix.rotate(angle), a.x, a.y); // dojo.gfx.matrix.Matrix2D
	},
	rotategAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
		// summary: rotates a picture using a specified point as a center of rotation
		
		// accepts several signatures:
		//	1) rotation angle in degrees, Point
		//	2) rotation angle in degrees, x, y
		return arguments.length > 1 ? dojo.gfx.matrix._sandwich(dojo.gfx.matrix.rotateg(degree), a, b) : dojo.gfx.matrix._sandwich(dojo.gfx.matrix.rotateg(degree), a.x, a.y); // dojo.gfx.matrix.Matrix2D
	},
	skewXAt: function(/* Number */ angle, /* Number||Point */ a, /* Number, optional */ b){
		// summary: skews a picture along the X axis using a specified point as a center of skewing
		
		// accepts several signatures:
		//	1) skew angle in radians, Point
		//	2) skew angle in radians, x, y
		return arguments.length > 1 ? dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewX(angle), a, b) : dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewX(angle), a.x, a.y); // dojo.gfx.matrix.Matrix2D
	},
	skewXgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
		// summary: skews a picture along the X axis using a specified point as a center of skewing
		
		// accepts several signatures:
		//	1) skew angle in degrees, Point
		//	2) skew angle in degrees, x, y
		return arguments.length > 1 ? dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewXg(degree), a, b) : dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewXg(degree), a.x, a.y); // dojo.gfx.matrix.Matrix2D
	},
	skewYAt: function(/* Number */ angle, /* Number||Point */ a, /* Number, optional */ b){
		// summary: skews a picture along the Y axis using a specified point as a center of skewing
		
		// accepts several signatures:
		//	1) skew angle in radians, Point
		//	2) skew angle in radians, x, y
		return arguments.length > 1 ? dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewY(angle), a, b) : dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewY(angle), a.x, a.y); // dojo.gfx.matrix.Matrix2D
	},
	skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
		// summary: skews a picture along the Y axis using a specified point as a center of skewing
		
		// accepts several signatures:
		//	1) skew angle in degrees, Point
		//	2) skew angle in degrees, x, y
		return arguments.length > 1 ? dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewYg(degree), a, b) : dojo.gfx.matrix._sandwich(dojo.gfx.matrix.skewYg(degree), a.x, a.y); // dojo.gfx.matrix.Matrix2D
	}
	// TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
});

__CPAN_FILE__ src/gfx/common.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.common");

dojo.require("dojo.gfx.color");
dojo.require("dojo.lang.declare");
dojo.require("dojo.lang.extras");
dojo.require("dojo.dom");

dojo.lang.mixin(dojo.gfx, {
	// summary: defines constants, prototypes, and utility functions
	
	// default shapes, which is used to fill in missing parameters
	defaultPath:     {type: "path",     path: ""},
	defaultPolyline: {type: "polyline", points: []},
	defaultRect:     {type: "rect",     x: 0, y: 0, width: 100, height: 100, r: 0},
	defaultEllipse:  {type: "ellipse",  cx: 0, cy: 0, rx: 200, ry: 100},
	defaultCircle:   {type: "circle",   cx: 0, cy: 0, r: 100},
	defaultLine:     {type: "line",     x1: 0, y1: 0, x2: 100, y2: 100},
	defaultImage:    {type: "image",    width: 0, height: 0, src: ""},

	// default geometric attributes (a stroke, and fills)
	defaultStroke: {color: "black", width: 1, cap: "butt", join: 4},
	defaultLinearGradient: {type: "linear", x1: 0, y1: 0, x2: 100, y2: 100, 
		colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]},
	defaultRadialGradient: {type: "radial", cx: 0, cy: 0, r: 100, 
		colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]},
	defaultPattern: {type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""},

	normalizeColor: function(/* Color */ color){
		// summary: converts any legal color representation to normalized Color object
		return (color instanceof dojo.gfx.color.Color) ? color : new dojo.gfx.color.Color(color); // dojo.gfx.color.Color
	},
	normalizeParameters: function(/* Object */ existed, /* Object */ update){
		// summary: updates an existing object with properties from the "update" object
		// existed: the "target" object to be updated
		// update: the "update" object, whose properties will be used to update the existed object
		if(update){
			var empty = {};
			for(var x in existed){
				if(x in update && !(x in empty)){
					existed[x] = update[x];
				}
			}
		}
		return existed;	// Object
	},
	makeParameters: function(/* Object */ defaults, /* Object */ update){
		// summary: copies the original object, and all copied properties from the "update" object
		// defaults: the object to be cloned before updating
		// update: the object, which properties are to be cloned during updating
		if(!update) return dojo.lang.shallowCopy(defaults, true);
		var result = {};
		for(var i in defaults){
			if(!(i in result)){
				result[i] = dojo.lang.shallowCopy((i in update) ? update[i] : defaults[i], true);
			}
		}
		return result; // Object
	},
	formatNumber: function(/* Number */ x, /* Boolean, optional */ addSpace){
		// summary: converts a number to a string using a fixed notation
		// x: number to be converted
		// addSpace: add a space before a positive number
		var val = x.toString();
		if(val.indexOf("e") >= 0){
			val = x.toFixed(4);
		}else{
			var point = val.indexOf(".");
			if(point >= 0 && val.length - point > 5){
				val = x.toFixed(4);
			}
		}
		if(x < 0){
			return val; // String
		}
		return addSpace ? " " + val : val; // String
	},
	// a constant used to split a SVG/VML path into primitive components
	pathRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g
});

dojo.declare("dojo.gfx.Surface", null, {
	// summary: a surface object to be used for drawings
	initializer: function(){
		// summary: a constructor
		
		// underlying node
		this.rawNode = null;
	},
	getEventSource: function(){
		// summary: returns a node, which can be used to attach event listeners
		return this.rawNode; // Node
	}
});

__CPAN_FILE__ src/gfx/svg.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.svg");

dojo.require("dojo.lang.declare");
dojo.require("dojo.svg");

dojo.require("dojo.gfx.color");
dojo.require("dojo.gfx.common");
dojo.require("dojo.gfx.shape");
dojo.require("dojo.gfx.path");

dojo.require("dojo.experimental");
dojo.experimental("dojo.gfx.svg");

dojo.gfx.svg.getRef = function(fill){
	if(!fill || fill == "none") return null;
	if(fill.match(/^url\(#.+\)$/)){
		return dojo.byId(fill.slice(5, -1));
	}
	// Opera's bug: incorrect representation of a reference
	if(dojo.render.html.opera && fill.match(/^#dj_unique_.+$/)){
		// we assume here that a reference was generated by dojo.gfx
		return dojo.byId(fill.slice(1));
	}
	return null;
};

dojo.lang.extend(dojo.gfx.Shape, {
	setStroke: function(stroke){
		if(!stroke){
			// don't stroke
			this.strokeStyle = null;
			this.rawNode.setAttribute("stroke", "none");
			this.rawNode.setAttribute("stroke-opacity", 0);
			return this;
		}
		// normalize the stroke
		this.strokeStyle = dojo.gfx.makeParameters(dojo.gfx.defaultStroke, stroke);
		this.strokeStyle.color = dojo.gfx.normalizeColor(this.strokeStyle.color);
		// generate attributes
		var s = this.strokeStyle;
		var rn = this.rawNode;
		if(s){
			rn.setAttribute("stroke", s.color.toCss());
			rn.setAttribute("stroke-opacity", s.color.a);
			rn.setAttribute("stroke-width",   s.width);
			rn.setAttribute("stroke-linecap", s.cap);
			if(typeof(s.join) == "number"){
				rn.setAttribute("stroke-linejoin",   "miter");
				rn.setAttribute("stroke-miterlimit", s.join);
			}else{
				rn.setAttribute("stroke-linejoin",   s.join);
			}
		}
		return this;
	},
	
	setFill: function(fill){
		if(!fill){
			// don't fill
			this.fillStyle = null;
			this.rawNode.setAttribute("fill", "none");
			this.rawNode.setAttribute("fill-opacity", 0);
			return this;
		}
		if(typeof(fill) == "object" && "type" in fill){
			// gradient
			switch(fill.type){
				case "linear":
					var f = dojo.gfx.makeParameters(dojo.gfx.defaultLinearGradient, fill);
					var gradient = this._setFillObject(f, "linearGradient");
					dojo.lang.forEach(["x1", "y1", "x2", "y2"], function(x){
						gradient.setAttribute(x, f[x].toFixed(8));
					});
					break;
				case "radial":
					var f = dojo.gfx.makeParameters(dojo.gfx.defaultRadialGradient, fill);
					var gradient = this._setFillObject(f, "radialGradient");
					dojo.lang.forEach(["cx", "cy", "r"], function(x){
						gradient.setAttribute(x, f[x].toFixed(8));
					});
					break;
				case "pattern":
					var f = dojo.gfx.makeParameters(dojo.gfx.defaultPattern, fill);
					var pattern = this._setFillObject(f, "pattern");
					dojo.lang.forEach(["x", "y", "width", "height"], function(x){
						pattern.setAttribute(x, f[x].toFixed(8));
					});
					break;
			}
			return this;
		}
		// color object
		var f = dojo.gfx.normalizeColor(fill);
		this.fillStyle = f;
		this.rawNode.setAttribute("fill", f.toCss());
		this.rawNode.setAttribute("fill-opacity", f.a);
		return this;
	},
	
	_setFillObject: function(/*Object*/f, /*String*/nodeType){
		var def_elems = this.rawNode.parentNode.getElementsByTagName("defs");
		if(def_elems.length == 0){ return this; }
		this.fillStyle = f;
		var defs = def_elems[0];
		var fill = this.rawNode.getAttribute("fill");
		var ref  = dojo.gfx.svg.getRef(fill);
		if(ref){
			fill = ref;
			if(fill.tagName.toLowerCase() != nodeType.toLowerCase()){
				var id = fill.id;
				fill.parentNode.removeChild(fill);
				fill = document.createElementNS(dojo.svg.xmlns.svg, nodeType);
				fill.setAttribute("id", id);
				defs.appendChild(fill);
			}else{
				while(fill.childNodes.length){
					fill.removeChild(fill.lastChild);
				}
			}
		}else{
			fill = document.createElementNS(dojo.svg.xmlns.svg, nodeType);
			fill.setAttribute("id", dojo.dom.getUniqueId());
			defs.appendChild(fill);
		}
		if(nodeType == "pattern"){
			fill.setAttribute("patternUnits", "userSpaceOnUse");
			var img = document.createElementNS(dojo.svg.xmlns.svg, "image");
			img.setAttribute("x", 0);
			img.setAttribute("y", 0);
			img.setAttribute("width",  f.width .toFixed(8));
			img.setAttribute("height", f.height.toFixed(8));
			img.setAttributeNS(dojo.svg.xmlns.xlink, "href", f.src);
			fill.appendChild(img);
		}else{
			fill.setAttribute("gradientUnits", "userSpaceOnUse");
			for(var i = 0; i < f.colors.length; ++i){
				f.colors[i].color = dojo.gfx.normalizeColor(f.colors[i].color);
				var t = document.createElementNS(dojo.svg.xmlns.svg, "stop");
				t.setAttribute("offset",     f.colors[i].offset.toFixed(8));
				t.setAttribute("stop-color", f.colors[i].color.toCss());
				fill.appendChild(t);
			}
		}
		this.rawNode.setAttribute("fill", "url(#" + fill.getAttribute("id") +")");
		this.rawNode.removeAttribute("fill-opacity");
		return fill;
	},
	
	_applyTransform: function() {
		var matrix = this._getRealMatrix();
		if(matrix){
			var tm = this.matrix;
			this.rawNode.setAttribute("transform", "matrix(" +
				tm.xx.toFixed(8) + "," + tm.yx.toFixed(8) + "," +
				tm.xy.toFixed(8) + "," + tm.yy.toFixed(8) + "," +
				tm.dx.toFixed(8) + "," + tm.dy.toFixed(8) + ")");
		}else{
			this.rawNode.removeAttribute("transform");
		}
		return this;
	},

	setRawNode: function(rawNode){
		// summary:
		//		assigns and clears the underlying node that will represent this
		//		shape. Once set, transforms, gradients, etc, can be applied.
		// no fill & stroke by default
		with(rawNode){
			setAttribute("fill", "none");
			setAttribute("fill-opacity", 0);
			setAttribute("stroke", "none");
			setAttribute("stroke-opacity", 0);
			setAttribute("stroke-width", 1);
			setAttribute("stroke-linecap", "butt");
			setAttribute("stroke-linejoin", "miter");
			setAttribute("stroke-miterlimit", 4);
		}
		this.rawNode = rawNode;
	},

	moveToFront: function(){
		this.rawNode.parentNode.appendChild(this.rawNode);
		return this;
	},
	moveToBack: function(){
		this.rawNode.parentNode.insertBefore(this.rawNode, this.rawNode.parentNode.firstChild);
		return this;
	},
	
	setShape: function(newShape){
		this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		for(var i in this.shape){
			if(i != "type"){ this.rawNode.setAttribute(i, this.shape[i]); }
		}
		return this;
	},
	
	attachFill: function(rawNode){
		var fillStyle = null;
		if(rawNode){
			var fill = rawNode.getAttribute("fill");
			if(fill == "none"){ return; }
			var ref  = dojo.gfx.svg.getRef(fill);
			if(ref){
				var gradient = ref;
				switch(gradient.tagName.toLowerCase()){
					case "lineargradient":
						fillStyle = this._getGradient(dojo.gfx.defaultLinearGradient, gradient);
						dojo.lang.forEach(["x1", "y1", "x2", "y2"], function(x){
							fillStyle[x] = gradient.getAttribute(x);
						});
						break;
					case "radialgradient":
						fillStyle = this._getGradient(dojo.gfx.defaultRadialGradient, gradient);
						dojo.lang.forEach(["cx", "cy", "r"], function(x){
							fillStyle[x] = gradient.getAttribute(x);
						});
						fillStyle.cx = gradient.getAttribute("cx");
						fillStyle.cy = gradient.getAttribute("cy");
						fillStyle.r  = gradient.getAttribute("r");
						break;
					case "pattern":
						fillStyle = dojo.lang.shallowCopy(dojo.gfx.defaultPattern, true);
						dojo.lang.forEach(["x", "y", "width", "height"], function(x){
							fillStyle[x] = gradient.getAttribute(x);
						});
						fillStyle.src = gradient.firstChild.getAttributeNS(dojo.svg.xmlns.xlink, "href");
						break;
				}
			}else{
				fillStyle = new dojo.gfx.color.Color(fill);
				var opacity = rawNode.getAttribute("fill-opacity");
				if(opacity != null) fillStyle.a = opacity;
			}
		}
		return fillStyle;
	},
	
	_getGradient: function(defaultGradient, gradient){
		var fillStyle = dojo.lang.shallowCopy(defaultGradient, true);
		fillStyle.colors = [];
		for(var i = 0; i < gradient.childNodes.length; ++i){
			fillStyle.colors.push({
				offset: gradient.childNodes[i].getAttribute("offset"),
				color:  new dojo.gfx.color.Color(gradient.childNodes[i].getAttribute("stop-color"))
			});
		}
		return fillStyle;
	},

	attachStroke: function(rawNode){
		if(!rawNode){ return; }
		var stroke = rawNode.getAttribute("stroke");
		if(stroke == null || stroke == "none") return null;
		var strokeStyle = dojo.lang.shallowCopy(dojo.gfx.defaultStroke, true);
		var color = new dojo.gfx.color.Color(stroke);
		if(color){
			strokeStyle.color = color;
			strokeStyle.color.a = rawNode.getAttribute("stroke-opacity");
			strokeStyle.width = rawNode.getAttribute("stroke-width");
			strokeStyle.cap = rawNode.getAttribute("stroke-linecap");
			strokeStyle.join = rawNode.getAttribute("stroke-linejoin");
			if(strokeStyle.join == "miter"){
				strokeStyle.join = rawNode.getAttribute("stroke-miterlimit");
			}
		}
		return strokeStyle;
	},

	attachTransform: function(rawNode){
		var matrix = null;
		if(rawNode){
			matrix = rawNode.getAttribute("transform");
			if(matrix.match(/^matrix\(.+\)$/)){
				var t = matrix.slice(7, -1).split(",");
				matrix = dojo.gfx.matrix.normalize({
					xx: parseFloat(t[0]), xy: parseFloat(t[2]), 
					yx: parseFloat(t[1]), yy: parseFloat(t[3]), 
					dx: parseFloat(t[4]), dy: parseFloat(t[5])
				});
			}
		}
		return matrix;
	},
	
	attachShape: function(rawNode){
		var shape = null;
		if(rawNode){
			shape = dojo.lang.shallowCopy(this.shape, true);
			for(var i in shape) {
				shape[i] = rawNode.getAttribute(i);
			}
		}
		return shape;
	},

	attach: function(rawNode){
		if(rawNode) {
			this.rawNode = rawNode;
			this.fillStyle = this.attachFill(rawNode);
			this.strokeStyle = this.attachStroke(rawNode);
			this.matrix = this.attachTransform(rawNode);
			this.shape = this.attachShape(rawNode);
		}
	}
});

dojo.declare("dojo.gfx.Group", dojo.gfx.Shape, {
	setRawNode: function(rawNode){
		this.rawNode = rawNode;
	}
});
dojo.gfx.Group.nodeType = "g";

dojo.declare("dojo.gfx.Rect", dojo.gfx.shape.Rect, {
	attachShape: function(rawNode){
		var shape = null;
		if(rawNode){
			shape = dojo.gfx.Rect.superclass.attachShape.apply(this, arguments);
			shape.r = Math.min(rawNode.getAttribute("rx"), rawNode.getAttribute("ry"));
		}
		return shape;
	},
	setShape: function(newShape){
		this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		for(var i in this.shape){
			if(i != "type" && i != "r"){ this.rawNode.setAttribute(i, this.shape[i]); }
		}
		this.rawNode.setAttribute("rx", this.shape.r);
		this.rawNode.setAttribute("ry", this.shape.r);
		return this;
	}
});
dojo.gfx.Rect.nodeType = "rect";

dojo.gfx.Ellipse = dojo.gfx.shape.Ellipse;
dojo.gfx.Ellipse.nodeType = "ellipse";

dojo.gfx.Circle = dojo.gfx.shape.Circle;
dojo.gfx.Circle.nodeType = "circle";

dojo.gfx.Line = dojo.gfx.shape.Line;
dojo.gfx.Line.nodeType = "line";

dojo.declare("dojo.gfx.Polyline", dojo.gfx.shape.Polyline, {
	setShape: function(points){
		if(points && points instanceof Array){
			this.shape = dojo.gfx.makeParameters(this.shape, { points: points });
			if(closed && this.shape.points.length){ 
				this.shape.points.push(this.shape.points[0]);
			}
		}else{
			this.shape = dojo.gfx.makeParameters(this.shape, points);
		}
		this.box = null;
		var attr = [];
		var p = this.shape.points;
		for(var i = 0; i < p.length; ++i){
			attr.push(p[i].x.toFixed(8));
			attr.push(p[i].y.toFixed(8));
		}
		this.rawNode.setAttribute("points", attr.join(" "));
		return this;
	}
});
dojo.gfx.Polyline.nodeType = "polyline";

dojo.declare("dojo.gfx.Image", dojo.gfx.shape.Image, {
	setShape: function(newShape){
		this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		var rawNode = this.rawNode;
		for(var i in this.shape){
			if(i != "type" && i != "src"){ rawNode.setAttribute(i, this.shape[i]); }
		}
		rawNode.setAttributeNS(dojo.svg.xmlns.xlink, "href", this.shape.src);
		return this;
	},
	setStroke: function() { return this; },
	setFill:   function() { return this; },
	attachStroke: function(rawNode){ return null; },
	attachFill:   function(rawNode){ return null; }
});
dojo.gfx.Image.nodeType = "image";

dojo.declare("dojo.gfx.Path", dojo.gfx.path.Path,
{
	_updateWithSegment: function(segment){
		dojo.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
		if(typeof(this.shape.path) == "string"){
			this.rawNode.setAttribute("d", this.shape.path);
		}
	},
	setShape: function(newShape){
		dojo.gfx.Path.superclass.setShape.apply(this, arguments);
		this.rawNode.setAttribute("d", this.shape.path);
		return this;
	}
});
dojo.gfx.Path.nodeType = "path";

dojo.gfx._creators = {
	// creators
	createPath: function(path){
		return this.createObject(dojo.gfx.Path, path);
	},
	createRect: function(rect){
		return this.createObject(dojo.gfx.Rect, rect);
	},
	createCircle: function(circle){
		return this.createObject(dojo.gfx.Circle, circle);
	},
	createEllipse: function(ellipse){
		return this.createObject(dojo.gfx.Ellipse, ellipse);
	},
	createLine: function(line){
		return this.createObject(dojo.gfx.Line, line);
	},
	createPolyline: function(points){
		return this.createObject(dojo.gfx.Polyline, points);
	},
	createImage: function(image){
		return this.createObject(dojo.gfx.Image, image);
	},
	createGroup: function(){
		return this.createObject(dojo.gfx.Group);
	},
	createObject: function(/*Function*/shapeType, /*Object*/rawShape){
		// summary: creates an instance of the passed shapeType class
		// shapeType: a class constructor to create an instance of
		// rawShape: properties to be passed in to the classes "setShape" method

		if(!this.rawNode){ return null; }
		var shape = new shapeType();
		var node = document.createElementNS(dojo.svg.xmlns.svg, shapeType.nodeType); 
		shape.setRawNode(node);
		this.rawNode.appendChild(node);
		shape.setShape(rawShape);
		this.add(shape);
		return shape;
	},
	// group control
	add: function(shape){
		var oldParent = shape.getParent();
		if(oldParent){
			oldParent.remove(shape, true);
		}
		shape._setParent(this, null);
		this.rawNode.appendChild(shape.rawNode);
		return this;
	},
	remove: function(shape, silently){
		if(this.rawNode == shape.rawNode.parentNode){
			this.rawNode.removeChild(shape.rawNode);
		}
		shape._setParent(null, null);
		return this;
	}
};

dojo.gfx.attachNode = function(node){
	if(!node) return null;
	var s = null;
	switch(node.tagName.toLowerCase()){
		case dojo.gfx.Rect.nodeType:
			s = new dojo.gfx.Rect();
			break;
		case dojo.gfx.Ellipse.nodeType:
			s = new dojo.gfx.Ellipse();
			break;
		case dojo.gfx.Polyline.nodeType:
			s = new dojo.gfx.Polyline();
			break;
		case dojo.gfx.Path.nodeType:
			s = new dojo.gfx.Path();
			break;
		case dojo.gfx.Circle.nodeType:
			s = new dojo.gfx.Circle();
			break;
		case dojo.gfx.Line.nodeType:
			s = new dojo.gfx.Line();
			break;
		case dojo.gfx.Image.nodeType:
			s = new dojo.gfx.Image();
			break;
		default:
			dojo.debug("FATAL ERROR! tagName = " + node.tagName);
	}
	s.attach(node);
	return s;
};

dojo.lang.extend(dojo.gfx.Surface, {
	setDimensions: function(/*String*/width, /*String*/height){
		// summary: sets the width and height of the rawNode
		if(!this.rawNode){ return this; }
		this.rawNode.setAttribute("width",  width);
		this.rawNode.setAttribute("height", height);
		return this; // dojo.gfx.Surface
	},
	getDimensions: function(){
		// summary: returns an object with properties "width" and "height"
		return this.rawNode ? {width: this.rawNode.getAttribute("width"), height: this.rawNode.getAttribute("height")} : null; // Object
	}
});

dojo.gfx.createSurface = function(parentNode, width, height){
	var s = new dojo.gfx.Surface();
	s.rawNode = document.createElementNS(dojo.svg.xmlns.svg, "svg");
	s.rawNode.setAttribute("width",  width);
	s.rawNode.setAttribute("height", height);

	var defs = new dojo.gfx.svg.Defines();
	var node = document.createElementNS(dojo.svg.xmlns.svg, dojo.gfx.svg.Defines.nodeType); 
	defs.setRawNode(node);
	s.rawNode.appendChild(node);
	
	dojo.byId(parentNode).appendChild(s.rawNode);
	return s;
};

dojo.gfx.attachSurface = function(node){
	var s = new dojo.gfx.Surface();
	s.rawNode = node;
	return s;
};

dojo.lang.extend(dojo.gfx.Group, dojo.gfx._creators);
dojo.lang.extend(dojo.gfx.Surface, dojo.gfx._creators);

delete dojo.gfx._creators;

// Gradient and pattern
dojo.gfx.svg.Defines = function(){
	this.rawNode = null;
};
dojo.lang.extend(dojo.gfx.svg.Defines, {
	setRawNode: function(rawNode){
		this.rawNode = rawNode;
	}
});
dojo.gfx.svg.Defines.nodeType = "defs";

__CPAN_FILE__ src/gfx/color.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.color");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.array");

// TODO: rewrite the "x2y" methods to take advantage of the parsing
//       abilities of the Color object. Also, beef up the Color
//       object (as possible) to parse most common formats

// takes an r, g, b, a(lpha) value, [r, g, b, a] array, "rgb(...)" string, hex string (#aaa, #aaaaaa, aaaaaaa)
dojo.gfx.color.Color = function(r, g, b, a) {
	// dojo.debug("r:", r[0], "g:", r[1], "b:", r[2]);
	if(dojo.lang.isArray(r)){
		this.r = r[0];
		this.g = r[1];
		this.b = r[2];
		this.a = r[3]||1.0;
	}else if(dojo.lang.isString(r)){
		var rgb = dojo.gfx.color.extractRGB(r);
		this.r = rgb[0];
		this.g = rgb[1];
		this.b = rgb[2];
		this.a = g||1.0;
	}else if(r instanceof dojo.gfx.color.Color){
		// why does this create a new instance if we were passed one?
		this.r = r.r;
		this.b = r.b;
		this.g = r.g;
		this.a = r.a;
	}else{
		this.r = r;
		this.g = g;
		this.b = b;
		this.a = a;
	}
}

dojo.gfx.color.Color.fromArray = function(arr) {
	return new dojo.gfx.color.Color(arr[0], arr[1], arr[2], arr[3]);
}

dojo.extend(dojo.gfx.color.Color, {
	toRgb: function(includeAlpha) {
		if(includeAlpha) {
			return this.toRgba();
		} else {
			return [this.r, this.g, this.b];
		}
	},
	toRgba: function() {
		return [this.r, this.g, this.b, this.a];
	},
	toHex: function() {
		return dojo.gfx.color.rgb2hex(this.toRgb());
	},
	toCss: function() {
		return "rgb(" + this.toRgb().join() + ")";
	},
	toString: function() {
		return this.toHex(); // decent default?
	},
	blend: function(color, weight){
		var rgb = null;
		if(dojo.lang.isArray(color)){
			rgb = color;
		}else if(color instanceof dojo.gfx.color.Color){
			rgb = color.toRgb();
		}else{
			rgb = new dojo.gfx.color.Color(color).toRgb();
		}
		return dojo.gfx.color.blend(this.toRgb(), rgb, weight);
	}
});

dojo.gfx.color.named = {
	white:      [255,255,255],
	black:      [0,0,0],
	red:        [255,0,0],
	green:	    [0,255,0],
	lime:	    [0,255,0],
	blue:       [0,0,255],
	navy:       [0,0,128],
	gray:       [128,128,128],
	silver:     [192,192,192]
};

dojo.gfx.color.blend = function(a, b, weight){
	// summary: 
	//		blend colors a and b (both as RGB array or hex strings) with weight
	//		from -1 to +1, 0 being a 50/50 blend
	if(typeof a == "string"){
		return dojo.gfx.color.blendHex(a, b, weight);
	}
	if(!weight){
		weight = 0;
	}
	weight = Math.min(Math.max(-1, weight), 1);

	// alex: this interface blows.
	// map -1 to 1 to the range 0 to 1
	weight = ((weight + 1)/2);
	
	var c = [];

	// var stop = (1000*weight);
	for(var x = 0; x < 3; x++){
		c[x] = parseInt( b[x] + ( (a[x] - b[x]) * weight) );
	}
	return c;
}

// very convenient blend that takes and returns hex values
// (will get called automatically by blend when blend gets strings)
dojo.gfx.color.blendHex = function(a, b, weight) {
	return dojo.gfx.color.rgb2hex(dojo.gfx.color.blend(dojo.gfx.color.hex2rgb(a), dojo.gfx.color.hex2rgb(b), weight));
}

// get RGB array from css-style color declarations
dojo.gfx.color.extractRGB = function(color) {
	var hex = "0123456789abcdef";
	color = color.toLowerCase();
	if( color.indexOf("rgb") == 0 ) {
		var matches = color.match(/rgba*\((\d+), *(\d+), *(\d+)/i);
		var ret = matches.splice(1, 3);
		return ret;
	} else {
		var colors = dojo.gfx.color.hex2rgb(color);
		if(colors) {
			return colors;
		} else {
			// named color (how many do we support?)
			return dojo.gfx.color.named[color] || [255, 255, 255];
		}
	}
}

dojo.gfx.color.hex2rgb = function(hex) {
	var hexNum = "0123456789ABCDEF";
	var rgb = new Array(3);
	if( hex.indexOf("#") == 0 ) { hex = hex.substring(1); }
	hex = hex.toUpperCase();
	if(hex.replace(new RegExp("["+hexNum+"]", "g"), "") != "") {
		return null;
	}
	if( hex.length == 3 ) {
		rgb[0] = hex.charAt(0) + hex.charAt(0)
		rgb[1] = hex.charAt(1) + hex.charAt(1)
		rgb[2] = hex.charAt(2) + hex.charAt(2);
	} else {
		rgb[0] = hex.substring(0, 2);
		rgb[1] = hex.substring(2, 4);
		rgb[2] = hex.substring(4);
	}
	for(var i = 0; i < rgb.length; i++) {
		rgb[i] = hexNum.indexOf(rgb[i].charAt(0)) * 16 + hexNum.indexOf(rgb[i].charAt(1));
	}
	return rgb;
}

dojo.gfx.color.rgb2hex = function(r, g, b) {
	if(dojo.lang.isArray(r)) {
		g = r[1] || 0;
		b = r[2] || 0;
		r = r[0] || 0;
	}
	var ret = dojo.lang.map([r, g, b], function(x) {
		x = new Number(x);
		var s = x.toString(16);
		while(s.length < 2) { s = "0" + s; }
		return s;
	});
	ret.unshift("#");
	return ret.join("");
}

__CPAN_FILE__ src/gfx/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.gfx.color",
		"dojo.gfx.matrix",
		"dojo.gfx.common"
	]
});

// include a renderer conditionally
dojo["requireIf"](dojo.render.svg.capable, "dojo.gfx.svg");
dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.gfx.vml");

dojo.provide("dojo.gfx.*");
__CPAN_FILE__ src/gfx/Colorspace.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.Colorspace");

dojo.require("dojo.lang.common");
dojo.require("dojo.math.matrix");

// to convert to YUV:
//   c.whitePoint = 'D65';
//   c.RGBWorkingSpace = 'pal_secam_rgb';
//   var out = c.convert([r,g,b], 'RGB', 'XYZ');
//
// to convert to YIQ:
//   c.whitePoint = 'D65';
//   c.RGBWorkingSpace = 'ntsc_rgb';
//   var out = c.convert([r,g,b], 'RGB', 'XYZ');
//

dojo.gfx.Colorspace = function(){
	//	summary
	//	An object for dealing with colorspace conversions.
	this.whitePoint = 'D65';
	this.stdObserver = '10';
	this.chromaticAdaptationAlg = 'bradford';
	this.RGBWorkingSpace = 's_rgb';
	this.useApproxCIELabMapping = 1; // see http://www.brucelindbloom.com/LContinuity.html

	this.chainMaps = {
		'RGB_to_xyY'  : ['XYZ'],
		'xyY_to_RGB'  : ['XYZ'],
		'RGB_to_Lab'  : ['XYZ'],
		'Lab_to_RGB'  : ['XYZ'],
		'RGB_to_LCHab': ['XYZ', 'Lab'],
		'LCHab_to_RGB': ['Lab'],
		'xyY_to_Lab'  : ['XYZ'],
		'Lab_to_xyY'  : ['XYZ'],
		'XYZ_to_LCHab': ['Lab'],
		'LCHab_to_XYZ': ['Lab'],
		'xyY_to_LCHab': ['XYZ', 'Lab'],
		'LCHab_to_xyY': ['Lab', 'XYZ'],
		'RGB_to_Luv'  : ['XYZ'],
		'Luv_to_RGB'  : ['XYZ'],
		'xyY_to_Luv'  : ['XYZ'],
		'Luv_to_xyY'  : ['XYZ'],
		'Lab_to_Luv'  : ['XYZ'],
		'Luv_to_Lab'  : ['XYZ'],
		'LCHab_to_Luv': ['Lab', 'XYZ'],
		'Luv_to_LCHab': ['XYZ', 'Lab'],
		'RGB_to_LCHuv'  : ['XYZ', 'Luv'],
		'LCHuv_to_RGB'  : ['Luv', 'XYZ'],
		'XYZ_to_LCHuv'  : ['Luv'],
		'LCHuv_to_XYZ'  : ['Luv'],
		'xyY_to_LCHuv'  : ['XYZ', 'Luv'],
		'LCHuv_to_xyY'  : ['Luv', 'XYZ'],
		'Lab_to_LCHuv'  : ['XYZ', 'Luv'],
		'LCHuv_to_Lab'  : ['Luv', 'XYZ'],
		'LCHab_to_LCHuv': ['Lab', 'XYZ', 'Luv'],
		'LCHuv_to_LCHab': ['Luv', 'XYZ', 'Lab'],
		'XYZ_to_CMY'    : ['RGB'],
		'CMY_to_XYZ'    : ['RGB'],
		'xyY_to_CMY'    : ['RGB'],
		'CMY_to_xyY'    : ['RGB'],
		'Lab_to_CMY'    : ['RGB'],
		'CMY_to_Lab'    : ['RGB'],
		'LCHab_to_CMY'  : ['RGB'],
		'CMY_to_LCHab'  : ['RGB'],
		'Luv_to_CMY'    : ['RGB'],
		'CMY_to_Luv'    : ['RGB'],
		'LCHuv_to_CMY'  : ['RGB'],
		'CMY_to_LCHuv'  : ['RGB'],
		'XYZ_to_HSL'    : ['RGB'],
		'HSL_to_XYZ'    : ['RGB'],
		'xyY_to_HSL'    : ['RGB'],
		'HSL_to_xyY'    : ['RGB'],
		'Lab_to_HSL'    : ['RGB'],
		'HSL_to_Lab'    : ['RGB'],
		'LCHab_to_HSL'  : ['RGB'],
		'HSL_to_LCHab'  : ['RGB'],
		'Luv_to_HSL'    : ['RGB'],
		'HSL_to_Luv'    : ['RGB'],
		'LCHuv_to_HSL'  : ['RGB'],
		'HSL_to_LCHuv'  : ['RGB'],
		'CMY_to_HSL'    : ['RGB'],
		'HSL_to_CMY'    : ['RGB'],
		'CMYK_to_HSL'   : ['RGB'],
		'HSL_to_CMYK'   : ['RGB'],
		'XYZ_to_HSV'    : ['RGB'],
		'HSV_to_XYZ'    : ['RGB'],
		'xyY_to_HSV'    : ['RGB'],
		'HSV_to_xyY'    : ['RGB'],
		'Lab_to_HSV'    : ['RGB'],
		'HSV_to_Lab'    : ['RGB'],
		'LCHab_to_HSV'  : ['RGB'],
		'HSV_to_LCHab'  : ['RGB'],
		'Luv_to_HSV'    : ['RGB'],
		'HSV_to_Luv'    : ['RGB'],
		'LCHuv_to_HSV'  : ['RGB'],
		'HSV_to_LCHuv'  : ['RGB'],
		'CMY_to_HSV'    : ['RGB'],
		'HSV_to_CMY'    : ['RGB'],
		'CMYK_to_HSV'   : ['RGB'],
		'HSV_to_CMYK'   : ['RGB'],
		'HSL_to_HSV'    : ['RGB'],
		'HSV_to_HSL'    : ['RGB'],
		'XYZ_to_CMYK'   : ['RGB'],
		'CMYK_to_XYZ'   : ['RGB'],
		'xyY_to_CMYK'   : ['RGB'],
		'CMYK_to_xyY'   : ['RGB'],
		'Lab_to_CMYK'   : ['RGB'],
		'CMYK_to_Lab'   : ['RGB'],
		'LCHab_to_CMYK' : ['RGB'],
		'CMYK_to_LCHab' : ['RGB'],
		'Luv_to_CMYK'   : ['RGB'],
		'CMYK_to_Luv'   : ['RGB'],
		'LCHuv_to_CMYK' : ['RGB'],
		'CMYK_to_LCHuv' : ['RGB']
	};
	return this;
}

dojo.gfx.Colorspace.prototype.convert = function(col, model_from, model_to){
	var k = model_from+'_to_'+model_to;
	if (this[k]){
		return this[k](col);
	}else{
		if (this.chainMaps[k]){
			var cur = model_from;
			var models = this.chainMaps[k].concat();
			models.push(model_to);
			for(var i=0; i<models.length; i++){
				col = this.convert(col, cur, models[i]);
				cur = models[i];
			}
			return col;
		}else{
			dojo.debug("Can't convert from "+model_from+' to '+model_to);
		}
	}
}

dojo.gfx.Colorspace.prototype.munge = function(keys, args){
	if (dojo.lang.isArray(args[0])){
		args = args[0];
	}
	var out = new Array();
	for (var i=0; i<keys.length; i++){
		out[keys.charAt(i)] = args[i];
	}
	return out;
}

dojo.gfx.Colorspace.prototype.getWhitePoint = function(){
	var x = 0;
	var y = 0;
	var t = 0;

	// ref: http://en.wikipedia.org/wiki/White_point
	// TODO: i need some good/better white point values

	switch(this.stdObserver){
		case '2' :
			switch(this.whitePoint){
				case 'E'   : x=1/3    ; y=1/3    ; t=5400; break; //Equal energy
				case 'D50' : x=0.34567; y=0.35850; t=5000; break;
				case 'D55' : x=0.33242; y=0.34743; t=5500; break;
				case 'D65' : x=0.31271; y=0.32902; t=6500; break;
				case 'D75' : x=0.29902; y=0.31485; t=7500; break;
				case 'A'   : x=0.44757; y=0.40745; t=2856; break; //Incandescent tungsten
				case 'B'   : x=0.34842; y=0.35161; t=4874; break;
				case 'C'   : x=0.31006; y=0.31616; t=6774; break;
				case '9300': x=0.28480; y=0.29320; t=9300; break; //Blue phosphor monitors
				case 'F2'  : x=0.37207; y=0.37512; t=4200; break; //Cool White Fluorescent
				case 'F7'  : x=0.31285; y=0.32918; t=6500; break; //Narrow Band Daylight Fluorescent
				case 'F11' : x=0.38054; y=0.37691; t=4000; break; //Narrow Band White Fluorescent
				default: dojo.debug('White point '+this.whitePoint+" isn't defined for Std. Observer "+this.strObserver);
			};
			break;
		case '10' :
			switch(this.whitePoint){
				case 'E'   : x=1/3    ; y=1/3    ; t=5400; break; //Equal energy
				case 'D50' : x=0.34773; y=0.35952; t=5000; break;
				case 'D55' : x=0.33411; y=0.34877; t=5500; break;
				case 'D65' : x=0.31382; y=0.33100; t=6500; break;
				case 'D75' : x=0.29968; y=0.31740; t=7500; break;
				case 'A'   : x=0.45117; y=0.40594; t=2856; break; //Incandescent tungsten
				case 'B'   : x=0.3498 ; y=0.3527 ; t=4874; break;
				case 'C'   : x=0.31039; y=0.31905; t=6774; break;
				case 'F2'  : x=0.37928; y=0.36723; t=4200; break; //Cool White Fluorescent
				case 'F7'  : x=0.31565; y=0.32951; t=6500; break; //Narrow Band Daylight Fluorescent
				case 'F11' : x=0.38543; y=0.37110; t=4000; break; //Narrow Band White Fluorescent
				default: dojo.debug('White point '+this.whitePoint+" isn't defined for Std. Observer "+this.strObserver);
			};
			break;
		default:
			dojo.debug("Std. Observer "+this.strObserver+" isn't defined");
	}

	var z = 1 - x - y;
	var wp = {'x':x, 'y':y, 'z':z, 't':t};
	wp.Y = 1;

	var XYZ = this.xyY_to_XYZ([wp.x, wp.y, wp.Y]);
	wp.X = XYZ[0];
	wp.Y = XYZ[1];
	wp.Z = XYZ[2];
	return wp;
}

dojo.gfx.Colorspace.prototype.getPrimaries = function(){
	// ref: http://www.fho-emden.de/~hoffmann/ciexyz29082000.pdf
	// ref: http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var m = [];
	switch(this.RGBWorkingSpace){
		case 'adobe_rgb_1998'	: m = [2.2, 'D65', 0.6400, 0.3300, 0.297361, 0.2100, 0.7100, 0.627355, 0.1500, 0.0600, 0.075285]; break;
		case 'apple_rgb'	: m = [1.8, 'D65', 0.6250, 0.3400, 0.244634, 0.2800, 0.5950, 0.672034, 0.1550, 0.0700, 0.083332]; break;
		case 'best_rgb'		: m = [2.2, 'D50', 0.7347, 0.2653, 0.228457, 0.2150, 0.7750, 0.737352, 0.1300, 0.0350, 0.034191]; break;
		case 'beta_rgb'		: m = [2.2, 'D50', 0.6888, 0.3112, 0.303273, 0.1986, 0.7551, 0.663786, 0.1265, 0.0352, 0.032941]; break;
		case 'bruce_rgb'	: m = [2.2, 'D65', 0.6400, 0.3300, 0.240995, 0.2800, 0.6500, 0.683554, 0.1500, 0.0600, 0.075452]; break;
		case 'cie_rgb'		: m = [2.2, 'E'  , 0.7350, 0.2650, 0.176204, 0.2740, 0.7170, 0.812985, 0.1670, 0.0090, 0.010811]; break;
		case 'color_match_rgb'	: m = [1.8, 'D50', 0.6300, 0.3400, 0.274884, 0.2950, 0.6050, 0.658132, 0.1500, 0.0750, 0.066985]; break;
		case 'don_rgb_4'	: m = [2.2, 'D50', 0.6960, 0.3000, 0.278350, 0.2150, 0.7650, 0.687970, 0.1300, 0.0350, 0.033680]; break;
		case 'eci_rgb'		: m = [1.8, 'D50', 0.6700, 0.3300, 0.320250, 0.2100, 0.7100, 0.602071, 0.1400, 0.0800, 0.077679]; break;
		case 'ekta_space_ps5'	: m = [2.2, 'D50', 0.6950, 0.3050, 0.260629, 0.2600, 0.7000, 0.734946, 0.1100, 0.0050, 0.004425]; break;
		case 'ntsc_rgb'		: m = [2.2, 'C'  , 0.6700, 0.3300, 0.298839, 0.2100, 0.7100, 0.586811, 0.1400, 0.0800, 0.114350]; break;
		case 'pal_secam_rgb'	: m = [2.2, 'D65', 0.6400, 0.3300, 0.222021, 0.2900, 0.6000, 0.706645, 0.1500, 0.0600, 0.071334]; break;
		case 'pro_photo_rgb'	: m = [1.8, 'D50', 0.7347, 0.2653, 0.288040, 0.1596, 0.8404, 0.711874, 0.0366, 0.0001, 0.000086]; break;
		case 'smpte-c_rgb'	: m = [2.2, 'D65', 0.6300, 0.3400, 0.212395, 0.3100, 0.5950, 0.701049, 0.1550, 0.0700, 0.086556]; break;
		case 's_rgb'		: m = [2.2, 'D65', 0.6400, 0.3300, 0.212656, 0.3000, 0.6000, 0.715158, 0.1500, 0.0600, 0.072186]; break;
		case 'wide_gamut_rgb'	: m = [2.2, 'D50', 0.7350, 0.2650, 0.258187, 0.1150, 0.8260, 0.724938, 0.1570, 0.0180, 0.016875]; break;
		default: dojo.debug("RGB working space "+this.RGBWorkingSpace+" isn't defined");
	}

	var p = {
		name: this.RGBWorkingSpace,
		gamma:m[0],
		wp:m[1],
		xr:m[2],
		yr:m[3],
		Yr:m[4],
		xg:m[5],
		yg:m[6],
		Yg:m[7],
		xb:m[8],
		yb:m[9],
		Yb:m[10]
	};

	// if WP doesn't match current WP, convert the primaries over
	if (p.wp != this.whitePoint){
		var r = this.XYZ_to_xyY( this.chromaticAdaptation( this.xyY_to_XYZ([p.xr, p.yr, p.Yr]), p.wp, this.whitePoint ) );
		var g = this.XYZ_to_xyY( this.chromaticAdaptation( this.xyY_to_XYZ([p.xg, p.yg, p.Yg]), p.wp, this.whitePoint ) );
		var b = this.XYZ_to_xyY( this.chromaticAdaptation( this.xyY_to_XYZ([p.xb, p.yb, p.Yb]), p.wp, this.whitePoint ) );

		p.xr = r[0];
		p.yr = r[1];
		p.Yr = r[2];

		p.xg = g[0];
		p.yg = g[1];
		p.Yg = g[2];

		p.xb = b[0];
		p.yb = b[1];
		p.Yb = b[2];

		p.wp = this.whitePoint;
	}

	p.zr = 1 - p.xr - p.yr;
	p.zg = 1 - p.xg - p.yg;
	p.zb = 1 - p.xb - p.yb;
	return p;
}

dojo.gfx.Colorspace.prototype.epsilon = function(){
	return this.useApproxCIELabMapping ? 0.008856 : 216 / 24289;
}

dojo.gfx.Colorspace.prototype.kappa = function(){
	return this.useApproxCIELabMapping ? 903.3 : 24389 / 27;
}

dojo.gfx.Colorspace.prototype.XYZ_to_xyY = function(){
	var src = this.munge('XYZ', arguments);
	var sum = src.X + src.Y + src.Z;
	if (sum == 0){
		var wp = this.getWhitePoint();
		var x = wp.x;
		var y = wp.y;
	}else{
		var x = src.X / sum;
		var y = src.Y / sum;
	}

	var Y = src.Y;
	return [x, y, Y];
}

dojo.gfx.Colorspace.prototype.xyY_to_XYZ = function(){
	var src = this.munge('xyY', arguments);
	if (src.y == 0){
		var X = 0;
		var Y = 0;
		var Z = 0;
	}else{
		var X = (src.x * src.Y) / src.y;
		var Y = src.Y;
		var Z = ((1 - src.x - src.y) * src.Y) / src.y;
	}

	return [X, Y, Z];
}

dojo.gfx.Colorspace.prototype.RGB_to_XYZ = function(){
	var src = this.munge('RGB', arguments);
	var m = this.getRGB_XYZ_Matrix();
	var pr = this.getPrimaries();

	if (this.RGBWorkingSpace == 's_rgb'){
		var r = (src.R > 0.04045) ? Math.pow(((src.R + 0.055) / 1.055), 2.4) : src.R / 12.92;
		var g = (src.G > 0.04045) ? Math.pow(((src.G + 0.055) / 1.055), 2.4) : src.G / 12.92;
		var b = (src.B > 0.04045) ? Math.pow(((src.B + 0.055) / 1.055), 2.4) : src.B / 12.92;
	}else{
		var r = Math.pow(src.R, pr.gamma);
		var g = Math.pow(src.G, pr.gamma);
		var b = Math.pow(src.B, pr.gamma);
	}

	var XYZ = dojo.math.matrix.multiply([[r, g, b]], m);
	return [XYZ[0][0], XYZ[0][1], XYZ[0][2]];
}

dojo.gfx.Colorspace.prototype.XYZ_to_RGB = function(){
	var src = this.munge('XYZ', arguments);
	var mi = this.getXYZ_RGB_Matrix();
	var pr = this.getPrimaries();

	var rgb = dojo.math.matrix.multiply([[src.X, src.Y, src.Z]], mi);
	var r = rgb[0][0];
	var g = rgb[0][1];
	var b = rgb[0][2];

	if (this.RGBWorkingSpace == 's_rgb'){
		var R = (r > 0.0031308) ? (1.055 * Math.pow(r, 1.0/2.4)) - 0.055 : 12.92 * r;
		var G = (g > 0.0031308) ? (1.055 * Math.pow(g, 1.0/2.4)) - 0.055 : 12.92 * g;
		var B = (b > 0.0031308) ? (1.055 * Math.pow(b, 1.0/2.4)) - 0.055 : 12.92 * b;
	}else{
		var R = Math.pow(r, 1/pr.gamma);
		var G = Math.pow(g, 1/pr.gamma);
		var B = Math.pow(b, 1/pr.gamma);
	}
	return [R, G, B];
}

dojo.gfx.Colorspace.prototype.XYZ_to_Lab = function(){
	var src = this.munge('XYZ', arguments);
	var wp = this.getWhitePoint();

	var xr = src.X / wp.X;
	var yr = src.Y / wp.Y;
	var zr = src.Z / wp.Z;

	var fx = (xr > this.epsilon()) ? Math.pow(xr, 1/3) : (this.kappa() * xr + 16) / 116;
	var fy = (yr > this.epsilon()) ? Math.pow(yr, 1/3) : (this.kappa() * yr + 16) / 116;
	var fz = (zr > this.epsilon()) ? Math.pow(zr, 1/3) : (this.kappa() * zr + 16) / 116;

	var L = 116 * fy - 16;
	var a = 500 * (fx - fy);
	var b = 200 * (fy - fz);

	return [L, a, b];
}

dojo.gfx.Colorspace.prototype.Lab_to_XYZ = function(){
	var src = this.munge('Lab', arguments);
	var wp = this.getWhitePoint();
	var yr = (src.L > (this.kappa() * this.epsilon())) ? Math.pow((src.L + 16) / 116, 3) : src.L / this.kappa();

	var fy = (yr > this.epsilon()) ? (src.L + 16) / 116 : (this.kappa() * yr + 16) / 116;
	var fx = (src.a / 500) + fy;
	var fz = fy - (src.b / 200);

	var fxcube = Math.pow(fx, 3);
	var fzcube = Math.pow(fz, 3);

	var xr = (fxcube > this.epsilon()) ? fxcube : (116 * fx - 16) / this.kappa();
	var zr = (fzcube > this.epsilon()) ? fzcube : (116 * fz - 16) / this.kappa();

	var X = xr * wp.X;
	var Y = yr * wp.Y;
	var Z = zr * wp.Z;

	return [X, Y, Z];
}

dojo.gfx.Colorspace.prototype.Lab_to_LCHab = function(){
	var src = this.munge('Lab', arguments);

	var L = src.L;
	var C = Math.pow(src.a * src.a + src.b * src.b, 0.5);
	var H = Math.atan2(src.b, src.a) * (180 / Math.PI);

	if (H < 0){ H += 360; }
	if (H > 360){ H -= 360; }

	return [L, C, H];
}

dojo.gfx.Colorspace.prototype.LCHab_to_Lab = function(){
	var src = this.munge('LCH', arguments);

	var H_rad = src.H * (Math.PI / 180);
	var L = src.L;
	var a = src.C / Math.pow(Math.pow(Math.tan(H_rad), 2) + 1, 0.5);
	if ((90 < src.H) && (src.H < 270)){ a= -a; }

	var b = Math.pow(Math.pow(src.C, 2) - Math.pow(a, 2), 0.5);
	if (src.H > 180){ b = -b; }

	return [L, a, b];
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// this function converts an XYZ color array (col) from one whitepoint (src_w) to another (dst_w)
//

dojo.gfx.Colorspace.prototype.chromaticAdaptation = function(col, src_w, dst_w){
	col = this.munge('XYZ', [col]);
	var old_wp = this.whitePoint;

	this.whitePoint = src_w;
	var wp_src = this.getWhitePoint();

	this.whitePoint = dst_w;
	var wp_dst = this.getWhitePoint();

	this.whitePoint = old_wp;

	switch(this.chromaticAdaptationAlg){
		case 'xyz_scaling':
			var ma = [[1,0,0],[0,1,0],[0,0,1]];
			var mai = [[1,0,0],[0,1,0],[0,0,1]];
			break;
		case 'bradford':
			var ma = [[0.8951, -0.7502, 0.0389],[0.2664, 1.7135, -0.0685],[-0.1614, 0.0367, 1.0296]];
			var mai = [[0.986993, 0.432305, -0.008529],[-0.147054, 0.518360, 0.040043],[0.159963, 0.049291, 0.968487]];
			break;
		case 'von_kries':
			var ma = [[0.40024, -0.22630, 0.00000],[0.70760, 1.16532, 0.00000],[-0.08081, 0.04570, 0.91822]]
			var mai = [[1.859936, 0.361191, 0.000000],[-1.129382, 0.638812, 0.000000],[0.219897, -0.000006, 1.089064]]
			break;
		default:
			dojo.debug("The "+this.chromaticAdaptationAlg+" chromatic adaptation algorithm matricies are not defined");
	}

	var domain_src = dojo.math.matrix.multiply( [[wp_src.x, wp_src.y, wp_src.z]], ma);
	var domain_dst = dojo.math.matrix.multiply( [[wp_dst.x, wp_dst.y, wp_dst.z]], ma);

	var centre = [
		[domain_dst[0][0]/domain_src[0][0], 0, 0],
		[0, domain_dst[0][1]/domain_src[0][1], 0],
		[0, 0, domain_dst[0][2]/domain_src[0][2]]
	];

	var m = dojo.math.matrix.multiply( dojo.math.matrix.multiply( ma, centre ), mai );
	var dst = dojo.math.matrix.multiply( [[ col.X, col.Y, col.Z ]], m );
	return dst[0];
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
dojo.gfx.Colorspace.prototype.getRGB_XYZ_Matrix = function(){
	var wp = this.getWhitePoint();
	var pr = this.getPrimaries();

	var Xr = pr.xr / pr.yr;
	var Yr = 1;
	var Zr = (1 - pr.xr - pr.yr) / pr.yr;

	var Xg = pr.xg / pr.yg;
	var Yg = 1;
	var Zg = (1 - pr.xg - pr.yg) / pr.yg;

	var Xb = pr.xb / pr.yb;
	var Yb = 1;
	var Zb = (1 - pr.xb - pr.yb) / pr.yb;

	var m1 = [[Xr, Yr, Zr],[Xg, Yg, Zg],[Xb, Yb, Zb]];
	var m2 = [[wp.X, wp.Y, wp.Z]];
	var sm = dojo.math.matrix.multiply(m2, dojo.math.matrix.inverse(m1));

	var Sr = sm[0][0];
	var Sg = sm[0][1];
	var Sb = sm[0][2];

	var m4 = [[Sr*Xr, Sr*Yr, Sr*Zr],
		  [Sg*Xg, Sg*Yg, Sg*Zg],
		  [Sb*Xb, Sb*Yb, Sb*Zb]];

	return m4;
}

dojo.gfx.Colorspace.prototype.getXYZ_RGB_Matrix = function(){
	var m = this.getRGB_XYZ_Matrix();
	return dojo.math.matrix.inverse(m);
}

dojo.gfx.Colorspace.prototype.XYZ_to_Luv = function(){
	var src = this.munge('XYZ', arguments);

	var wp = this.getWhitePoint();
	var ud = (4 * src.X) / (src.X + 15 * src.Y + 3 * src.Z);
	var vd = (9 * src.Y) / (src.X + 15 * src.Y + 3 * src.Z);

	var udr = (4 * wp.X) / (wp.X + 15 * wp.Y + 3 * wp.Z);
	var vdr = (9 * wp.Y) / (wp.X + 15 * wp.Y + 3 * wp.Z);
	var yr = src.Y / wp.Y;

	var L = (yr > this.epsilon()) ? 116 * Math.pow(yr, 1/3) - 16 : this.kappa() * yr;
	var u = 13 * L * (ud-udr);
	var v = 13 * L * (vd-vdr);

	return [L, u, v];
}

dojo.gfx.Colorspace.prototype.Luv_to_XYZ = function(){
	var src = this.munge('Luv', arguments);

	var wp = this.getWhitePoint();
	var uz = (4 * wp.X) / (wp.X + 15 * wp.Y + 3 * wp.Z);
	var vz = (9 * wp.Y) / (wp.X + 15 * wp.Y + 3 * wp.Z);
	var Y = (src.L > this.kappa() * this.epsilon()) ? Math.pow((src.L + 16) / 116, 3) : src.L / this.kappa();

	var a = (1 / 3) * (((52 * src.L) / (src.u + 13 * src.L * uz)) - 1);
	var b = -5 * Y;
	var c = - (1 / 3);
	var d = Y * (((39 * src.L) / (src.v + 13 * src.L * vz)) - 5);

	var X = (d - b) / (a - c);
	var Z = X * a + b;

	return [X, Y, Z];
}

dojo.gfx.Colorspace.prototype.Luv_to_LCHuv = function(){
	var src = this.munge('Luv', arguments);

	var L = src.L;
	var C = Math.pow(src.u * src.u + src.v * src.v, 0.5);
	var H = Math.atan2(src.v, src.u) * (180 / Math.PI);

	if (H < 0){ H += 360; }
	if (H > 360){ H -= 360; }

	return [L, C, H];
}

dojo.gfx.Colorspace.prototype.LCHuv_to_Luv = function(){
	var src = this.munge('LCH', arguments);

	var H_rad = src.H * (Math.PI / 180);
	var L = src.L;
	var u = src.C / Math.pow(Math.pow(Math.tan(H_rad), 2) + 1, 0.5);
	var v = Math.pow(src.C * src.C - u * u, 0.5);

	if ((90 < src.H) && (src.H < 270)){ u *= -1; }
	if (src.H > 180){ v *= -1; }

	return [L, u, v];
}

dojo.gfx.Colorspace.colorTemp_to_whitePoint = function(T){
	if (T < 4000){
		dojo.debug("Can't find a white point for temperatures under 4000K");
		return [0,0];
	}

	if (T > 25000){
		dojo.debug("Can't find a white point for temperatures over 25000K");
		return [0,0];
	}

	var T1 = T;
	var T2 = T * T;
	var T3 = T2 * T;

	var ten9 = Math.pow(10, 9);
	var ten6 = Math.pow(10, 6);
	var ten3 = Math.pow(10, 3);

	if (T <= 7000){
		var x = (-4.6070 * ten9 / T3) + (2.9678 * ten6 / T2) + (0.09911 * ten3 / T) + 0.244063;
	}else{
		var x = (-2.0064 * ten9 / T3) + (1.9018 * ten6 / T2) + (0.24748 * ten3 / T) + 0.237040;
	}
	var y = -3.000 * x * x + 2.870 * x - 0.275;

	return [x, y];
}

dojo.gfx.Colorspace.prototype.RGB_to_CMY = function(){
	var src = this.munge('RGB', arguments);

	var C = 1 - src.R;
	var M = 1 - src.G;
	var Y = 1 - src.B;

	return [C, M, Y];
}

dojo.gfx.Colorspace.prototype.CMY_to_RGB = function(){
	var src = this.munge('CMY', arguments);

	var R = 1 - src.C;
	var G = 1 - src.M;
	var B = 1 - src.Y;

	return [R, G, B];
}

dojo.gfx.Colorspace.prototype.RGB_to_CMYK = function(){
	var src = this.munge('RGB', arguments);

	var K = Math.min(1-src.R, 1-src.G, 1-src.B);
	var C = (1 - src.R - K) / (1 - K);
	var M = (1 - src.G - K) / (1 - K);
	var Y = (1 - src.B - K) / (1 - K);

	return [C, M, Y, K];
}

dojo.gfx.Colorspace.prototype.CMYK_to_RGB = function(){
	var src = this.munge('CMYK', arguments);

	var R = 1 - Math.min(1, src.C * (1-src.K) + src.K);
	var G = 1 - Math.min(1, src.M * (1-src.K) + src.K);
	var B = 1 - Math.min(1, src.Y * (1-src.K) + src.K);

	return [R, G, B];
}

dojo.gfx.Colorspace.prototype.CMY_to_CMYK = function(){
	var src = this.munge('CMY', arguments);

	var K = Math.min(src.C, src.M, src.Y);
	var C = (src.C - K) / (1 - K);
	var M = (src.M - K) / (1 - K);
	var Y = (src.Y - K) / (1 - K);

	return [C, M, Y, K];
}

dojo.gfx.Colorspace.prototype.CMYK_to_CMY = function(){
	var src = this.munge('CMYK', arguments);

	var C = Math.min(1, src.C * (1-src.K) + src.K);
	var M = Math.min(1, src.M * (1-src.K) + src.K);
	var Y = Math.min(1, src.Y * (1-src.K) + src.K);

	return [C, M, Y];
}

dojo.gfx.Colorspace.prototype.RGB_to_HSV = function(){
	var src = this.munge('RGB', arguments);

	// Based on C Code in "Computer Graphics -- Principles and Practice,"
	// Foley et al, 1996, p. 592. 

	var min = Math.min(src.R, src.G, src.B);
	var V = Math.max(src.R, src.G, src.B);

	var delta = V - min;

	var H = null;
	var S = (V == 0) ? 0 : delta / V;

	if (S == 0){
		H = 0;
	}else{
		if (src.R == V){
			H = 60 * (src.G - src.B) / delta;
		}else{
			if (src.G == V){
				H = 120 + 60 * (src.B - src.R) / delta;
			}else{
				if (src.B == V){
					// between magenta and cyan
					H = 240 + 60 * (src.R - src.G) / delta;
				}
			}
		}
		if (H < 0){
			H += 360;
		}
	}

	H = (H == 0) ? 360 : H;

	return [H, S, V];
}

dojo.gfx.Colorspace.prototype.HSV_to_RGB = function(){
	var src = this.munge('HSV', arguments);
	if (src.H == 360){ src.H = 0;}

	// Based on C Code in "Computer Graphics -- Principles and Practice,"
	// Foley et al, 1996, p. 593.
	var r = null;
	var g = null;
	var b = null;

	if (src.S == 0){
		// color is on black-and-white center line
		// achromatic: shades of gray
		var R = src.V;
		var G = src.V;
		var B = src.V;
	}else{
		// chromatic color
		var hTemp = src.H / 60;		// h is now IN [0,6]
		var i = Math.floor(hTemp);	// largest integer <= h
		var f = hTemp - i;		// fractional part of h

		var p = src.V * (1 - src.S);
		var q = src.V * (1 - (src.S * f));
		var t = src.V * (1 - (src.S * (1 - f)));

		switch(i){
			case 0: R = src.V; G = t    ; B = p    ; break;
			case 1: R = q    ; G = src.V; B = p    ; break;
			case 2: R = p    ; G = src.V; B = t    ; break;
			case 3: R = p    ; G = q    ; B = src.V; break;
			case 4: R = t    ; G = p    ; B = src.V; break;
			case 5: R = src.V; G = p    ; B = q    ; break;
		}
	}

	return [R, G, B];
}

dojo.gfx.Colorspace.prototype.RGB_to_HSL = function(){
	var src = this.munge('RGB', arguments);

	// based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/
	var min = Math.min(src.R, src.G, src.B);
	var max = Math.max(src.R, src.G, src.B);
	var delta = max - min;

	var H = 0;
	var S = 0;
	var L = (min + max) / 2;

	if ((L > 0) && (L < 1)){
		S = delta / ((L < 0.5) ? (2 * L) : (2 - 2 * L));
	}

	if (delta > 0) {
		if ((max == src.R) && (max != src.G)){
			H += (src.G - src.B) / delta;
		}
		if ((max == src.G) && (max != src.B)){
			H += (2 + (src.B - src.R) / delta);
		}
		if ((max == src.B) && (max != src.R)){
			H += (4 + (src.R - src.G) / delta);
		}
		H *= 60;
	}
	H = (H == 0) ? 360 : H;
	return [H, S, L];
}

dojo.gfx.Colorspace.prototype.HSL_to_RGB = function(){
	var src = this.munge('HSL', arguments);

	// based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/
	while (src.H < 0){ src.H += 360; }
	while (src.H >= 360){ src.H -= 360; }

	var R = 0;
	var G = 0;
	var B = 0;

	if (src.H < 120){
		R = (120 - src.H) / 60;
		G = src.H / 60;
		B = 0;
	}else if (src.H < 240){
		R = 0;
		G = (240 - src.H) / 60;
		B = (src.H - 120) / 60;
	}else{
		R = (src.H - 240) / 60;
		G = 0;
		B = (360 - src.H) / 60;
	}

	R = 2 * src.S * Math.min(R, 1) + (1 - src.S);
	G = 2 * src.S * Math.min(G, 1) + (1 - src.S);
	B = 2 * src.S * Math.min(B, 1) + (1 - src.S);

	if (src.L < 0.5){
		R = src.L * R;
		G = src.L * G;
		B = src.L * B;
	}else{
		R = (1 - src.L) * R + 2 * src.L - 1;
		G = (1 - src.L) * G + 2 * src.L - 1;
		B = (1 - src.L) * B + 2 * src.L - 1;
	}
	return [R, G, B];
}

__CPAN_FILE__ src/gfx/vml.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.vml");

dojo.require("dojo.dom");
dojo.require("dojo.math");
dojo.require("dojo.lang.declare");
dojo.require("dojo.lang.extras");
dojo.require("dojo.string.*");
dojo.require("dojo.html.metrics");

dojo.require("dojo.gfx.color");
dojo.require("dojo.gfx.common");
dojo.require("dojo.gfx.shape");
dojo.require("dojo.gfx.path");

dojo.require("dojo.experimental");
dojo.experimental("dojo.gfx.vml");

dojo.gfx.vml.xmlns = "urn:schemas-microsoft-com:vml";

dojo.gfx.vml._parseFloat = function(str) {
	return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str);
};

dojo.gfx.vml.cm_in_pt = 72 / 2.54;
dojo.gfx.vml.mm_in_pt = 7.2 / 2.54;

dojo.gfx.vml.px_in_pt = function(){ return dojo.html.getCachedFontMeasurements()["12pt"] / 12; };

dojo.gfx.vml.pt2px = function(len){ return len * this.px_in_pt(); };
dojo.gfx.vml.px2pt = function(len){ return len / this.px_in_pt(); };

dojo.gfx.vml.normalizedLength = function(len) {
	if(len.length == 0) return 0;
	if(len.length > 2){
		var px_in_pt = this.px_in_pt();
		var val = parseFloat(len);
		switch(len.slice(-2)){
			case "px": return val;
			case "pt": return val * px_in_pt;
			case "in": return val * 72 * px_in_pt;
			case "pc": return val * 12 * px_in_pt;
			case "mm": return val / this.mm_in_pt * px_in_pt;
			case "cm": return val / this.cm_in_pt * px_in_pt;
		}
	}
	return parseFloat(len);
};

dojo.lang.extend(dojo.gfx.Shape, {
	setStroke: function(stroke){
		if(!stroke){
			// don't stroke
			this.strokeStyle = null;
			this.rawNode.stroked = false;
			return this;
		}
		// normalize the stroke
		this.strokeStyle = dojo.gfx.makeParameters(dojo.gfx.defaultStroke, stroke);
		this.strokeStyle.color = dojo.gfx.normalizeColor(this.strokeStyle.color);
		// generate attributes
		var s = this.strokeStyle;
		this.rawNode.stroked = true;
		this.rawNode.strokecolor = s.color.toCss();
		this.rawNode.strokeweight = s.width + "px";	// TODO: should we assume that the width is always in pixels?
		if(this.rawNode.stroke) {
			this.rawNode.stroke.opacity = s.color.a;
			this.rawNode.stroke.endcap = this._translate(this._capMap, s.cap);
			if(typeof(s.join) == "number") {
				this.rawNode.stroke.joinstyle = "miter";
				this.rawNode.stroke.miterlimit = s.join;
			}else{
				this.rawNode.stroke.joinstyle = s.join;
				// this.rawNode.stroke.miterlimit = s.width;
			}
		}
		return this;
	},
	
	_capMap: { butt: 'flat' },
	_capMapReversed: { flat: 'butt' },
	
	_translate: function(dict, value) {
		return (value in dict) ? dict[value] : value;
	},
	
	setFill: function(fill){
		if(!fill){
			// don't fill
			this.fillStyle = null;
			this.rawNode.filled = false;
			return this;
		}
		if(typeof(fill) == "object" && "type" in fill){
			// gradient
			switch(fill.type){
				case "linear":
					var f = dojo.gfx.makeParameters(dojo.gfx.defaultLinearGradient, fill);
					this.fillStyle = f;
					var s = "";
					for(var i = 0; i < f.colors.length; ++i){
						f.colors[i].color = dojo.gfx.normalizeColor(f.colors[i].color);
						s += f.colors[i].offset.toFixed(8) + " " + f.colors[i].color.toHex() + ";";
					}
					var fo = this.rawNode.fill;
					fo.colors.value = s;
					fo.method = "sigma";
					fo.type = "gradient";
					fo.angle = (dojo.math.radToDeg(Math.atan2(f.x2 - f.x1, f.y2 - f.y1)) + 180) % 360;
					fo.on = true;
					break;
				case "radial":
					var f = dojo.gfx.makeParameters(dojo.gfx.defaultRadialGradient, fill);
					this.fillStyle = f;
					var w = parseFloat(this.rawNode.style.width);
					var h = parseFloat(this.rawNode.style.height);
					var c = isNaN(w) ? 1 : 2 * f.r / w;
					var i = f.colors.length - 1;
					f.colors[i].color = dojo.gfx.normalizeColor(f.colors[i].color);
					var s = "0 " + f.colors[i].color.toHex();
					for(; i >= 0; --i){
						f.colors[i].color = dojo.gfx.normalizeColor(f.colors[i].color);
						s += (1 - c * f.colors[i].offset).toFixed(8) + " " + f.colors[i].color.toHex() + ";";
					}
					var fo = this.rawNode.fill;
					fo.colors.value = s;
					fo.method = "sigma";
					fo.type = "gradientradial";
					if(isNaN(w) || isNaN(h)){
						fo.focusposition = "0.5 0.5";
					}else{
						fo.focusposition = (f.cx / w).toFixed(8) + " " + (f.cy / h).toFixed(8);
					}
					fo.focussize = "0 0";
					fo.on = true;
					break;
				case "pattern":
					var f = dojo.gfx.makeParameters(dojo.gfx.defaultPattern, fill);
					this.fillStyle = f;
					var fo = this.rawNode.fill;
					fo.type = "tile";
					fo.src = f.src;
					if(f.width && f.height){
						// in points
						fo.size.x = dojo.gfx.vml.px2pt(f.width);
						fo.size.y = dojo.gfx.vml.px2pt(f.height);
					}
					fo.alignShape = false;
					fo.position.x = 0;
					fo.position.y = 0;
					fo.origin.x = f.width  ? f.x / f.width  : 0;
					fo.origin.y = f.height ? f.y / f.height : 0;
					fo.on = true;
					break;
			}
			this.rawNode.fill.opacity = 1;
			return this;
		}
		// color object
		this.fillStyle = dojo.gfx.normalizeColor(fill);
		this.rawNode.fillcolor = this.fillStyle.toHex();
		this.rawNode.fill.opacity = this.fillStyle.a;
		this.rawNode.filled = true;
		return this;
	},

	_applyTransform: function() {
		var matrix = this._getRealMatrix();
		if(!matrix) return this;
		var skew = this.rawNode.skew;
		if(typeof(skew) == "undefined"){
			for(var i = 0; i < this.rawNode.childNodes.length; ++i){
				if(this.rawNode.childNodes[i].tagName == "skew"){
					skew = this.rawNode.childNodes[i];
					break;
				}
			}
		}
		if(skew){
			skew.on = false;
			var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " + 
				matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0";
			var offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px";
			var l = parseFloat(this.rawNode.style.left);
			var t = parseFloat(this.rawNode.style.top);
			var w = parseFloat(this.rawNode.style.width);
			var h = parseFloat(this.rawNode.style.height);
			if(isNaN(l)) l = 0;
			if(isNaN(t)) t = 0;
			if(isNaN(w)) w = 1;
			if(isNaN(h)) h = 1;
			var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
			skew.matrix =  mt;
			skew.origin = origin;
			skew.offset = offset;
			skew.on = true;
		}
		return this;
	},

	setRawNode: function(rawNode){
		rawNode.stroked = false;
		rawNode.filled  = false;
		this.rawNode = rawNode;
	},

	// Attach family
	attachStroke: function(rawNode) {
		var strokeStyle = dojo.lang.shallowCopy(dojo.gfx.defaultStroke, true);
		if(rawNode && rawNode.stroked){
			strokeStyle.color = new dojo.gfx.color.Color(rawNode.strokecolor.value);
			dojo.debug("We are expecting an .75pt here, instead of strokeweight = " + rawNode.strokeweight );
			strokeStyle.width = dojo.gfx.vml.normalizedLength(rawNode.strokeweight+"");
			strokeStyle.color.a = rawNode.stroke.opacity;
			strokeStyle.cap = this._translate(this._capMapReversed, rawNode.stroke.endcap);
			strokeStyle.join = rawNode.stroke.joinstyle == "miter" ? rawNode.stroke.miterlimit : rawNode.stroke.joinstyle;
		}else{
			return null;
		}
		return strokeStyle;
	},

	attachFill: function(rawNode){
		var fillStyle = null;
		var fo = rawNode.fill;
		if(rawNode) {
			if(fo.on && fo.type == "gradient"){
				var fillStyle = dojo.lang.shallowCopy(dojo.gfx.defaultLinearGradient, true);
				var rad = dojo.math.degToRad(fo.angle);
				fillStyle.x2 = Math.cos(rad);
				fillStyle.y2 = Math.sin(rad);
				fillStyle.colors = [];
				var stops = fo.colors.value.split(";");
				for(var i = 0; i < stops.length; ++i){
					var t = stops[i].match(/\S+/g);
					if(!t || t.length != 2) continue;
					fillStyle.colors.push({offset: dojo.gfx.vml._parseFloat(t[0]), color: new dojo.gfx.color.Color(t[1])});
				}
			}else if(fo.on && fo.type == "gradientradial"){
				var fillStyle = dojo.lang.shallowCopy(dojo.gfx.defaultRadialGradient, true);
				var w = parseFloat(rawNode.style.width);
				var h = parseFloat(rawNode.style.height);
				fillStyle.cx = isNaN(w) ? 0 : fo.focusposition.x * w;
				fillStyle.cy = isNaN(h) ? 0 : fo.focusposition.y * h;
				fillStyle.r  = isNaN(w) ? 1 : w / 2;
				fillStyle.colors = [];
				var stops = fo.colors.value.split(";");
				for(var i = stops.length - 1; i >= 0; --i){
					var t = stops[i].match(/\S+/g);
					if(!t || t.length != 2) continue;
					fillStyle.colors.push({offset: dojo.gfx.vml._parseFloat(t[0]), color: new dojo.gfx.color.Color(t[1])});
				}
			}else if(fo.on && fo.type == "tile"){
				var fillStyle = dojo.lang.shallowCopy(dojo.gfx.defaultPattern, true);
				fillStyle.width  = dojo.gfx.vml.pt2px(fo.size.x); // from pt
				fillStyle.height = dojo.gfx.vml.pt2px(fo.size.y); // from pt
				fillStyle.x = fo.origin.x * fillStyle.width;
				fillStyle.y = fo.origin.y * fillStyle.height;
				fillStyle.src = fo.src;
			}else if(fo.on && rawNode.fillcolor){
				// a color object !
				fillStyle = new dojo.gfx.color.Color(rawNode.fillcolor+"");
				fillStyle.a = fo.opacity;
			}
		}
		return fillStyle;
	},

	attachTransform: function(rawNode) {
		var matrix = {};
		if(rawNode){
			var s = rawNode.skew;
			matrix.xx = s.matrix.xtox;
			matrix.xy = s.matrix.ytox;
			matrix.yx = s.matrix.xtoy;
			matrix.yy = s.matrix.ytoy;
			matrix.dx = dojo.gfx.vml.pt2px(s.offset.x);
			matrix.dy = dojo.gfx.vml.pt2px(s.offset.y);
		}
		return dojo.gfx.matrix.normalize(matrix);
	},

	attach: function(rawNode){
		if(rawNode){
			this.rawNode = rawNode;
			this.shape = this.attachShape(rawNode);
			this.fillStyle = this.attachFill(rawNode);
			this.strokeStyle = this.attachStroke(rawNode);
			this.matrix = this.attachTransform(rawNode);
		}
	}
});

dojo.declare("dojo.gfx.Group", dojo.gfx.shape.VirtualGroup, {
	add: function(shape){
		if(this != shape.getParent()){
			this.rawNode.appendChild(shape.rawNode);
			dojo.gfx.Group.superclass.add.apply(this, arguments);
		}
		return this;
	},
	remove: function(shape, silently){
		if(this == shape.getParent()){
			if(this.rawNode == shape.rawNode.parentNode){
				this.rawNode.removeChild(shape.rawNode);
			}
			dojo.gfx.Group.superclass.remove.apply(this, arguments);
		}
		return this;
	},
	attach: function(rawNode){
		if(rawNode){
			this.rawNode = rawNode;
			this.shape = null;
			this.fillStyle = null;
			this.strokeStyle = null;
			this.matrix = null;
		}
	}
});
dojo.gfx.Group.nodeType = "group";

var zIndex = {
	moveToFront: function(){
		this.rawNode.parentNode.appendChild(this.rawNode);
		return this;
	},
	moveToBack: function(){
		this.rawNode.parentNode.insertBefore(this.rawNode, this.rawNode.parentNode.firstChild);
		return this;
	}
};
dojo.lang.extend(dojo.gfx.Shape, zIndex);
dojo.lang.extend(dojo.gfx.Group, zIndex);
delete zIndex;

dojo.declare("dojo.gfx.Rect", dojo.gfx.shape.Rect, {
	setShape: function(newShape){
		var shape = this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		var style = this.rawNode.style;
		style.left   = shape.x.toFixed();
		style.top    = shape.y.toFixed();
		style.width  = (typeof(shape.width) == "string" && shape.width.indexOf("%") >= 0)  ? shape.width  : shape.width.toFixed();
		style.height = (typeof(shape.width) == "string" && shape.height.indexOf("%") >= 0) ? shape.height : shape.height.toFixed();
		var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8);
		// a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
		var parent = this.rawNode.parentNode;
		var before = null;
		if(parent){
			if(parent.lastChild != this.rawNode){
				for(var i = 0; i < parent.childNodes.length; ++i){
					if(parent.childNodes[i] == this.rawNode){
						before = parent.childNodes[i+1];
						break;
					}
				}
			}
			parent.removeChild(this.rawNode);
		}
		this.rawNode.arcsize = r;
		if(parent){
			if(before){
				parent.insertBefore(this.rawNode, before);
			}else{
				parent.appendChild(this.rawNode);
			}
		}
		return this.setTransform(this.matrix);
	},
	attachShape: function(rawNode){
		// a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
		var arcsize = rawNode.outerHTML.match(/arcsize = \"(\d*\.?\d+[%f]?)\"/)[1];
		arcsize = (arcsize.indexOf("%") >= 0) ? parseFloat(arcsize) / 100 : dojo.gfx.vml._parseFloat(arcsize);
		var style = rawNode.style;
		var width  = parseFloat(style.width);
		var height = parseFloat(style.height);
		// make an object
		return dojo.gfx.makeParameters(dojo.gfx.defaultRect, {
			x: parseInt(style.left),
			y: parseInt(style.top),
			width:  width,
			height: height,
			r: Math.min(width, height) * arcsize
		});
	}
});
dojo.gfx.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected

dojo.declare("dojo.gfx.Ellipse", dojo.gfx.shape.Ellipse, {
	setShape: function(newShape){
		var shape = this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		var style = this.rawNode.style;
		style.left   = (shape.cx - shape.rx).toFixed();
		style.top    = (shape.cy - shape.ry).toFixed();
		style.width  = (shape.rx * 2).toFixed();
		style.height = (shape.ry * 2).toFixed();
		return this.setTransform(this.matrix);
	},
	attachShape: function(rawNode){
		var style = this.rawNode.style;
		var rx = parseInt(style.width ) / 2;
		var ry = parseInt(style.height) / 2;
		return dojo.gfx.makeParameters(dojo.gfx.defaultEllipse, {
			cx: parseInt(style.left) + rx,
			cy: parseInt(style.top ) + ry,
			rx: rx,
			ry: ry
		});
	}
});
dojo.gfx.Ellipse.nodeType = "oval";

dojo.declare("dojo.gfx.Circle", dojo.gfx.shape.Circle, {
	setShape: function(newShape){
		var shape = this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		var style = this.rawNode.style;
		style.left   = (shape.cx - shape.r).toFixed();
		style.top    = (shape.cy - shape.r).toFixed();
		style.width  = (shape.r * 2).toFixed();
		style.height = (shape.r * 2).toFixed();
		return this;
	},
	attachShape: function(rawNode){
		var style = this.rawNode.style;
		var r = parseInt(style.width) / 2;
		return dojo.gfx.makeParameters(dojo.gfx.defaultCircle, {
			cx: parseInt(style.left) + r,
			cy: parseInt(style.top)  + r,
			r:  r
		});
	}
});
dojo.gfx.Circle.nodeType = "oval";

dojo.declare("dojo.gfx.Line", dojo.gfx.shape.Line,
	function(rawNode){
		if(rawNode) rawNode.setAttribute("dojoGfxType", "line");
	}, {
	setShape: function(newShape){
		var shape = this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() +
			"l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e";
		return this.setTransform(this.matrix);
	},
	attachShape: function(rawNode){
		var p = rawNode.path.v.match(dojo.gfx.pathRegExp);
		var shape = {};
		do{
			if(p.length < 7 || p[0] != "m" || p[3] != "l" || p[6] != "e") break;
			shape.x1 = parseInt(p[1]);
			shape.y1 = parseInt(p[2]);
			shape.x2 = parseInt(p[4]);
			shape.y2 = parseInt(p[5]);
		}while(false);
		return dojo.gfx.makeParameters(dojo.gfx.defaultLine, shape);
	}
});
dojo.gfx.Line.nodeType = "shape";

dojo.declare("dojo.gfx.Polyline", dojo.gfx.shape.Polyline,
	function(rawNode){
		if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline");
	}, {
	setShape: function(points, closed){
		if(points && points instanceof Array){
			this.shape = dojo.gfx.makeParameters(this.shape, { points: points });
			if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]);
		}else{
			this.shape = dojo.gfx.makeParameters(this.shape, points);
		}
		this.bbox = null;
		var attr = [];
		var p = this.shape.points;
		if(p.length > 0){
			attr.push("m");
			attr.push(p[0].x.toFixed());
			attr.push(p[0].y.toFixed());
			if(p.length > 1){
				attr.push("l");
				for(var i = 1; i < p.length; ++i){
					attr.push(p[i].x.toFixed());
					attr.push(p[i].y.toFixed());
				}
			}
		}
		attr.push("e");
		this.rawNode.path.v = attr.join(" ");
		return this.setTransform(this.matrix);
	},
	attachShape: function(rawNode){
		var shape = dojo.lang.shallowCopy(dojo.gfx.defaultPolyline, true);
		var p = rawNode.path.v.match(dojo.gfx.pathRegExp);
		do{
			if(p.length < 3 || p[0] != "m") break;
			var x = parseInt(p[0]);
			var y = parseInt(p[1]);
			if(isNaN(x) || isNaN(y)) break;
			shape.points.push({x: x, y: y});
			if(p.length < 6 || p[3] != "l") break;
			for(var i = 4; i < p.length; i += 2){
				x = parseInt(p[i]);
				y = parseInt(p[i + 1]);
				if(isNaN(x) || isNaN(y)) break;
				shape.points.push({x: x, y: y});
			}
		}while(false);
		return shape;
	}
});
dojo.gfx.Polyline.nodeType = "shape";

dojo.declare("dojo.gfx.Image", dojo.gfx.shape.Image, {
	getEventSource: function() {
		return this.rawNode ? this.rawNode.firstChild : null;
	},
	setShape: function(newShape){
		var shape = this.shape = dojo.gfx.makeParameters(this.shape, newShape);
		this.bbox = null;
		var firstChild = this.rawNode.firstChild;
        firstChild.src = shape.src;
        if(shape.width || shape.height){
			firstChild.style.width  = shape.width;
			firstChild.style.height = shape.height;
        }
		return this.setTransform(this.matrix);
	},
	setStroke: function() { return this; },
	setFill:   function() { return this; },
	attachShape: function(rawNode){
		var shape = dojo.lang.shallowCopy(dojo.gfx.defaultImage, true);
		shape.src = rawNode.firstChild.src;
		return shape;
	},
	attachStroke: function(rawNode){ return null; },
	attachFill:   function(rawNode){ return null; },
	attachTransform: function(rawNode) {
		var matrix = {};
		if(rawNode){
			var m = rawNode.filters["DXImageTransform.Microsoft.Matrix"];
			matrix.xx = m.M11;
			matrix.xy = m.M12;
			matrix.yx = m.M21;
			matrix.yy = m.M22;
			matrix.dx = m.Dx;
			matrix.dy = m.Dy;
		}
		return dojo.gfx.matrix.normalize(matrix);
	},
	_applyTransform: function() {
		var matrix = this._getRealMatrix();
		if(!matrix) return this;
		with(this.rawNode.filters["DXImageTransform.Microsoft.Matrix"]){
			M11 = matrix.xx;
			M12 = matrix.xy;
			M21 = matrix.yx;
			M22 = matrix.yy;
			Dx  = matrix.dx;
			Dy  = matrix.dy;
		}
		return this;
	}
});
dojo.gfx.Image.nodeType = "image";

dojo.gfx.path._calcArc = function(alpha){
	var cosa  = Math.cos(alpha);
	var sina  = Math.sin(alpha);
	// return a start point, 1st and 2nd control points, and an end point
	var p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina};
	return {
		s:  {x: cosa, y: sina},
		c1: p2,
		c2: {x: p2.x, y: -p2.y},
		e:  {x: cosa, y: -sina}
	};
};

dojo.declare("dojo.gfx.Path", dojo.gfx.path.Path,
	function(rawNode){
		if(rawNode) rawNode.setAttribute("dojoGfxType", "path");
		this.vmlPath = "";
		this.lastControl = {};
	}, {
	_updateWithSegment: function(segment){
		var last = dojo.lang.shallowCopy(this.last);
		dojo.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
		// add a VML path segment
		var path = this[this.renderers[segment.action]](segment, last);
		if(typeof(this.vmlPath) == "string"){
			this.vmlPath += path.join("");
		}else{
			this.vmlPath = this.vmlPath.concat(path);
		}
		if(typeof(this.vmlPath) == "string"){
			this.rawNode.path.v = this.vmlPath + " e";
		}
	},
	setShape: function(newShape){
		this.vmlPath = [];
		this.lastControl = {};
		dojo.gfx.Path.superclass.setShape.apply(this, arguments);
		this.vmlPath = this.vmlPath.join("");
		this.rawNode.path.v = this.vmlPath + " e";
		return this;
	},
	_pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""},
	attachShape: function(rawNode){
		var shape = dojo.lang.shallowCopy(dojo.gfx.defaultPath, true);
		var p = rawNode.path.v.match(dojo.gfx.pathRegExp);
		var t = [], skip = false;
		for(var i = 0; i < p.length; ++p){
			var s = p[i];
			if(s in this._pathVmlToSvgMap) {
				skip = false;
				t.push(this._pathVmlToSvgMap[s]);
			} else if(!skip){
				var n = parseInt(s);
				if(isNaN(n)){
					skip = true;
				}else{
					t.push(n);
				}
			}
		}
		if(t.length) shape.path = t.join(" ");
		return shape;
	},
	// VML-specific segment renderers
	renderers: {
		M: "_moveToA", m: "_moveToR", 
		L: "_lineToA", l: "_lineToR", 
		H: "_hLineToA", h: "_hLineToR", 
		V: "_vLineToA", v: "_vLineToR", 
		C: "_curveToA", c: "_curveToR", 
		S: "_smoothCurveToA", s: "_smoothCurveToR", 
		Q: "_qCurveToA", q: "_qCurveToR", 
		T: "_qSmoothCurveToA", t: "_qSmoothCurveToR", 
		A: "_arcTo", a: "_arcTo", 
		Z: "_closePath", z: "_closePath"
	},
	_addArgs: function(path, args, from, upto){
		if(typeof(upto) == "undefined"){
			upto = args.length;
		}
		if(typeof(from) == "undefined"){
			from = 0;
		}
		for(var i = from; i < upto; ++i){
			path.push(" ");
			path.push(args[i].toFixed());
		}
	},
	_addArgsAdjusted: function(path, last, args, from, upto){
		if(typeof(upto) == "undefined"){
			upto = args.length;
		}
		if(typeof(from) == "undefined"){
			from = 0;
		}
		for(var i = from; i < upto; i += 2){
			path.push(" ");
			path.push((last.x + args[i]).toFixed());
			path.push(" ");
			path.push((last.y + args[i + 1]).toFixed());
		}
	},
	_moveToA: function(segment){
		var p = [" m"];
		var n = segment.args;
		var l = n.length;
		if(l == 2){
			this._addArgs(p, n);
		}else{
			this._addArgs(p, n, 0, 2);
			p.push(" l");
			this._addArgs(p, n, 2);
		}
		this.lastControl = {};
		return p;
	},
	_moveToR: function(segment, last){
		var p = ["x" in last ? " t" : " m"];
		var n = segment.args;
		var l = n.length;
		if(l == 2){
			this._addArgs(p, n);
		}else{
			this._addArgs(p, n, 0, 2);
			p.push(" r");
			this._addArgs(p, n, 2);
		}
		this.lastControl = {};
		return p;
	},
	_lineToA: function(segment){
		var p = [" l"];
		this._addArgs(p, segment.args);
		this.lastControl = {};
		return p;
	},
	_lineToR: function(segment){
		var p = [" r"];
		this._addArgs(p, segment.args);
		this.lastControl = {};
		return p;
	},
	_hLineToA: function(segment, last){
		var p = [" l"];
		var n = segment.args;
		var l = n.length;
		var y = " " + last.y.toFixed();
		for(var i = 0; i < l; ++i){
			p.push(" ");
			p.push(n[i].toFixed());
			p.push(y);
		}
		this.lastControl = {};
		return p;
	},
	_hLineToR: function(segment){
		var p = [" r"];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; ++i){
			p.push(" ");
			p.push(n[i].toFixed());
			p.push(" 0");
		}
		this.lastControl = {};
		return p;
	},
	_vLineToA: function(segment, last){
		var p = [" l"];
		var n = segment.args;
		var l = n.length;
		var x = " " + last.x.toFixed();
		for(var i = 0; i < l; ++i){
			p.push(x);
			p.push(" ");
			p.push(n[i].toFixed());
		}
		this.lastControl = {};
		return p;
	},
	_vLineToR: function(segment){
		var p = [" r"];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; ++i){
			p.push(" 0 ");
			p.push(n[i].toFixed());
		}
		this.lastControl = {};
		return p;
	},
	_curveToA: function(segment){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 6){
			p.push(" c");
			this._addArgs(p, n, i, i + 6);
		}
		this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"};
		return p;
	},
	_curveToR: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 6){
			p.push(" v");
			this._addArgs(p, n, i, i + 6);
			this.lastControl = {x: last.x + n[i + 2], y: last.y + n[i + 3]};
			last.x += n[i + 4];
			last.y += n[i + 5];
		}
		this.lastControl.type = "C";
		return p;
	},
	_smoothCurveToA: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 4){
			p.push(" c");
			if(this.lastControl.type == "C"){
				this._addArgs(p, [
					2 * last.x - this.lastControl.x, 
					2 * last.y - this.lastControl.y
				]);
			}else{
				this._addArgs(p, [last.x, last.y]);
			}
			this._addArgs(p, n, i, i + 4);
		}
		this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"};
		return p;
	},
	_smoothCurveToR: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 4){
			p.push(" v");
			if(this.lastControl.type == "C"){
				this._addArgs(p, [
					last.x - this.lastControl.x, 
					last.y - this.lastControl.y
				]);
			}else{
				this._addArgs(p, [0, 0]);
			}
			this._addArgs(p, n, i, i + 4);
			this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]};
			last.x += n[i + 2];
			last.y += n[i + 3];
		}
		this.lastControl.type = "C";
		return p;
	},
	_qCurveToA: function(segment){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 4){
			p.push(" qb");
			this._addArgs(p, n, i, i + 4);
		}
		this.lastControl = {x: n[l - 4], y: n[l - 3], type: "Q"};
		return p;
	},
	_qCurveToR: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 4){
			p.push(" qb");
			this._addArgsAdjusted(p, last, n, i, i + 4);
			this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]};
			last.x += n[i + 2];
			last.y += n[i + 3];
		}
		this.lastControl.type = "Q";
		return p;
	},
	_qSmoothCurveToA: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 2){
			p.push(" qb");
			if(this.lastControl.type == "Q"){
				this._addArgs(p, [
					this.lastControl.x = 2 * last.x - this.lastControl.x, 
					this.lastControl.y = 2 * last.y - this.lastControl.y
				]);
			}else{
				this._addArgs(p, [
					this.lastControl.x = last.x, 
					this.lastControl.y = last.y
				]);
			}
			this._addArgs(p, n, i, i + 2);
		}
		this.lastControl.type = "Q";
		return p;
	},
	_qSmoothCurveToR: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		for(var i = 0; i < l; i += 2){
			p.push(" qb");
			if(this.lastControl.type == "Q"){
				this._addArgs(p, [
					this.lastControl.x = 2 * last.x - this.lastControl.x, 
					this.lastControl.y = 2 * last.y - this.lastControl.y
				]);
			}else{
				this._addArgs(p, [
					this.lastControl.x = last.x, 
					this.lastControl.y = last.y
				]);
			}
			this._addArgsAdjusted(p, last, n, i, i + 2);
		}
		this.lastControl.type = "Q";
		return p;
	},
	_PI4: Math.PI / 4,
	_curvePI4: dojo.gfx.path._calcArc(Math.PI / 8),
	_calcArcTo: function(path, last, rx, ry, xRotg, large, cw, x, y){
		var m = dojo.gfx.matrix;
		// calculate parameters
		var xRot = -dojo.math.degToRad(xRotg);
		var rx2 = rx * rx;
		var ry2 = ry * ry;
		var pa = m.multiplyPoint(
			m.rotate(-xRot), 
			{x: (last.x - x) / 2, y: (last.y - y) / 2}
		);
		var pax2 = pa.x * pa.x;
		var pay2 = pa.y * pa.y;
		var c1 = Math.sqrt((rx2 * ry2 - rx2 * pay2 - ry2 * pax2) / (rx2 * pay2 + ry2 * pax2));
		var ca = {
			x:  c1 * rx * pa.y / ry,
			y: -c1 * ry * pa.x / rx
		};
		if(large == cw){
			ca = {x: -ca.x, y: -ca.y};
		}
		// our center
		var c = m.multiplyPoint(
			[
				m.translate(
					(last.x + x) / 2,
					(last.y + y) / 2
				),
				m.rotate(xRot)
			], 
			ca
		);
		// start of our arc
		var startAngle = Math.atan2(c.y - last.y, last.x - c.x) - xRot;
		var endAngle   = Math.atan2(c.y - y, x - c.x) - xRot;
		// size of our arc in radians
		var theta = cw ? startAngle - endAngle : endAngle - startAngle;
		if(theta < 0){
			theta += this._2PI;
		}else if(theta > this._2PI){
			theta = this._2PI;
		}
		// calculate our elliptic transformation
		var elliptic_transform = m.normalize([
			m.translate(c.x, c.y),
			m.rotate(xRot),
			m.scale(rx, ry)
		]);
		// draw curve chunks
		var alpha = this._PI4 / 2;
		var curve = this._curvePI4;
		var step  = cw ? -alpha : alpha;
		for(var angle = theta; angle > 0; angle -= this._PI4){
			if(angle < this._PI4){
				alpha = angle / 2;
				curve = dojo.gfx.path._calcArc(alpha);
				step  = cw ? -alpha : alpha;
			}
			var c1, c2, e;
			var M = m.normalize([elliptic_transform, m.rotate(startAngle + step)]);
			if(cw){
				c1 = m.multiplyPoint(M, curve.c2);
				c2 = m.multiplyPoint(M, curve.c1);
				e  = m.multiplyPoint(M, curve.s );
			}else{
				c1 = m.multiplyPoint(M, curve.c1);
				c2 = m.multiplyPoint(M, curve.c2);
				e  = m.multiplyPoint(M, curve.e );
			}
			// draw the curve
			path.push(" c");
			this._addArgs(path, [c1.x, c1.y, c2.x, c2.y, e.x, e.y]);
			startAngle += 2 * step;
		}
	},
	_arcTo: function(segment, last){
		var p = [];
		var n = segment.args;
		var l = n.length;
		var relative = segment.action == "a";
		for(var i = 0; i < l; i += 7){
			var x1 = n[i + 5];
			var y1 = n[i + 6];
			if(relative){
				x1 += last.x;
				y1 += last.y;
			}
			this._calcArcTo(
				p, last, n[i], n[i + 1], n[i + 2], 
				n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0,
				x1, y1
			);
			last = {x: x1, y: y1};
		}
		this.lastControl = {};
		return p;
	},
	_closePath: function(){
		this.lastControl = {};
		return ["x"];
	}
});
dojo.gfx.Path.nodeType = "shape";


dojo.gfx._creators = {
	createRect: function(rect){
		return this.createObject(dojo.gfx.Rect, rect);
	},
	createEllipse: function(ellipse){
		return this.createObject(dojo.gfx.Ellipse, ellipse);
	},
	createCircle: function(circle){
		return this.createObject(dojo.gfx.Circle, circle);
	},
	createLine: function(line){
		return this.createObject(dojo.gfx.Line, line, true);
	},
	createPolyline: function(points){
		return this.createObject(dojo.gfx.Polyline, points, true);
	},
	createPath: function(path){
		return this.createObject(dojo.gfx.Path, path, true);
	},
	createGroup: function(path){
		return this.createObject(dojo.gfx.Group, null, true);
	},
	createImage: function(image){
		if(!this.rawNode) return null;
		var shape = new dojo.gfx.Image();
		var node = document.createElement('div');
		node.style.position = "relative";
		node.style.width  = this.rawNode.style.width;
		node.style.height = this.rawNode.style.height;
		node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, Dx=0, Dy=0)";
		var img  = document.createElement('img');
		node.appendChild(img);
		shape.setRawNode(node);
		this.rawNode.appendChild(node);
		shape.setShape(image);
		this.add(shape);
		return shape;
	},
	createObject: function(shapeType, rawShape, overrideSize) {
		if(!this.rawNode) return null;
		var shape = new shapeType();
		var node = document.createElement('v:' + shapeType.nodeType);
		shape.setRawNode(node);
		this.rawNode.appendChild(node);
		if(overrideSize) this._overrideSize(node);
		shape.setShape(rawShape);
		this.add(shape);
		return shape;
	},
	_overrideSize: function(node){
		node.style.width  = this.rawNode.style.width;
		node.style.height = this.rawNode.style.height;
		node.coordsize = parseFloat(node.style.width) + " " + parseFloat(node.style.height);
	}
};

dojo.lang.extend(dojo.gfx.Group, dojo.gfx._creators);
dojo.lang.extend(dojo.gfx.Surface, dojo.gfx._creators);

delete dojo.gfx._creators;

dojo.gfx.attachNode = function(node){
	if(!node) return null;
	var s = null;
	switch(node.tagName.toLowerCase()){
		case dojo.gfx.Rect.nodeType:
			s = new dojo.gfx.Rect();
			break;
		case dojo.gfx.Ellipse.nodeType:
			s = (node.style.width == node.style.height)
				? new dojo.gfx.Circle()
				: new dojo.gfx.Ellipse();
			break;
		case dojo.gfx.Path.nodeType:
			switch(node.getAttribute("dojoGfxType")){
				case "line":
					s = new dojo.gfx.Line();
					break;
				case "polyline":
					s = new dojo.gfx.Polyline();
					break;
				case "path":
					s = new dojo.gfx.Path();
					break;
			}
			break;
		case dojo.gfx.Image.nodeType:
			s = new dojo.gfx.Image();
			break;
		default:
			dojo.debug("FATAL ERROR! tagName = " + node.tagName);
	}
	s.attach(node);
	return s;
};

dojo.lang.extend(dojo.gfx.Surface, {
	setDimensions: function(width, height){
		if(!this.rawNode) return this;
		this.rawNode.style.width = width;
		this.rawNode.style.height = height;
		this.rawNode.coordsize = width + " " + height;
		return this;
	},
	getDimensions: function(){
		return this.rawNode ? { width: this.rawNode.style.width, height: this.rawNode.style.height } : null;
	},
	// group control
	add: function(shape){
		var oldParent = shape.getParent();
		if(this != oldParent){
			this.rawNode.appendChild(shape.rawNode);
			if(oldParent){
				oldParent.remove(shape, true);
			}
			shape._setParent(this, null);
		}
		return this;
	},
	remove: function(shape, silently){
		if(this == shape.getParent()){
			if(this.rawNode == shape.rawNode.parentNode){
				this.rawNode.removeChild(shape.rawNode);
			}
			shape._setParent(null, null);
		}
		return this;
	}
});

dojo.gfx.createSurface = function(parentNode, width, height){
	var s = new dojo.gfx.Surface();
	s.rawNode = document.createElement("v:group");
	s.rawNode.style.width  = width  ? width  : "100%";
	s.rawNode.style.height = height ? height : "100%";
	s.rawNode.coordsize = (width && height)
		? (parseFloat(width) + " " + parseFloat(height))
		: "100% 100%";
	s.rawNode.coordorigin = "0 0";
	dojo.byId(parentNode).appendChild(s.rawNode);
	return s;
};

dojo.gfx.attachSurface = function(node){
	var s = new dojo.gfx.Surface();
	s.rawNode = node;
	return s;
};

__CPAN_FILE__ src/gfx/path.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.path");

dojo.require("dojo.math");

dojo.require("dojo.gfx.shape");

dojo.declare("dojo.gfx.path.Path", dojo.gfx.Shape, {
	// summary:
	//		a path shape
	initializer: function(/* Node */ rawNode){
		// summary: a constructor of a path shape object
		// rawNode: a DOM node to be used by this path object
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultPath, true);
		this.segments = [];
		this.absolute = true;
		this.last = {};
		this.attach(rawNode);
	},
	
	// mode manipulations
	setAbsoluteMode: function(/* Boolean||String */ mode){
		// summary: sets an absolute or relative mode for path points
		// mode: true/false or "absolute"/"relative" to specify the mode
		this.absolute = typeof(mode) == "string" ? (mode == "absolute") : mode;
		return this; // self
	},
	getAbsoluteMode: function(){
		// summary: returns a current value of the absolute mode
		return this.absolute; // Boolean
	},
	getBoundingBox: function(){
		// summary: returns a bounding box {x, y, width, height} or null
		return "l" in this.bbox ? {x: this.bbox.l, y: this.bbox.t, width: this.bbox.r - this.bbox.l, height: this.bbox.b - this.bbox.t} : null; // Object
	},
	getLastPosition: function(){
		// summary: returns the last point in the path, or null
		return "x" in this.last ? this.last : null; // Object
	},
	
	// segment interpretation
	_updateBBox: function(/* Number */ x, /* Number */ y){
		// summary: updates a bounding box of path with new point
		
		// we use {l, b, r, t} representation of a bbox
		if("l" in this.bbox){
			if(this.bbox.l > x) this.bbox.l = x;
			if(this.bbox.r < x) this.bbox.r = x;
			if(this.bbox.t > y) this.bbox.t = y;
			if(this.bbox.b < y) this.bbox.b = y;
		}else{
			this.bbox = {l: x, b: y, r: x, t: y};
		}
	},
	_updateWithSegment: function(/* Object */ segment){
		// summary: updates a bounding box of path with new segment
		var n = segment.args;
		var l = n.length;
		// update internal variables: bbox, absolute, last
		switch(segment.action){
			case "M":
			case "L":
			case "C":
			case "S":
			case "Q":
			case "T":
				for(var i = 0; i < l; i += 2){
					this._updateBBox(this.bbox, n[i], n[i + 1]);
				}
				this.last.x = n[l - 2];
				this.last.y = n[l - 1];
				this.absolute = true;
				break;
			case "H":
				for(var i = 0; i < l; ++i){
					this._updateBBox(this.bbox, n[i], this.last.y);
				}
				this.last.x = n[l - 1];
				this.absolute = true;
				break;
			case "V":
				for(var i = 0; i < l; ++i){
					this._updateBBox(this.bbox, this.last.x, n[i]);
				}
				this.last.y = n[l - 1];
				this.absolute = true;
				break;
			case "m":
				var start = 0;
				if(!("x" in this.last)){
					this._updateBBox(this.bbox, this.last.x = n[0], this.last.y = n[1]);
					start = 2;
				}
				for(var i = start; i < l; i += 2){
					this._updateBBox(this.bbox, this.last.x += n[i], this.last.y += n[i + 1]);
				}
				this.absolute = false;
				break;
			case "l":
			case "t":
				for(var i = 0; i < l; i += 2){
					this._updateBBox(this.bbox, this.last.x += n[i], this.last.y += n[i + 1]);
				}
				this.absolute = false;
				break;
			case "h":
				for(var i = 0; i < l; ++i){
					this._updateBBox(this.bbox, this.last.x += n[i], this.last.y);
				}
				this.absolute = false;
				break;
			case "v":
				for(var i = 0; i < l; ++i){
					this._updateBBox(this.bbox, this.last.x, this.last.y += n[i]);
				}
				this.absolute = false;
				break;
			case "c":
				for(var i = 0; i < l; i += 6){
					this._updateBBox(this.bbox, this.last.x + n[i], this.last.y + n[i + 1]);
					this._updateBBox(this.bbox, this.last.x + n[i + 2], this.last.y + n[i + 3]);
					this._updateBBox(this.bbox, this.last.x += n[i + 4], this.last.y += n[i + 5]);
				}
				this.absolute = false;
				break;
			case "s":
			case "q":
				for(var i = 0; i < l; i += 4){
					this._updateBBox(this.bbox, this.last.x + n[i], this.last.y + n[i + 1]);
					this._updateBBox(this.bbox, this.last.x += n[i + 2], this.last.y += n[i + 3]);
				}
				this.absolute = false;
				break;
			case "A":
				for(var i = 0; i < l; i += 7){
					this._updateBBox(this.bbox, n[i + 5], n[i + 6]);
				}
				this.last.x = n[l - 2];
				this.last.y = n[l - 1];
				this.absolute = true;
				break;
			case "a":
				for(var i = 0; i < l; i += 7){
					this._updateBBox(this.bbox, this.last.x += n[i + 5], this.last.y += n[i + 6]);
				}
				this.absolute = false;
				break;
		}
		// add an SVG path segment
		var path = [segment.action];
		for(var i = 0; i < l; ++i){
			path.push(dojo.gfx.formatNumber(n[i], true));
		}
		if(typeof(this.shape.path) == "string"){
			this.shape.path += path.join("");
		}else{
			this.shape.path = this.shape.path.concat(path);
		}
	},
	// a dictionary, which maps segment type codes to a number of their argemnts
	_validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0},
	_pushSegment: function(/* String */ action, /* Array */ args){
		// summary: adds a segment
		// action: valid SVG code for a segment's type
		// args: a list of parameters for this segment
		var group = this._validSegments[action.toLowerCase()];
		if(typeof(group) == "number"){
			if(group){
				if(args.length >= group){
					var segment = {action: action, args: args.slice(0, args.length - args.length % group)};
					this.segments.push(segment);
					this._updateWithSegment(segment);
				}
			}else{
				var segment = {action: action, args: []};
				this.segments.push(segment);
				this._updateWithSegment(segment);
			}
		}
	},
	_collectArgs: function(/* Array */ array, /* Array */ args){
		// summary: converts an array of arguments to plain numeric values
		for(var i = 0; i < args.length; ++i){
			var t = args[i];
			if(typeof(t) == "boolean"){
				array.push(t ? 1 : 0);
			}else if(typeof(t) == "number"){
				array.push(t);
			}else if(t instanceof Array){
				this._collectArgs(array, t);
			}else if("x" in t && "y" in t){
				array.push(t.x);
				array.push(t.y);
			}
		}
	},

	// segments	
	moveTo: function(){
		// summary: formes a move segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "M" : "m", args);
		return this; // self
	},
	lineTo: function(){
		// summary: formes a line segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "L" : "l", args);
		return this; // self
	},
	hLineTo: function(){
		// summary: formes a horizontal line segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "H" : "h", args);
		return this; // self
	},
	vLineTo: function(){
		// summary: formes a vertical line segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "V" : "v", args);
		return this; // self
	},
	curveTo: function(){
		// summary: formes a curve segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "C" : "c", args);
		return this; // self
	},
	smoothCurveTo: function(){
		// summary: formes a smooth curve segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "S" : "s", args);
		return this; // self
	},
	qCurveTo: function(){
		// summary: formes a quadratic curve segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "Q" : "q", args);
		return this; // self
	},
	qSmoothCurveTo: function(){
		// summary: formes a quadratic smooth curve segment
		var args = [];
		this._collectArgs(args, arguments);
		this._pushSegment(this.absolute ? "T" : "t", args);
		return this; // self
	},
	arcTo: function(){
		// summary: formes an elliptic arc segment
		var args = [];
		this._collectArgs(args, arguments);
		for(var i = 2; i < args.length; i += 7){
			args[i] = -args[i];
		}
		this._pushSegment(this.absolute ? "A" : "a", args);
		return this; // self
	},
	closePath: function(){
		// summary: closes a path
		this._pushSegment("Z", []);
		return this; // self
	},
	
	// setShape
	_setPath: function(path){
		// summary: forms a path using an SVG path string
		var p = path.match(dojo.gfx.pathRegExp);
		this.segments = [];
		this.absolute = true;
		this.bbox = {};
		this.last = {};
		if(!p) return;
		// create segments
		var action = "";	// current action
		var args = [];		// current arguments
		for(var i = 0; i < p.length; ++i){
			var t = p[i];
			var x = parseFloat(t);
			if(isNaN(x)){
				if(action){
					this._pushSegment(action, args);
				}
				args = [];
				action = t;
			}else{
				args.push(x);
			}
		}
		this._pushSegment(action, args);
	},
	setShape: function(newShape){
		// summary: forms a path using a shape
		this.shape = dojo.gfx.makeParameters(this.shape, typeof(newShape) == "string" ? {path: newShape} : newShape);
		var path = this.shape.path;
		// switch to non-updating version of path building
		this.shape.path = [];
		this._setPath(path);
		// switch back to the string path
		this.shape.path = this.shape.path.join("");
		return this; // self
	},
	
	_2PI: Math.PI * 2 // useful constant for descendants
});

__CPAN_FILE__ src/gfx/shape.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.shape");

dojo.require("dojo.lang.declare");

dojo.require("dojo.gfx.common");

// this is a Shape object, which knows how to apply graphical attributes and a transformation
dojo.declare("dojo.gfx.Shape", null, {

	initializer: function(){
		// underlying node
		this.rawNode = null;
		// abstract shape object
		this.shape = null;
		// transformation matrix
		this.matrix  = null;
		// graphical attributes
		this.fillStyle   = null;
		this.strokeStyle = null;
		// virtual group structure
		this.parent = null;
		this.parentMatrix = null;
		// bounding box
		this.bbox = null;
	},

	// trivial getters
	getNode:        function(){ return this.rawNode; },
	getShape:       function(){ return this.shape; },
	getTransform:   function(){ return this.matrix; },
	getFill:        function(){ return this.fillStyle; },
	getStroke:      function(){ return this.strokeStyle; },
	getParent:      function(){ return this.parent; },
	getBoundingBox: function(){ return this.bbox; },
	getEventSource: function(){ return this.rawNode; },
	
	// empty settings
	setShape:  function(shape) { return this; },	// ignore
	setStroke: function(stroke){ return this; },	// ignore
	setFill:   function(fill)  { return this; },	// ignore
	
	// z-index
	moveToFront: function(){ return this; },		// ignore
	moveToBack:  function(){ return this; },		// ignore

	// apply transformations
	setTransform: function(matrix){
		this.matrix = dojo.gfx.matrix.clone(matrix ? dojo.gfx.matrix.normalize(matrix) : dojo.gfx.identity, true);
		return this._applyTransform();
	},
	
	// apply left & right transformation
	applyRightTransform: function(matrix){
		return matrix ? this.setTransform([this.matrix, matrix]) : this;
	},
	applyLeftTransform: function(matrix){
		return matrix ? this.setTransform([matrix, this.matrix]) : this;
	},

	// a shortcut for apply-right
	applyTransform: function(matrix){
		return matrix ? this.setTransform([this.matrix, matrix]) : this;
	},
	
	// virtual group methods
	remove: function(silently){
		if(this.parent){
			this.parent.remove(this, silently);
		}
		return this;
	},
	_setParent: function(parent, matrix){
		this.parent = parent;
		return this._updateParentMatrix(matrix);
	},
	_updateParentMatrix: function(matrix){
		this.parentMatrix = matrix ? dojo.gfx.matrix.clone(matrix) : null;
		return this._applyTransform();
	},
	_getRealMatrix: function(){
		return this.parentMatrix ? new dojo.gfx.matrix.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix;
	}
});

dojo.declare("dojo.gfx.shape.VirtualGroup", dojo.gfx.Shape, {
	initializer: function() {
		this.children = [];
	},
	
	// group management
	add: function(shape){
		var oldParent = shape.getParent();
		if(oldParent){
			oldParent.remove(shape, true);
		}
		this.children.push(shape);
		return shape._setParent(this, this._getRealMatrix());
	},
	remove: function(shape, silently){
		var i = 0;
		for(; i < this.children.length; ++i){
			if(this.children[i] == shape){
				if(silently){
					// skip for now
				}else{
					shape._setParent(null, null);
				}
				this.children.splice(i, 1);
				break;
			}
		}
		return this;
	},
	
	// apply transformation
	_applyTransform: function(){
		var matrix = this._getRealMatrix();
		for(var i = 0; i < this.children.length; ++i){
			this.children[i]._updateParentMatrix(matrix);
		}
		return this;
	}
});

dojo.declare("dojo.gfx.shape.Rect", dojo.gfx.Shape, {
	initializer: function(rawNode) {
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultRect, true);
		this.attach(rawNode);
	},
	getBoundingBox: function(){ return this.shape; }
});

dojo.declare("dojo.gfx.shape.Ellipse", dojo.gfx.Shape, {
	initializer: function(rawNode) {
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultEllipse, true);
		this.attach(rawNode);
	},
	getBoundingBox: function(){
		if(!this.bbox){
			var shape = this.shape;
			this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry, 
				width: 2 * shape.rx, height: 2 * shape.ry};
		}
		return this.bbox;
	}
});

dojo.declare("dojo.gfx.shape.Circle", dojo.gfx.Shape, {
	initializer: function(rawNode) {
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultCircle, true);
		this.attach(rawNode);
	},
	getBoundingBox: function(){
		if(!this.bbox){
			var shape = this.shape;
			this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r, 
				width: 2 * shape.r, height: 2 * shape.r};
		}
		return this.bbox;
	}
});

dojo.declare("dojo.gfx.shape.Line", dojo.gfx.Shape, {
	initializer: function(rawNode) {
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultLine, true);
		this.attach(rawNode);
	},
	getBoundingBox: function(){
		if(!this.bbox){
			var shape = this.shape;
			this.bbox = {
				x:		Math.min(shape.x1, shape.x2),
				y:		Math.min(shape.y1, shape.y2),
				width:	Math.abs(shape.x2 - shape.x1),
				height:	Math.abs(shape.y2 - shape.y1)
			};
		}
		return this.bbox;
	}
});

dojo.declare("dojo.gfx.shape.Polyline", dojo.gfx.Shape, {
	initializer: function(rawNode) {
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultPolyline, true);
		this.attach(rawNode);
	},
	getBoundingBox: function(){
		if(!this.bbox && this.shape.points.length){
			var p = this.shape.points;
			var l = p.length;
			var t = p[0];
			var bbox = {l: t.x, t: t.y, r: t.x, b: t.y};
			for(var i = 1; i < l; ++i){
				t = p[i];
				if(bbox.l > t.x) bbox.l = t.x;
				if(bbox.r < t.x) bbox.r = t.x;
				if(bbox.t > t.y) bbox.t = t.y;
				if(bbox.b < t.y) bbox.b = t.y;
			}
			this.bbox = {
				x:		bbox.l, 
				y:		bbox.t, 
				width:	bbox.r - bbox.l, 
				height:	bbox.b - bbox.t
			};
		}
		return this.bbox;
	}
});

dojo.declare("dojo.gfx.shape.Image", dojo.gfx.Shape, {
	initializer: function(rawNode) {
		this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultImage, true);
		this.attach(rawNode);
	},
	getBoundingBox: function(){
		if(!this.bbox){
			var shape = this.shape;
			this.bbox = {
				x:		0,
				y:		0,
				width:	shape.width,
				height:	shape.height
			};
		}
		return this.bbox;
	}
});

__CPAN_DIR__ src/gfx/color
__CPAN_FILE__ src/gfx/color/hsl.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.color.hsl");
dojo.require("dojo.lang.array");

dojo.lang.extend(dojo.gfx.color.Color, {
	toHsl: function() {
		return dojo.gfx.color.rgb2hsl(this.toRgb());
	}
});

dojo.gfx.color.rgb2hsl = function(r, g, b){
	if (dojo.lang.isArray(r)) {
		b = r[2] || 0;
		g = r[1] || 0;
		r = r[0] || 0;
	}

	r /= 255;
	g /= 255;
	b /= 255;

	//
	// based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/
	//

	var h = null;
	var s = null;
	var l = null;

	var min = Math.min(r, g, b);
	var max = Math.max(r, g, b);
	var delta = max - min;

	l = (min + max) / 2;
	s = 0;

	if ((l > 0) && (l < 1)){
		s = delta / ((l < 0.5) ? (2 * l) : (2 - 2 * l));
	}

	h = 0;

	if (delta > 0) {
		if ((max == r) && (max != g)){
			h += (g - b) / delta;
		}
		if ((max == g) && (max != b)){
			h += (2 + (b - r) / delta);
		}
		if ((max == b) && (max != r)){
			h += (4 + (r - g) / delta);
		}
		h *= 60;
	}

	h = (h == 0) ? 360 : Math.ceil((h / 360) * 255);
	s = Math.ceil(s * 255);
	l = Math.ceil(l * 255);

	return [h, s, l];
}

dojo.gfx.color.hsl2rgb = function(h, s, l){
	if (dojo.lang.isArray(h)) {
		l = h[2] || 0;
		s = h[1] || 0;
		h = h[0] || 0;
	}

	h = (h / 255) * 360;
	if (h == 360){ h = 0;}
	s = s / 255;
	l = l / 255;

	//
	// based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/
	//


	while (h < 0){ h += 360; }
	while (h > 360){ h -= 360; }
	var r, g, b;
	if (h < 120){
		r = (120 - h) / 60;
		g = h / 60;
		b = 0;
	}else if (h < 240){
		r = 0;
		g = (240 - h) / 60;
		b = (h - 120) / 60;
	}else{
		r = (h - 240) / 60;
		g = 0;
		b = (360 - h) / 60;
	}

	r = Math.min(r, 1);
	g = Math.min(g, 1);
	b = Math.min(b, 1);

	r = 2 * s * r + (1 - s);
	g = 2 * s * g + (1 - s);
	b = 2 * s * b + (1 - s);

	if (l < 0.5){
		r = l * r;
		g = l * g;
		b = l * b;
	}else{
		r = (1 - l) * r + 2 * l - 1;
		g = (1 - l) * g + 2 * l - 1;
		b = (1 - l) * b + 2 * l - 1;
	}

	r = Math.ceil(r * 255);
	g = Math.ceil(g * 255);
	b = Math.ceil(b * 255);

	return [r, g, b];
}

dojo.gfx.color.hsl2hex = function(h, s, l){
	var rgb = dojo.gfx.color.hsl2rgb(h, s, l);
	return dojo.gfx.color.rgb2hex(rgb[0], rgb[1], rgb[2]);
}

dojo.gfx.color.hex2hsl = function(hex){
	var rgb = dojo.gfx.color.hex2rgb(hex);
	return dojo.gfx.color.rgb2hsl(rgb[0], rgb[1], rgb[2]);
}

__CPAN_FILE__ src/gfx/color/hsv.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.gfx.color.hsv");
dojo.require("dojo.lang.array");
dojo.require("dojo.math");

dojo.lang.extend(dojo.gfx.color.Color, {
	toHsv: function() {
		return dojo.gfx.color.rgb2hsv(this.toRgb());
	}

});

// Default input range for RBG values is 0-255
dojo.gfx.color.rgb2hsv = function(/* int || Array */r, /* int */g, /* int */b, /* Object? */options){
	//	summary
	//	converts an RGB value set to HSV, ranges depending on optional options object.
	//	patch for options by Matthew Eernisse 	
	if (dojo.lang.isArray(r)) {
		if(g) {
			options = g;
		}
		b = r[2] || 0;
		g = r[1] || 0;
		r = r[0] || 0;
	}

	var opt = {
		inputRange:  (options && options.inputRange)  ? options.inputRange : 255,
		outputRange: (options && options.outputRange) ? options.outputRange : [255, 255, 255]
	};

	// r,g,b, each 0 to 255, to HSV.
	// h = 0.0 to 360.0 (corresponding to 0..360.0 degrees around hexcone)
	// s = 0.0 (shade of gray) to 1.0 (pure color)
	// v = 0.0 (black) to 1.0 {white)
	//
	// Based on C Code in "Computer Graphics -- Principles and Practice,"
	// Foley et al, 1996, p. 592. 
	//
	// our calculatuions are based on 'regular' values (0-360, 0-1, 0-1) 
	// but we return bytes values (0-255, 0-255, 0-255)

	var h = null;
	var s = null;
	var v = null;

	switch(opt.inputRange) { 
		// 0.0-1.0 
		case 1:
			r = (r * 255);
			g = (g * 255);
			b = (b * 255);
			break;
		// 0-100 
		case 100:
			r = (r / 100) * 255;
			g = (g / 100) * 255;
			b = (b / 100) * 255;
			break;
		// 0-255
		default:
			// Do nothing
			break;
	} 
	
	var min = Math.min(r, g, b);
	v = Math.max(r, g, b);

	var delta = v - min;

	// calculate saturation (0 if r, g and b are all 0)

	s = (v == 0) ? 0 : delta/v;
	if (s == 0){
		// achromatic: when saturation is, hue is undefined
		h = 0;
	}else{
		// chromatic
		if (r == v){
			// between yellow and magenta
			h = 60 * (g - b) / delta;
		}else{
			if (g == v){
				// between cyan and yellow
				h = 120 + 60 * (b - r) / delta;
			}else{
				if (b == v){
					// between magenta and cyan
					h = 240 + 60 * (r - g) / delta;
				}
			}
		}
		if (h <= 0){
			h += 360;
		}
	}
	// Hue
	switch (opt.outputRange[0]) {
		case 360:
			// Do nothing
			break;
		case 100:
			h = (h / 360) * 100;
			break;
		case 1:
			h = (h / 360);
			break;
		default: // 255
			h = (h / 360) * 255;
			break;
	}
	// Saturation
	switch (opt.outputRange[1]) {
		case 100:
			s = s * 100;
		case 1:
			// Do nothing
			break;
		default: // 255
			s = s * 255;
			break;
	}
	// Value
	switch (opt.outputRange[2]) {
		case 100:
			v = (v / 255) * 100;
			break;
		case 1:
			v = (v / 255);
			break;
		default: // 255
			// Do nothing
			break;
	}
	h = dojo.math.round(h);
	s = dojo.math.round(s);
	v = dojo.math.round(v);
	return [h, s, v];
}

// Based on C Code in "Computer Graphics -- Principles and Practice,"
// Foley et al, 1996, p. 593.
//
// H = 0 to 255 (corresponding to 0..360 degrees around hexcone) 0 for S = 0
// S = 0 (shade of gray) to 255 (pure color)
// V = 0 (black) to 255 (white)
dojo.gfx.color.hsv2rgb = function(/* int || Array */h, /* int */s, /* int */v, /* Object? */options){
	//	summary
	//	converts an HSV value set to RGB, ranges depending on optional options object.
	//	patch for options by Matthew Eernisse 	
	if (dojo.lang.isArray(h)) {
		if(s){
			options = s;
		}
		v = h[2] || 0;
		s = h[1] || 0;
		h = h[0] || 0;
	}

	var opt = {
		inputRange:  (options && options.inputRange)  ? options.inputRange : [255, 255, 255],
		outputRange: (options && options.outputRange) ? options.outputRange : 255
	};

    switch(opt.inputRange[0]) { 
		// 0.0-1.0 
		case 1: h = h * 360; break; 
		// 0-100 
		case 100: h = (h / 100) * 360; break; 
		// 0-360 
		case 360: h = h; break; 
		// 0-255 
		default: h = (h / 255) * 360; 
	} 
	if (h == 360){ h = 0;}

	//	no need to alter if inputRange[1] = 1
	switch(opt.inputRange[1]){
		case 100: s /= 100; break;
		case 255: s /= 255;
	}

	//	no need to alter if inputRange[1] = 1
	switch(opt.inputRange[2]){
		case 100: v /= 100; break;
		case 255: v /= 255;
	}

	var r = null;
	var g = null;
	var b = null;

	if (s == 0){
		// color is on black-and-white center line
		// achromatic: shades of gray
		r = v;
		g = v;
		b = v;
	}else{
		// chromatic color
		var hTemp = h / 60;		// h is now IN [0,6]
		var i = Math.floor(hTemp);	// largest integer <= h
		var f = hTemp - i;		// fractional part of h

		var p = v * (1 - s);
		var q = v * (1 - (s * f));
		var t = v * (1 - (s * (1 - f)));

		switch(i){
			case 0: r = v; g = t; b = p; break;
			case 1: r = q; g = v; b = p; break;
			case 2: r = p; g = v; b = t; break;
			case 3: r = p; g = q; b = v; break;
			case 4: r = t; g = p; b = v; break;
			case 5: r = v; g = p; b = q; break;
		}
	}

	switch(opt.outputRange){
		case 1:
			r = dojo.math.round(r, 2);
			g = dojo.math.round(g, 2);
			b = dojo.math.round(b, 2);
			break;
		case 100:
			r = Math.round(r * 100);
			g = Math.round(g * 100);
			b = Math.round(b * 100);
			break;
		default:
			r = Math.round(r * 255);
			g = Math.round(g * 255);
			b = Math.round(b * 255);
	}

	return [r, g, b];
}

__CPAN_DIR__ src/text
__CPAN_FILE__ src/text/textDirectory.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.require("dojo.cal.textDirectory");
dojo.deprecate("dojo.text.textDirectory", "use dojo.cal.textDirectory", "0.5");

__CPAN_FILE__ src/text/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.text.String",
		"dojo.text.Builder"
	]
});

dojo.deprecated("dojo.text", "textDirectory moved to cal, text.String and text.Builder havne't been here for awhile", "0.5");

__CPAN_DIR__ src/logging
__CPAN_FILE__ src/logging/Logger.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

/*		This is the dojo logging facility, which is imported from nWidgets
		(written by Alex Russell, CLA on file), which is patterned on the
		Python logging module, which in turn has been heavily influenced by
		log4j (execpt with some more pythonic choices, which we adopt as well).

		While the dojo logging facilities do provide a set of familiar
		interfaces, many of the details are changed to reflect the constraints
		of the browser environment. Mainly, file and syslog-style logging
		facilites are not provided, with HTTP POST and GET requests being the
		only ways of getting data from the browser back to a server. Minimal
		support for this (and XML serialization of logs) is provided, but may
		not be of practical use in a deployment environment.

		The Dojo logging classes are agnostic of any environment, and while
		default loggers are provided for browser-based interpreter
		environments, this file and the classes it define are explicitly
		designed to be portable to command-line interpreters and other
		ECMA-262v3 envrionments.

	the logger needs to accomidate:
		log "levels"
		type identifiers
		file?
		message
		tic/toc?

	The logger should ALWAYS record:
		time/date logged
		message
		type
		level
*/
// TODO: conver documentation to javadoc style once we confirm that is our choice
// TODO: define DTD for XML-formatted log messages
// TODO: write XML Formatter class
// TODO: write HTTP Handler which uses POST to send log lines/sections

// Filename:	LogCore.js
// Purpose:		a common logging infrastructure for dojo
// Classes:		dojo.logging, dojo.logging.Logger, dojo.logging.Record, dojo.logging.LogFilter
// Global Objects:	dojo.logging
// Dependencies:	none

dojo.provide("dojo.logging.Logger");
dojo.require("dojo.lang.common");

/*
	A simple data structure class that stores information for and about
	a logged event. Objects of this type are created automatically when
	an event is logged and are the internal format in which information
	about log events is kept.
*/

dojo.logging.Record = function(lvl, msg){
	this.level = lvl;
	this.message = "";
	this.msgArgs = [];
	this.time = new Date();
	
	if(dojo.lang.isArray(msg)){
		if(msg.length > 0 && dojo.lang.isString(msg[0])){
			this.message=msg.shift();
		}
		this.msgArgs=msg;
	}else{
		this.message=msg;
	}
	// FIXME: what other information can we receive/discover here?
}

// an empty parent (abstract) class which concrete filters should inherit from.
dojo.logging.LogFilter = function(loggerChain){
	this.passChain = loggerChain || "";
	this.filter = function(record){
		// FIXME: need to figure out a way to enforce the loggerChain
		// restriction
		return true; // pass all records
	}
}

dojo.logging.Logger = function(){
	this.cutOffLevel = 0;
	this.propagate = true;
	this.parent = null;
	// storage for dojo.logging.Record objects seen and accepted by this logger
	this.data = [];
	this.filters = [];
	this.handlers = [];
}

dojo.extend(dojo.logging.Logger,{
	argsToArr: function(args){
		// utility function, reproduced from __util__ here to remove dependency
		var ret = [];
		for(var x=0; x<args.length; x++){
			ret.push(args[x]);
		}
		return ret;
	},

	setLevel: function(lvl){
		this.cutOffLevel = parseInt(lvl);
	},

	isEnabledFor: function(lvl){
		return parseInt(lvl) >= this.cutOffLevel;
	},

	getEffectiveLevel: function(){
		if((this.cutOffLevel==0)&&(this.parent)){
			return this.parent.getEffectiveLevel();
		}
		return this.cutOffLevel;
	},

	addFilter: function(flt){
		this.filters.push(flt);
		return this.filters.length-1;
	},

	removeFilterByIndex: function(fltIndex){
		if(this.filters[fltIndex]){
			delete this.filters[fltIndex];
			return true;
		}
		return false;
	},

	removeFilter: function(fltRef){
		for(var x=0; x<this.filters.length; x++){
			if(this.filters[x]===fltRef){
				delete this.filters[x];
				return true;
			}
		}
		return false;
	},

	removeAllFilters: function(){
		this.filters = []; // clobber all of them
	},

	filter: function(rec){
		for(var x=0; x<this.filters.length; x++){
			if((this.filters[x]["filter"])&&
			   (!this.filters[x].filter(rec))||
			   (rec.level<this.cutOffLevel)){
				return false;
			}
		}
		return true;
	},

	addHandler: function(hdlr){
		this.handlers.push(hdlr);
		return this.handlers.length-1;
	},

	handle: function(rec){
		if((!this.filter(rec))||(rec.level<this.cutOffLevel)){ return false; }
		for(var x=0; x<this.handlers.length; x++){
			if(this.handlers[x]["handle"]){
			   this.handlers[x].handle(rec);
			}
		}
		// FIXME: not sure what to do about records to be propagated that may have
		// been modified by the handlers or the filters at this logger. Should
		// parents always have pristine copies? or is passing the modified record
		// OK?
		// if((this.propagate)&&(this.parent)){ this.parent.handle(rec); }
		return true;
	},

	// the heart and soul of the logging system
	log: function(lvl, msg){
		if(	(this.propagate)&&(this.parent)&&
			(this.parent.rec.level>=this.cutOffLevel)){
			this.parent.log(lvl, msg);
			return false;
		}
		// FIXME: need to call logging providers here!
		this.handle(new dojo.logging.Record(lvl, msg));
		return true;
	},

	// logger helpers
	debug:function(msg){
		return this.logType("DEBUG", this.argsToArr(arguments));
	},

	info: function(msg){
		return this.logType("INFO", this.argsToArr(arguments));
	},

	warning: function(msg){
		return this.logType("WARNING", this.argsToArr(arguments));
	},

	error: function(msg){
		return this.logType("ERROR", this.argsToArr(arguments));
	},

	critical: function(msg){
		return this.logType("CRITICAL", this.argsToArr(arguments));
	},

	exception: function(msg, e, squelch){
		// FIXME: this needs to be modified to put the exception in the msg
		// if we're on Moz, we can get the following from the exception object:
		//		lineNumber
		//		message
		//		fileName
		//		stack
		//		name
		// on IE, we get:
		//		name
		//		message (from MDA?)
		//		number
		//		description (same as message!)
		if(e){
			var eparts = [e.name, (e.description||e.message)];
			if(e.fileName){
				eparts.push(e.fileName);
				eparts.push("line "+e.lineNumber);
				// eparts.push(e.stack);
			}
			msg += " "+eparts.join(" : ");
		}

		this.logType("ERROR", msg);
		if(!squelch){
			throw e;
		}
	},

	logType: function(type, args){
		return this.log.apply(this, [dojo.logging.log.getLevel(type), 
			args]);
	},
	
	warn:function(){
		this.warning.apply(this,arguments);
	},
	err:function(){
		this.error.apply(this,arguments);
	},
	crit:function(){
		this.critical.apply(this,arguments);
	}
});

// the Handler class
dojo.logging.LogHandler = function(level){
	this.cutOffLevel = (level) ? level : 0;
	this.formatter = null; // FIXME: default formatter?
	this.data = [];
	this.filters = [];
}
dojo.lang.extend(dojo.logging.LogHandler,{
	
	setFormatter:function(formatter){
		dojo.unimplemented("setFormatter");
	},
	
	flush:function(){},
	close:function(){},
	handleError:function(){},
	
	handle:function(record){
		if((this.filter(record))&&(record.level>=this.cutOffLevel)){
			this.emit(record);
		}
	},
	
	emit:function(record){
		dojo.unimplemented("emit");
	}
});

// set aliases since we don't want to inherit from dojo.logging.Logger
void(function(){ // begin globals protection closure
	var names = [
		"setLevel", "addFilter", "removeFilterByIndex", "removeFilter",
		"removeAllFilters", "filter"
	];
	var tgt = dojo.logging.LogHandler.prototype;
	var src = dojo.logging.Logger.prototype;
	for(var x=0; x<names.length; x++){
		tgt[names[x]] = src[names[x]];
	}
})(); // end globals protection closure

dojo.logging.log = new dojo.logging.Logger();

// an associative array of logger objects. This object inherits from
// a list of level names with their associated numeric levels
dojo.logging.log.levels = [ {"name": "DEBUG", "level": 1},
						   {"name": "INFO", "level": 2},
						   {"name": "WARNING", "level": 3},
						   {"name": "ERROR", "level": 4},
						   {"name": "CRITICAL", "level": 5} ];

dojo.logging.log.loggers = {};

dojo.logging.log.getLogger = function(name){
	if(!this.loggers[name]){
		this.loggers[name] = new dojo.logging.Logger();
		this.loggers[name].parent = this;
	}
	return this.loggers[name];
}

dojo.logging.log.getLevelName = function(lvl){
	for(var x=0; x<this.levels.length; x++){
		if(this.levels[x].level == lvl){
			return this.levels[x].name;
		}
	}
	return null;
}

dojo.logging.log.addLevelName = function(name, lvl){
	if(this.getLevelName(name)){
		this.err("could not add log level "+name+" because a level with that name already exists");
		return false;
	}
	this.levels.append({"name": name, "level": parseInt(lvl)});
	return true;
}

dojo.logging.log.getLevel = function(name){
	for(var x=0; x<this.levels.length; x++){
		if(this.levels[x].name.toUpperCase() == name.toUpperCase()){
			return this.levels[x].level;
		}
	}
	return null;
}

// a default handler class, it simply saves all of the handle()'d records in
// memory. Useful for attaching to with dojo.event.connect()
dojo.logging.MemoryLogHandler = function(level, recordsToKeep, postType, postInterval){
	// mixin style inheritance
	dojo.logging.LogHandler.call(this, level);
	// default is unlimited
	this.numRecords = (typeof djConfig['loggingNumRecords'] != 'undefined') ? djConfig['loggingNumRecords'] : ((recordsToKeep) ? recordsToKeep : -1);
	// 0=count, 1=time, -1=don't post TODO: move this to a better location for prefs
	this.postType = (typeof djConfig['loggingPostType'] != 'undefined') ? djConfig['loggingPostType'] : ( postType || -1);
	// milliseconds for time, interger for number of records, -1 for non-posting,
	this.postInterval = (typeof djConfig['loggingPostInterval'] != 'undefined') ? djConfig['loggingPostInterval'] : ( postType || -1);
}

dojo.lang.inherits(dojo.logging.MemoryLogHandler, dojo.logging.LogHandler);
dojo.lang.extend(dojo.logging.MemoryLogHandler,{
	
	emit:function(record){
		if (!djConfig.isDebug) { return; }
		
		var logStr = String(dojo.log.getLevelName(record.level)+": "
					+record.time.toLocaleTimeString())+": "+record.message;
		if(!dj_undef("println", dojo.hostenv)){
			dojo.hostenv.println(logStr);
		}
		
		this.data.push(record);
		if(this.numRecords != -1){
			while(this.data.length>this.numRecords){
				this.data.shift();
			}
		}
	}
});

dojo.logging.logQueueHandler = new dojo.logging.MemoryLogHandler(0,50,0,10000);

dojo.logging.log.addHandler(dojo.logging.logQueueHandler);
dojo.log = dojo.logging.log;

__CPAN_FILE__ src/logging/ConsoleLogger.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.logging.ConsoleLogger");
dojo.require("dojo.logging.Logger");

dojo.lang.extend(dojo.logging.MemoryLogHandler,{
	
	debug:function(){
		dojo.hostenv.println.apply(this,arguments);
	},
	info:function(){
		dojo.hostenv.println.apply(this,arguments);
	},
	warn:function(){
		dojo.hostenv.println.apply(this,arguments);
	},
	error:function(){
		dojo.hostenv.println.apply(this,arguments);
	},
	critical:function(){
		dojo.hostenv.println.apply(this,arguments);
	},
	
	emit:function(record){
		if (!djConfig.isDebug) { return; }
		
		var funcName=null;
		switch(record.level){
			case 1:
				funcName="debug";
				break;
			case 2:
				funcName="info";
				break;
			case 3:
				funcName="warn";
				break;
			case 4:
				funcName="error";
				break;
			case 5:
				funcName="critical";
				break;
			default:
				funcName="debug";
		}
		
		var logStr = String(dojo.log.getLevelName(record.level)+": "
					+record.time.toLocaleTimeString())+": "+record.message;
		if(record.msgArgs && record.msgArgs.length > 0){
			this[funcName].call(this, logStr, record.msgArgs);
		} else {
			this[funcName].call(this, logStr);
		}
		
		this.data.push(record);
		if(this.numRecords != -1){
			while(this.data.length>this.numRecords){
				this.data.shift();
			}
		}
	}
});

if(!dj_undef("console") && !dj_undef("info", console)){
dojo.lang.extend(dojo.logging.MemoryLogHandler,{
	debug:function(){
		console.debug.apply(this, arguments);
	},
	info:function(){
		console.info.apply(this, arguments);
	},
	warn:function(){
		console.warn.apply(this, arguments);
	},
	error:function(){
		console.error.apply(this, arguments);
	},
	critical:function(){
		console.error.apply(this, arguments);
	}
});

dojo.lang.extend(dojo.logging.Logger,{
	exception: function(msg, e, squelch){
		var args=[msg];
		
		if(e){
			msg+=" : "+ e.name + " " + (e.description||e.message);
			args.push(e);
		}
		
		this.logType("ERROR", args);
		if(!squelch){
			throw e;
		}
	}
});

}

__CPAN_FILE__ src/logging/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [["dojo.logging.Logger", false, false]],
	rhino: ["dojo.logging.RhinoLogger"]
});
dojo.provide("dojo.logging.*");

__CPAN_DIR__ src/uuid
__CPAN_FILE__ src/uuid/NameBasedGenerator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uuid.NameBasedGenerator");

dojo.uuid.NameBasedGenerator = new function() {
	this.generate = function(/* constructor? */ returnType) {
		// summary: 
		//   This function generates name-based UUIDs, meaning "version 3" 
		//   and "version 5" UUIDs.
		// returnType: The type of object to return. Usually String or dojo.uuid.Uuid

		// examples: 
		//   var string = dojo.uuid.NameBasedGenerator.generate();
		//   var string = dojo.uuid.NameBasedGenerator.generate(String);
		//   var uuid   = dojo.uuid.NameBasedGenerator.generate(dojo.uuid.Uuid);

		dojo.unimplemented('dojo.uuid.NameBasedGenerator.generate');
		
		// FIXME:
		// For an algorithm to generate name-based UUIDs, 
		// see sections 4.3 of RFC 4122:
		//  http://www.ietf.org/rfc/rfc4122.txt
		
		var returnValue = "00000000-0000-0000-0000-000000000000"; // FIXME
		if (returnType && (returnType != String)) {
			returnValue = new returnType(returnValue);
		}
		return returnValue; // object
	};
}();
__CPAN_FILE__ src/uuid/TimeBasedGenerator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uuid.TimeBasedGenerator");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.type");
dojo.require("dojo.lang.assert");

dojo.uuid.TimeBasedGenerator = new function() {

	// --------------------------------------------------
	// Public constants:
	// Number of hours between October 15, 1582 and January 1, 1970:
	this.GREGORIAN_CHANGE_OFFSET_IN_HOURS = 3394248;
	// Number of seconds between October 15, 1582 and January 1, 1970:
	//   this.GREGORIAN_CHANGE_OFFSET_IN_SECONDS = 12219292800;	
	
	// --------------------------------------------------
	// Private variables:
	var _uuidPseudoNodeString = null;
	var _uuidClockSeqString = null;
	var _dateValueOfPreviousUuid = null;
	var _nextIntraMillisecondIncrement = 0;
	var _cachedMillisecondsBetween1582and1970 = null;
	var _cachedHundredNanosecondIntervalsPerMillisecond = null;
	var _uniformNode = null;
	
	// --------------------------------------------------
	// Private constants:
	var HEX_RADIX = 16;

	function _carry(/* array */ arrayA) {
		// summary: 
		//   Given an array which holds a 64-bit number broken into 4 16-bit 
		//   elements, this method carries any excess bits (greater than 16-bits) 
		//   from each array element into the next.
		// arrayA: An array with 4 elements, each of which is a 16-bit number.
		arrayA[2] += arrayA[3] >>> 16;
		arrayA[3] &= 0xFFFF;
		arrayA[1] += arrayA[2] >>> 16;
		arrayA[2] &= 0xFFFF;
		arrayA[0] += arrayA[1] >>> 16;
		arrayA[1] &= 0xFFFF;
		dojo.lang.assert((arrayA[0] >>> 16) === 0);
	}

	function _get64bitArrayFromFloat(/* float */ x) {
		// summary: 
		//   Given a floating point number, this method returns an array which 
		//   holds a 64-bit number broken into 4 16-bit elements.
		var result = new Array(0, 0, 0, 0);
		result[3] = x % 0x10000;
		x -= result[3];
		x /= 0x10000;
		result[2] = x % 0x10000;
		x -= result[2];
		x /= 0x10000;
		result[1] = x % 0x10000;
		x -= result[1];
		x /= 0x10000;
		result[0] = x;
		return result; // Array with 4 elements, each of which is a 16-bit number.
	}

	function _addTwo64bitArrays(/* array */ arrayA, /* array */ arrayB) {
		// summary: 
		//   Takes two arrays, each of which holds a 64-bit number broken into 4
		//   16-bit elements, and returns a new array that holds a 64-bit number
		//   that is the sum of the two original numbers.
		// arrayA: An array with 4 elements, each of which is a 16-bit number.
		// arrayB: An array with 4 elements, each of which is a 16-bit number.
		dojo.lang.assertType(arrayA, Array);
		dojo.lang.assertType(arrayB, Array);
		dojo.lang.assert(arrayA.length == 4);
		dojo.lang.assert(arrayB.length == 4);
	
		var result = new Array(0, 0, 0, 0);
		result[3] = arrayA[3] + arrayB[3];
		result[2] = arrayA[2] + arrayB[2];
		result[1] = arrayA[1] + arrayB[1];
		result[0] = arrayA[0] + arrayB[0];
		_carry(result);
		return result; // Array with 4 elements, each of which is a 16-bit number.
	}

	function _multiplyTwo64bitArrays(/* array */ arrayA, /* array */ arrayB) {
		// summary: 
		//   Takes two arrays, each of which holds a 64-bit number broken into 4
		//   16-bit elements, and returns a new array that holds a 64-bit number
		//   that is the product of the two original numbers.
		// arrayA: An array with 4 elements, each of which is a 16-bit number.
		// arrayB: An array with 4 elements, each of which is a 16-bit number.
		dojo.lang.assertType(arrayA, Array);
		dojo.lang.assertType(arrayB, Array);
		dojo.lang.assert(arrayA.length == 4);
		dojo.lang.assert(arrayB.length == 4);
	
		var overflow = false;
		if (arrayA[0] * arrayB[0] !== 0) { overflow = true; }
		if (arrayA[0] * arrayB[1] !== 0) { overflow = true; }
		if (arrayA[0] * arrayB[2] !== 0) { overflow = true; }
		if (arrayA[1] * arrayB[0] !== 0) { overflow = true; }
		if (arrayA[1] * arrayB[1] !== 0) { overflow = true; }
		if (arrayA[2] * arrayB[0] !== 0) { overflow = true; }
		dojo.lang.assert(!overflow);
	
		var result = new Array(0, 0, 0, 0);
		result[0] += arrayA[0] * arrayB[3];
		_carry(result);
		result[0] += arrayA[1] * arrayB[2];
		_carry(result);
		result[0] += arrayA[2] * arrayB[1];
		_carry(result);
		result[0] += arrayA[3] * arrayB[0];
		_carry(result);
		result[1] += arrayA[1] * arrayB[3];
		_carry(result);
		result[1] += arrayA[2] * arrayB[2];
		_carry(result);
		result[1] += arrayA[3] * arrayB[1];
		_carry(result);
		result[2] += arrayA[2] * arrayB[3];
		_carry(result);
		result[2] += arrayA[3] * arrayB[2];
		_carry(result);
		result[3] += arrayA[3] * arrayB[3];
		_carry(result);
		return result; // Array with 4 elements, each of which is a 16-bit number.
	}

	function _padWithLeadingZeros(/* string */ string, /* int */ desiredLength) {
		// summary: 
		//   Pads a string with leading zeros and returns the result.
		// string: A string to add padding to.
		// desiredLength: The number of characters the return string should have.

		// examples: 
		//   result = _padWithLeadingZeros("abc", 6);
		//   dojo.lang.assert(result == "000abc");
		while (string.length < desiredLength) {
			string = "0" + string;
		}
		return string; // string
	}

	function _generateRandomEightCharacterHexString() {
		// summary: 
		//   Returns a randomly generated 8-character string of hex digits.

		// FIXME: This probably isn't a very high quality random number.
	
		// Make random32bitNumber be a randomly generated floating point number
		// between 0 and (4,294,967,296 - 1), inclusive.
		var random32bitNumber = Math.floor( (Math.random() % 1) * Math.pow(2, 32) );
	
		var eightCharacterString = random32bitNumber.toString(HEX_RADIX);
		while (eightCharacterString.length < 8) {
			eightCharacterString = "0" + eightCharacterString;
		}
		return eightCharacterString; // String (an 8-character hex string)
	}

	function _generateUuidString(/* string? */ node) {
		// summary: 
		//   Generates a time-based UUID, meaning a version 1 UUID.  
		// description: 
		//   JavaScript code running in a browser doesn't have access to the 
		//   IEEE 802.3 address of the computer, so if a node value isn't 
		//   supplied, we generate a random pseudonode value instead.
		// node: An optional 12-character string to use as the node in the new UUID.
		dojo.lang.assertType(node, String, {optional: true});
		if (node) {
			dojo.lang.assert(node.length == 12);
		} else {
			if (_uniformNode) {
				node = _uniformNode;
			} else {
				if (!_uuidPseudoNodeString) {
					var pseudoNodeIndicatorBit = 0x8000;
					var random15bitNumber = Math.floor( (Math.random() % 1) * Math.pow(2, 15) );
					var leftmost4HexCharacters = (pseudoNodeIndicatorBit | random15bitNumber).toString(HEX_RADIX);
					_uuidPseudoNodeString = leftmost4HexCharacters + _generateRandomEightCharacterHexString();
				}
				node = _uuidPseudoNodeString;
			}
		}
		if (!_uuidClockSeqString) {
			var variantCodeForDCEUuids = 0x8000; // 10--------------, i.e. uses only first two of 16 bits.
			var random14bitNumber = Math.floor( (Math.random() % 1) * Math.pow(2, 14) );
			_uuidClockSeqString = (variantCodeForDCEUuids | random14bitNumber).toString(HEX_RADIX);
		}
	
		// Maybe we should think about trying to make the code more readable to
		// newcomers by creating a class called "WholeNumber" that encapsulates
		// the methods and data structures for working with these arrays that
		// hold 4 16-bit numbers?  And then these variables below have names
		// like "wholeSecondsPerHour" rather than "arraySecondsPerHour"?
		var now = new Date();
		var millisecondsSince1970 = now.valueOf(); // milliseconds since midnight 01 January, 1970 UTC.
		var nowArray = _get64bitArrayFromFloat(millisecondsSince1970);
		if (!_cachedMillisecondsBetween1582and1970) {
			var arraySecondsPerHour = _get64bitArrayFromFloat(60 * 60);
			var arrayHoursBetween1582and1970 = _get64bitArrayFromFloat(dojo.uuid.TimeBasedGenerator.GREGORIAN_CHANGE_OFFSET_IN_HOURS);
			var arraySecondsBetween1582and1970 = _multiplyTwo64bitArrays(arrayHoursBetween1582and1970, arraySecondsPerHour);
			var arrayMillisecondsPerSecond = _get64bitArrayFromFloat(1000);
			_cachedMillisecondsBetween1582and1970 = _multiplyTwo64bitArrays(arraySecondsBetween1582and1970, arrayMillisecondsPerSecond);
			_cachedHundredNanosecondIntervalsPerMillisecond = _get64bitArrayFromFloat(10000);
		}
		var arrayMillisecondsSince1970 = nowArray;
		var arrayMillisecondsSince1582 = _addTwo64bitArrays(_cachedMillisecondsBetween1582and1970, arrayMillisecondsSince1970);
		var arrayHundredNanosecondIntervalsSince1582 = _multiplyTwo64bitArrays(arrayMillisecondsSince1582, _cachedHundredNanosecondIntervalsPerMillisecond);
	
		if (now.valueOf() == _dateValueOfPreviousUuid) {
			arrayHundredNanosecondIntervalsSince1582[3] += _nextIntraMillisecondIncrement;
			_carry(arrayHundredNanosecondIntervalsSince1582);
			_nextIntraMillisecondIncrement += 1;
			if (_nextIntraMillisecondIncrement == 10000) {
				// If we've gotten to here, it means we've already generated 10,000
				// UUIDs in this single millisecond, which is the most that the UUID
				// timestamp field allows for.  So now we'll just sit here and wait
				// for a fraction of a millisecond, so as to ensure that the next
				// time this method is called there will be a different millisecond
				// value in the timestamp field.
				while (now.valueOf() == _dateValueOfPreviousUuid) {
					now = new Date();
				}
			}
		} else {
			_dateValueOfPreviousUuid = now.valueOf();
			_nextIntraMillisecondIncrement = 1;
		}
	
		var hexTimeLowLeftHalf  = arrayHundredNanosecondIntervalsSince1582[2].toString(HEX_RADIX);
		var hexTimeLowRightHalf = arrayHundredNanosecondIntervalsSince1582[3].toString(HEX_RADIX);
		var hexTimeLow = _padWithLeadingZeros(hexTimeLowLeftHalf, 4) + _padWithLeadingZeros(hexTimeLowRightHalf, 4);
		var hexTimeMid = arrayHundredNanosecondIntervalsSince1582[1].toString(HEX_RADIX);
		hexTimeMid = _padWithLeadingZeros(hexTimeMid, 4);
		var hexTimeHigh = arrayHundredNanosecondIntervalsSince1582[0].toString(HEX_RADIX);
		hexTimeHigh = _padWithLeadingZeros(hexTimeHigh, 3);
		var hyphen = "-";
		var versionCodeForTimeBasedUuids = "1"; // binary2hex("0001")
		var resultUuid = hexTimeLow + hyphen + hexTimeMid + hyphen +
					versionCodeForTimeBasedUuids + hexTimeHigh + hyphen +
					_uuidClockSeqString + hyphen + node;
		resultUuid = resultUuid.toLowerCase();
		return resultUuid; // String (a 36 character string, which will look something like "b4308fb0-86cd-11da-a72b-0800200c9a66")
	}

	this.setNode = function(/* string? */ node) {
		// summary: 
		//   Sets the 'node' value that will be included in generated UUIDs.
		// node: A 12-character hex string representing a pseudoNode or hardwareNode.
		dojo.lang.assert((node === null) || (node.length == 12));
		_uniformNode = node;
	};

	this.getNode = function() {
		// summary: 
		//   Returns the 'node' value that will be included in generated UUIDs.
		return _uniformNode; // String (a 12-character hex string representing a pseudoNode or hardwareNode)
	};

	this.generate = function(/* misc? */ input) {
		// summary: 
		//   This function generates time-based UUIDs, meaning "version 1" UUIDs. 
		// description: 
		// For more info, see
		//   http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
		//   http://www.infonuovo.com/dma/csdocs/sketch/instidid.htm
		//   http://kruithof.xs4all.nl/uuid/uuidgen
		//   http://www.opengroup.org/onlinepubs/009629399/apdxa.htm#tagcjh_20
		//   http://jakarta.apache.org/commons/sandbox/id/apidocs/org/apache/commons/id/uuid/clock/Clock.html

		// examples: 
		//   var generate = dojo.uuid.TimeBasedGenerator.generate;
		//   var uuid;   // an instance of dojo.uuid.Uuid
		//   var string; // a simple string literal
		//   string = generate();
		//   string = generate(String);
		//   uuid   = generate(dojo.uuid.Uuid);
		//   string = generate("017bf397618a");
		//   string = generate({node: "017bf397618a"});         // hardwareNode
		//   string = generate({node: "f17bf397618a"});         // pseudoNode
		//   string = generate({hardwareNode: "017bf397618a"});
		//   string = generate({pseudoNode:   "f17bf397618a"});
		//   string = generate({node: "017bf397618a", returnType: String});
		//   uuid   = generate({node: "017bf397618a", returnType: dojo.uuid.Uuid});
		//   dojo.uuid.TimeBasedGenerator.setNode("017bf397618a");
		//   string = generate(); // the generated UUID has node == "017bf397618a"
		//   uuid   = generate(dojo.uuid.Uuid); // the generated UUID has node == "017bf397618a"
		var nodeString = null;
		var returnType = null;
		
		if (input) {
			if (dojo.lang.isObject(input) && !dojo.lang.isBuiltIn(input)) {
				// input: object {node: string, hardwareNode: string, pseudoNode: string}
				// node: A 12-character hex string representing a pseudoNode or hardwareNode.
				// hardwareNode: A 12-character hex string containing an IEEE 802.3 network node identificator.
				// pseudoNode: A 12-character hex string representing a pseudoNode.
				var namedParameters = input;
				dojo.lang.assertValidKeywords(namedParameters, ["node", "hardwareNode", "pseudoNode", "returnType"]);
				var node = namedParameters["node"];
				var hardwareNode = namedParameters["hardwareNode"];
				var pseudoNode = namedParameters["pseudoNode"];
				nodeString = (node || pseudoNode || hardwareNode);
				if (nodeString) {
					var firstCharacter = nodeString.charAt(0);
					var firstDigit = parseInt(firstCharacter, HEX_RADIX);
					if (hardwareNode) {
						dojo.lang.assert((firstDigit >= 0x0) && (firstDigit <= 0x7));
					}
					if (pseudoNode) {
						dojo.lang.assert((firstDigit >= 0x8) && (firstDigit <= 0xF));
					}
				}
				returnType = namedParameters["returnType"];
				dojo.lang.assertType(returnType, Function, {optional: true});
			} else {
				if (dojo.lang.isString(input)) {
					// input: string A 12-character hex string representing a pseudoNode or hardwareNode.
					nodeString = input;
					returnType = null;
				} else {
					if (dojo.lang.isFunction(input)) {
						// input: constructor The type of object to return. Usually String or dojo.uuid.Uuid
						nodeString = null;
						returnType = input;
					}
				}
			}
			if (nodeString) {
				dojo.lang.assert(nodeString.length == 12);
				var integer = parseInt(nodeString, HEX_RADIX);
				dojo.lang.assert(isFinite(integer));
			}
			dojo.lang.assertType(returnType, Function, {optional: true});
		}
		
		var uuidString = _generateUuidString(nodeString);
		var returnValue;
		if (returnType && (returnType != String)) {
			returnValue = new returnType(uuidString);
		} else {
			returnValue = uuidString;
		}
		return returnValue; // object
	};
}();

__CPAN_FILE__ src/uuid/Uuid.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uuid.Uuid");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.assert");

dojo.uuid.Uuid = function(/* string || generator */ input) {
	// summary: 
	//   This is the constructor for the Uuid class.  The Uuid class offers 
	//   methods for inspecting existing UUIDs.
	
	// examples:
	//   var uuid;
	//   uuid = new dojo.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//   uuid = new dojo.uuid.Uuid(); // "00000000-0000-0000-0000-000000000000"
	//   uuid = new dojo.uuid.Uuid(dojo.uuid.RandomGenerator);
	//   uuid = new dojo.uuid.Uuid(dojo.uuid.TimeBasedGenerator);
	//   dojo.uuid.Uuid.setGenerator(dojo.uuid.RandomGenerator);
	//   uuid = new dojo.uuid.Uuid();
	//   dojo.lang.assert(!uuid.isEqual(dojo.uuid.Uuid.NIL_UUID));
	this._uuidString = dojo.uuid.Uuid.NIL_UUID;
	if (input) {
		if (dojo.lang.isString(input)) {
			// input: string? A 36-character string that conforms to the UUID spec.
			this._uuidString = input.toLowerCase();
			dojo.lang.assert(this.isValid());
		} else {
			if (dojo.lang.isObject(input) && input.generate) {
				// input: generator A UUID generator, such as dojo.uuid.TimeBasedGenerator.
				var generator = input;
				this._uuidString = generator.generate();
				dojo.lang.assert(this.isValid());
			} else {
				// we got passed something other than a string
				dojo.lang.assert(false, "The dojo.uuid.Uuid() constructor must be initializated with a UUID string.");
			}
		}
	} else {
		var ourGenerator = dojo.uuid.Uuid.getGenerator();
		if (ourGenerator) {
			this._uuidString = ourGenerator.generate();
			dojo.lang.assert(this.isValid());
		}
	}
};

// -------------------------------------------------------------------
// Public constants
// -------------------------------------------------------------------
dojo.uuid.Uuid.NIL_UUID = "00000000-0000-0000-0000-000000000000";
dojo.uuid.Uuid.Version = {
	UNKNOWN: 0,
	TIME_BASED: 1,
	DCE_SECURITY: 2,
	NAME_BASED_MD5: 3,
	RANDOM: 4,
	NAME_BASED_SHA1: 5 };
dojo.uuid.Uuid.Variant = {
	NCS: "0",
	DCE: "10",
	MICROSOFT: "110",
	UNKNOWN: "111" };
dojo.uuid.Uuid.HEX_RADIX = 16;

dojo.uuid.Uuid.compare = function(/* dojo.uuid.Uuid */ uuidOne, /* dojo.uuid.Uuid */ uuidTwo) {
	// summary: 
	//   Given two UUIDs to compare, this method returns 0, 1, or -1.
	// description:
	//   This method is designed to be used by sorting routines, like the
	//   JavaScript built-in Array sort() method. This implementation is 
	//   intended to match the sample implementation in IETF RFC 4122:
	//   http://www.ietf.org/rfc/rfc4122.txt
	// uuidOne: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	// uuidTwo: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.

	// examples:
	//   var uuid;
	//   var generator = dojo.uuid.TimeBasedGenerator;
	//   var a = new dojo.uuid.Uuid(generator);
	//   var b = new dojo.uuid.Uuid(generator);
	//   var c = new dojo.uuid.Uuid(generator);
	//   var array = new Array(a, b, c);
	//   array.sort(dojo.uuid.Uuid.compare);
	var uuidStringOne = uuidOne.toString();
	var uuidStringTwo = uuidTwo.toString();
	if (uuidStringOne > uuidStringTwo) return 1;   // integer
	if (uuidStringOne < uuidStringTwo) return -1;  // integer
	return 0; // integer (either 0, 1, or -1)
};

dojo.uuid.Uuid.setGenerator = function(/* generator? */ generator) {
	// summary: 
	//   Sets the default generator, which will be used by the 
	//   "new dojo.uuid.Uuid()" constructor if no parameters
	//   are passed in.
	// generator: A UUID generator, such as dojo.uuid.TimeBasedGenerator.
	dojo.lang.assert(!generator || (dojo.lang.isObject(generator) && generator.generate));
	dojo.uuid.Uuid._ourGenerator = generator;
};

dojo.uuid.Uuid.getGenerator = function() {
	// summary: 
	//   Returns the default generator.  See setGenerator().
	return dojo.uuid.Uuid._ourGenerator; // generator (A UUID generator, such as dojo.uuid.TimeBasedGenerator).
};

dojo.uuid.Uuid.prototype.toString = function(/* string? */format) {
	// summary: 
	//   By default this method returns a standard 36-character string representing 
	//   the UUID, such as "3b12f1df-5232-4804-897e-917bf397618a".  You can also
	//   pass in an optional format specifier to request the output in any of
	//   a half dozen slight variations.
	// format: One of these strings: '{}', '()', '""', "''", 'urn', '!-'

	// examples:
	//   var uuid = new dojo.uuid.Uuid(dojo.uuid.TimeBasedGenerator);
	//   var s;
	//   s = uuid.toString();       //  eb529fec-6498-11d7-b236-000629ba5445
	//   s = uuid.toString('{}');   // {eb529fec-6498-11d7-b236-000629ba5445}
	//   s = uuid.toString('()');   // (eb529fec-6498-11d7-b236-000629ba5445)
	//   s = uuid.toString('""');   // "eb529fec-6498-11d7-b236-000629ba5445"
	//   s = uuid.toString("''");   // 'eb529fec-6498-11d7-b236-000629ba5445'
	//   s = uuid.toString('!-');   //  eb529fec649811d7b236000629ba5445
	//   s = uuid.toString('urn');  //  urn:uuid:eb529fec-6498-11d7-b236-000629ba5445
	if (format) {
		switch (format) {
			case '{}':
				return '{' + this._uuidString + '}';
				break;
			case '()':
				return '(' + this._uuidString + ')';
				break;
			case '""':
				return '"' + this._uuidString + '"';
				break;
			case "''":
				return "'" + this._uuidString + "'";
				break;
			case 'urn':
				return 'urn:uuid:' + this._uuidString;
				break;
			case '!-':
				return this._uuidString.split('-').join('');
				break;
			default:
				// we got passed something other than what we expected
				dojo.lang.assert(false, "The toString() method of dojo.uuid.Uuid was passed a bogus format.");
		}
	} else {
		return this._uuidString; // string
	}
};

dojo.uuid.Uuid.prototype.compare = function(/* dojo.uuid.Uuid */ otherUuid) {
	// summary: 
	//   Compares this UUID to another UUID, and returns 0, 1, or -1.
	// description:
	//   This implementation is intended to match the sample implementation
	//   in IETF RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return dojo.uuid.Uuid.compare(this, otherUuid); // integer (either 0, 1, or -1)
};

dojo.uuid.Uuid.prototype.isEqual = function(/* dojo.uuid.Uuid */ otherUuid) {
	// summary: 
	//   Returns true if this UUID is equal to the otherUuid, or false otherwise.
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return (this.compare(otherUuid) == 0); // boolean
};

dojo.uuid.Uuid.prototype.isValid = function() {
	// summary: 
	//   Returns true if the UUID was initialized with a valid value.
	try {
		dojo.lang.assertType(this._uuidString, String);
		dojo.lang.assert(this._uuidString.length == 36);
		dojo.lang.assert(this._uuidString == this._uuidString.toLowerCase());
		var arrayOfParts = this._uuidString.split("-");
		dojo.lang.assert(arrayOfParts.length == 5);
		dojo.lang.assert(arrayOfParts[0].length == 8);
		dojo.lang.assert(arrayOfParts[1].length == 4);
		dojo.lang.assert(arrayOfParts[2].length == 4);
		dojo.lang.assert(arrayOfParts[3].length == 4);
		dojo.lang.assert(arrayOfParts[4].length == 12);
		for (var i in arrayOfParts) {
			var part = arrayOfParts[i];
			var integer = parseInt(part, dojo.uuid.Uuid.HEX_RADIX);
			dojo.lang.assert(isFinite(integer));
		}
		return true; // boolean
	} catch (e) {
		return false; // boolean
	}
};

dojo.uuid.Uuid.prototype.getVariant = function() {
	// summary: 
	//   Returns a variant code that indicates what type of UUID this is.
	//   Returns one of the enumerated dojo.uuid.Uuid.Variant values.

	// example: 
	//   var uuid = new dojo.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//   var variant = uuid.getVariant();
	//   dojo.lang.assert(variant == dojo.uuid.Uuid.Variant.DCE);
	// example: 
	// "3b12f1df-5232-4804-897e-917bf397618a"
	//                     ^
	//                     |
	//         (variant "10__" == DCE)
	var variantCharacter = this._uuidString.charAt(19);
	var variantNumber = parseInt(variantCharacter, dojo.uuid.Uuid.HEX_RADIX);
	dojo.lang.assert((variantNumber >= 0) && (variantNumber <= 16));

	if (!dojo.uuid.Uuid._ourVariantLookupTable) {
		var Variant = dojo.uuid.Uuid.Variant;
		var lookupTable = [];

		lookupTable[0x0] = Variant.NCS;       // 0000
		lookupTable[0x1] = Variant.NCS;       // 0001
		lookupTable[0x2] = Variant.NCS;       // 0010
		lookupTable[0x3] = Variant.NCS;       // 0011

		lookupTable[0x4] = Variant.NCS;       // 0100
		lookupTable[0x5] = Variant.NCS;       // 0101
		lookupTable[0x6] = Variant.NCS;       // 0110
		lookupTable[0x7] = Variant.NCS;       // 0111

		lookupTable[0x8] = Variant.DCE;       // 1000
		lookupTable[0x9] = Variant.DCE;       // 1001
		lookupTable[0xA] = Variant.DCE;       // 1010
		lookupTable[0xB] = Variant.DCE;       // 1011

		lookupTable[0xC] = Variant.MICROSOFT; // 1100
		lookupTable[0xD] = Variant.MICROSOFT; // 1101
		lookupTable[0xE] = Variant.UNKNOWN;   // 1110
		lookupTable[0xF] = Variant.UNKNOWN;   // 1111
		
		dojo.uuid.Uuid._ourVariantLookupTable = lookupTable;
	}

	return dojo.uuid.Uuid._ourVariantLookupTable[variantNumber]; // dojo.uuid.Uuid.Variant
};

dojo.uuid.Uuid.prototype.getVersion = function() {
	// summary: 
	//   Returns a version number that indicates what type of UUID this is.
	//   Returns one of the enumerated dojo.uuid.Uuid.Version values.

	// example: 
	//   var uuid = new dojo.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//   var version = uuid.getVersion();
	//   dojo.lang.assert(version == dojo.uuid.Uuid.Version.TIME_BASED);
	// exceptions: 
	//   Throws an Error if this is not a DCE Variant UUID.
	if (!this._versionNumber) {
		var errorMessage = "Called getVersion() on a dojo.uuid.Uuid that was not a DCE Variant UUID.";
		dojo.lang.assert(this.getVariant() == dojo.uuid.Uuid.Variant.DCE, errorMessage);
	
		// "b4308fb0-86cd-11da-a72b-0800200c9a66"
		//                ^
		//                |
		//       (version 1 == TIME_BASED)
		var versionCharacter = this._uuidString.charAt(14);
		this._versionNumber = parseInt(versionCharacter, dojo.uuid.Uuid.HEX_RADIX);
	}
	return this._versionNumber; // dojo.uuid.Uuid.Version
};

dojo.uuid.Uuid.prototype.getNode = function() {
	// summary: 
	//   If this is a version 1 UUID (a time-based UUID), getNode() returns a 
	//   12-character string with the "node" or "pseudonode" portion of the UUID, 
	//   which is the rightmost 12 characters.  

	// exceptions: 
	//   Throws an Error if this is not a version 1 UUID.
	if (!this._nodeString) {
		var errorMessage = "Called getNode() on a dojo.uuid.Uuid that was not a TIME_BASED UUID.";
		dojo.lang.assert(this.getVersion() == dojo.uuid.Uuid.Version.TIME_BASED, errorMessage);

		var arrayOfStrings = this._uuidString.split('-');
		this._nodeString = arrayOfStrings[4];
	}
	return this._nodeString; // String (a 12-character string, which will look something like "917bf397618a")
};

dojo.uuid.Uuid.prototype.getTimestamp = function(/* misc. */ returnType) {
	// summary: 
	//   If this is a version 1 UUID (a time-based UUID), this method returns
	//   the timestamp value encoded in the UUID.  The caller can ask for the
	//   timestamp to be returned either as a JavaScript Date object or as a 
	//   15-character string of hex digits.
	// returnType: Any of these five values: "string", String, "hex", "date", Date

	// returns: 
	//   Returns the timestamp value as a JavaScript Date object or a 15-character string of hex digits.
	// examples: 
	//   var uuid = new dojo.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//   var date, string, hexString;
	//   date   = uuid.getTimestamp();         // returns a JavaScript Date
	//   date   = uuid.getTimestamp(Date);     // 
	//   string = uuid.getTimestamp(String);   // "Mon, 16 Jan 2006 20:21:41 GMT"
	//   hexString = uuid.getTimestamp("hex"); // "1da86cdb4308fb0"
	// exceptions: 
	//   Throws an Error if this is not a version 1 UUID.
	var errorMessage = "Called getTimestamp() on a dojo.uuid.Uuid that was not a TIME_BASED UUID.";
	dojo.lang.assert(this.getVersion() == dojo.uuid.Uuid.Version.TIME_BASED, errorMessage);
	
	if (!returnType) {returnType = null};
	switch (returnType) {
		case "string":
		case String:
			return this.getTimestamp(Date).toUTCString(); // String (e.g. "Mon, 16 Jan 2006 20:21:41 GMT")
			break;
		case "hex":
			// Return a 15-character string of hex digits containing the 
			// timestamp for this UUID, with the high-order bits first.
			if (!this._timestampAsHexString) {
				var arrayOfStrings = this._uuidString.split('-');
				var hexTimeLow = arrayOfStrings[0];
				var hexTimeMid = arrayOfStrings[1];
				var hexTimeHigh = arrayOfStrings[2];
			
				// Chop off the leading "1" character, which is the UUID 
				// version number for time-based UUIDs.
				hexTimeHigh = hexTimeHigh.slice(1);
			
				this._timestampAsHexString = hexTimeHigh + hexTimeMid + hexTimeLow;
				dojo.lang.assert(this._timestampAsHexString.length == 15);
			}
			return this._timestampAsHexString; // String (e.g. "1da86cdb4308fb0")
			break;
		case null: // no returnType was specified, so default to Date
		case "date":
		case Date:
			// Return a JavaScript Date object. 
			if (!this._timestampAsDate) {
				var GREGORIAN_CHANGE_OFFSET_IN_HOURS = 3394248;
			
				var arrayOfParts = this._uuidString.split('-');
				var timeLow = parseInt(arrayOfParts[0], dojo.uuid.Uuid.HEX_RADIX);
				var timeMid = parseInt(arrayOfParts[1], dojo.uuid.Uuid.HEX_RADIX);
				var timeHigh = parseInt(arrayOfParts[2], dojo.uuid.Uuid.HEX_RADIX);
				var hundredNanosecondIntervalsSince1582 = timeHigh & 0x0FFF;
				hundredNanosecondIntervalsSince1582 <<= 16;
				hundredNanosecondIntervalsSince1582 += timeMid;
				// What we really want to do next is shift left 32 bits, but the 
				// result will be too big to fit in an int, so we'll multiply by 2^32,
				// and the result will be a floating point approximation.
				hundredNanosecondIntervalsSince1582 *= 0x100000000;
				hundredNanosecondIntervalsSince1582 += timeLow;
				var millisecondsSince1582 = hundredNanosecondIntervalsSince1582 / 10000;
			
				// Again, this will be a floating point approximation.
				// We can make things exact later if we need to.
				var secondsPerHour = 60 * 60;
				var hoursBetween1582and1970 = GREGORIAN_CHANGE_OFFSET_IN_HOURS;
				var secondsBetween1582and1970 = hoursBetween1582and1970 * secondsPerHour;
				var millisecondsBetween1582and1970 = secondsBetween1582and1970 * 1000;
				var millisecondsSince1970 = millisecondsSince1582 - millisecondsBetween1582and1970;
			
				this._timestampAsDate = new Date(millisecondsSince1970);
			}
			return this._timestampAsDate; // Date
			break;
		default:
			// we got passed something other than a valid returnType
			dojo.lang.assert(false, "The getTimestamp() method dojo.uuid.Uuid was passed a bogus returnType: " + returnType);
			break;
	}
};

__CPAN_FILE__ src/uuid/RandomGenerator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uuid.RandomGenerator");

dojo.uuid.RandomGenerator = new function() {
	this.generate = function(/* constructor? */ returnType) {
		// summary: 
		//   This function generates random UUIDs, meaning "version 4" UUIDs.
		// description: 
		//   A typical generated value would be something like this:
		//   "3b12f1df-5232-4804-897e-917bf397618a"
		// returnType: The type of object to return. Usually String or dojo.uuid.Uuid

		// examples: 
		//   var string = dojo.uuid.RandomGenerator.generate();
		//   var string = dojo.uuid.RandomGenerator.generate(String);
		//   var uuid   = dojo.uuid.RandomGenerator.generate(dojo.uuid.Uuid);

		dojo.unimplemented('dojo.uuid.RandomGenerator.generate');
		// FIXME:
		// For an algorithm to generate a random UUID, see
		// sections 4.4 and 4.5 of RFC 4122:
		//  http://www.ietf.org/rfc/rfc4122.txt
		
		var returnValue = "00000000-0000-0000-0000-000000000000"; // FIXME
		if (returnType && (returnType != String)) {
			returnValue = new returnType(returnValue);
		}
		return returnValue; // object
	};
}();

__CPAN_FILE__ src/uuid/NilGenerator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uuid.NilGenerator");

dojo.uuid.NilGenerator = new function() {
	this.generate = function(/* constructor? */ returnType) {
		// summary: 
		//   This function returns the Nil UUID: "00000000-0000-0000-0000-000000000000".
		// description: 
		//   The Nil UUID is described in section 4.1.7 of
		//   RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
		// returnType: The type of object to return. Usually String or dojo.uuid.Uuid

		// examples: 
		//   var string = dojo.uuid.NilGenerator.generate();
		//   var string = dojo.uuid.NilGenerator.generate(String);
		//   var uuid   = dojo.uuid.NilGenerator.generate(dojo.uuid.Uuid);
		var returnValue = "00000000-0000-0000-0000-000000000000";
		if (returnType && (returnType != String)) {
			returnValue = new returnType(returnValue);
		}
		return returnValue; // object
	};
}();
__CPAN_FILE__ src/uuid/__package__.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.kwCompoundRequire({
	common: [
		"dojo.uuid.Uuid",
		"dojo.uuid.LightweightGenerator",
		"dojo.uuid.RandomGenerator",
		"dojo.uuid.TimeBasedGenerator",
		"dojo.uuid.NameBasedGenerator",
		"dojo.uuid.NilGenerator"
	]
});
dojo.provide("dojo.uuid.*");


__CPAN_FILE__ src/uuid/LightweightGenerator.js
/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.uuid.LightweightGenerator");

/*
 * summary:
 *   The LightweightGenerator is intended to be small and fast,
 *   but not necessarily good.
 * 
 * description:
 *   Small: The LightweightGenerator has a small footprint. 
 *   Once comments are stripped, it's only about 25 lines of 
 *   code, and it doesn't dojo.require() any other packages.
 *
 *   Fast: The LightweightGenerator can generate lots of new 
 *   UUIDs fairly quickly (at least, more quickly than the other 
 *   dojo UUID generators).
 *
 *   Not necessarily good: We use Math.random() as our source
 *   of randomness, which may or may not provide much randomness. 
 */
 
dojo.uuid.LightweightGenerator = new function() {
	var HEX_RADIX = 16;

	function _generateRandomEightCharacterHexString() {
		// Make random32bitNumber be a randomly generated floating point number
		// between 0 and (4,294,967,296 - 1), inclusive.
		var random32bitNumber = Math.floor( (Math.random() % 1) * Math.pow(2, 32) );
		var eightCharacterHexString = random32bitNumber.toString(HEX_RADIX);
		while (eightCharacterHexString.length < 8) {
			eightCharacterHexString = "0" + eightCharacterHexString;
		}
		return eightCharacterHexString; // for example: "3B12F1DF"
	}

	this.generate = function(/* constructor? */ returnType) {
		// summary: 
		//   This function generates random UUIDs, meaning "version 4" UUIDs.
		// description: 
		//   A typical generated value would be something like this:
		//   "3b12f1df-5232-4804-897e-917bf397618a"
		// returnType: The type of object to return. Usually String or dojo.uuid.Uuid

		// examples: 
		//   var string = dojo.uuid.LightweightGenerator.generate();
		//   var string = dojo.uuid.LightweightGenerator.generate(String);
		//   var uuid   = dojo.uuid.LightweightGenerator.generate(dojo.uuid.Uuid);
		var hyphen = "-";
		var versionCodeForRandomlyGeneratedUuids = "4"; // 8 == binary2hex("0100")
		var variantCodeForDCEUuids = "8"; // 8 == binary2hex("1000")
		var a = _generateRandomEightCharacterHexString();
		var b = _generateRandomEightCharacterHexString();
		b = b.substring(0, 4) + hyphen + versionCodeForRandomlyGeneratedUuids + b.substring(5, 8);
		var c = _generateRandomEightCharacterHexString();
		c = variantCodeForDCEUuids + c.substring(1, 4) + hyphen + c.substring(4, 8);
		var d = _generateRandomEightCharacterHexString();
		var returnValue = a + hyphen + b + hyphen + c + d;
		returnValue = returnValue.toLowerCase();
		if (returnType && (returnType != String)) {
			returnValue = new returnType(returnValue);
		}
		return returnValue;
	};
}();

