You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/02/01 06:41:23 UTC

svn commit: r373998 [10/23] - in /jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo: ./ src/ src/alg/ src/animation/ src/collections/ src/crypto/ src/data/ src/dnd/ src/event/ src/flash/ src/flash/flash6/ src/flash/flash8/ src/fx/...

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/IframeIO.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/IframeIO.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/IframeIO.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/IframeIO.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,239 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.*");
+
+dojo.io.createIFrame = function(fname, onloadstr){
+	if(window[fname]){ return window[fname]; }
+	if(window.frames[fname]){ return window.frames[fname]; }
+	var r = dojo.render.html;
+	var cframe = null;
+	var turi = 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;
+	}
+	(document.body||document.getElementsByTagName("body")[0]).appendChild(cframe);
+	window[fname] = cframe;
+	with(cframe.style){
+		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;
+}
+
+// thanks burstlib!
+dojo.io.iframeContentWindow = function(iframe_el) {
+	var win = iframe_el.contentWindow || // IE
+		dojo.io.iframeContentDocument(iframe_el).defaultView || // Moz, opera
+		// Moz. TODO: is this available when defaultView isn't?
+		dojo.io.iframeContentDocument(iframe_el).__parent__ || 
+		(iframe_el.name && document.frames[iframe_el.name]) || null;
+	return win;
+}
+
+dojo.io.iframeContentDocument = 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;
+}
+
+dojo.io.IframeTransport = new function(){
+	var _this = this;
+	this.currentRequest = null;
+	this.requestQueue = [];
+	this.iframeName = "dojoIoIframe";
+
+	this.fireNextRequest = function(){
+		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.indexOf("?") > -1 ? "&" : "?") + query;
+			dojo.io.setIFrameSrc(this.iframe, tmpUrl, true);
+		}
+	}
+
+	this.canHandle = function(kwArgs){
+		return (
+			(
+				// FIXME: can we really handle text/plain and
+				// text/javascript requests?
+				dojo.lang.inArray(kwArgs["mimetype"], 
+				[	"text/plain", "text/html", 
+					"application/xml", "text/xml", 
+					"text/javascript", "text/json"])
+			)&&(
+				// make sur we really only get used in file upload cases	
+				(kwArgs["formNode"])&&(dojo.io.checkChildrenForFile(kwArgs["formNode"]))
+			)&&(
+				dojo.lang.inArray(kwArgs["method"].toLowerCase(), ["post", "get"])
+			)&&(
+				// never handle a sync request
+				!  ((kwArgs["sync"])&&(kwArgs["sync"] == true))
+			)
+		);
+	}
+
+	this.bind = function(kwArgs){
+		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(){
+		if(!_this.currentRequest){
+			_this.fireNextRequest();
+			return;
+		}
+
+		var req = _this.currentRequest;
+
+		// remove all the hidden content inputs
+		var toClean = req._contentToClean;
+		for(var i = 0; i < toClean.length; i++) {
+			var key = toClean[i];
+			var input = req.formNode[key];
+			req.formNode.removeChild(input);
+			req.formNode[key] = null;
+		}
+		// restore original action + target
+		req.formNode.setAttribute("action", req._originalAction);
+		req.formNode.setAttribute("target", req._originalTarget);
+		req.formNode.target = req._originalTarget;
+
+		var ifr = _this.iframe;
+		var ifw = dojo.io.iframeContentWindow(ifr);
+		// handle successful returns
+		// FIXME: how do we determine success for iframes? Is there an equiv of
+		// the "status" property?
+		var value;
+		var success = false;
+
+		try{
+			var cmt = req.mimetype;
+			if((cmt == "text/javascript")||(cmt == "text/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 cd = dojo.io.iframeContentDocument(_this.iframe);
+				var js = cd.getElementsByTagName("textarea")[0].value;
+				if(cmt == "text/json") { js = "(" + js + ")"; }
+				value = dj_eval(js);
+			}else if((cmt == "application/xml")||(cmt == "text/xml")){
+				value = dojo.io.iframeContentDocument(_this.iframe);
+			}else{ // text/plain
+				value = ifw.innerHTML;
+			}
+			success = true;
+		}catch(e){ 
+			// looks like we didn't get what we wanted!
+			var errObj = new dojo.io.Error("IframeTransport Error");
+			if(dojo.lang.isFunction(req["error"])){
+				req.error("error", errObj, req);
+			}
+		}
+
+		// 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();
+		}
+	}
+
+	dojo.io.transports.addTransport("IframeTransport");
+}
+
+dojo.addOnLoad(function(){
+	dojo.io.IframeTransport.setUpIframe();
+});

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RepubsubIO.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RepubsubIO.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RepubsubIO.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RepubsubIO.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,524 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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.Event");
+dojo.require("dojo.event.BrowserEvent");
+dojo.require("dojo.io.BrowserIO");
+
+dojo.provide("dojo.io.RepubsubIO");
+dojo.provide("dojo.io.repubsub");
+dojo.provide("dojo.io.repubsubTransport");
+
+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 = function(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;
+}

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RhinoIO.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RhinoIO.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RhinoIO.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/RhinoIO.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,22 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");
+
+// TODO: this doesn't execute
+/*dojo.io.SyncHTTPRequest = function(){
+	dojo.io.SyncRequest.call(this);
+
+	this.send = function(URI){
+	}
+}
+
+dojo.inherits(dojo.io.SyncHTTPRequest, dojo.io.SyncRequest);
+*/

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/__package__.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/__package__.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/__package__.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/__package__.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,17 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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.conditionalLoadModule({
+	common: ["dojo.io"],
+	rhino: ["dojo.io.RhinoIO"],
+	browser: ["dojo.io.BrowserIO", "dojo.io.cookie"],
+	dashboard: ["dojo.io.BrowserIO", "dojo.io.cookie"]
+});
+dojo.hostenv.moduleLoaded("dojo.io.*");

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookie.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookie.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookie.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookie.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,103 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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) {
+	var idx = document.cookie.indexOf(name+'=');
+	if(idx == -1) { return null; }
+	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; }

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookies.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookies.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookies.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/io/cookies.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,14 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dj_deprecated("dojo.io.cookies has been replaced by dojo.io.cookie");
+dojo.require("dojo.io.cookie");
+if(!dojo.io.cookies) { dojo.io.cookies = dojo.io.cookie; }
+dojo.provide("dojo.io.cookies");

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/json.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/json.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/json.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/json.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,135 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.lang.repr");
+dojo.require("dojo.AdapterRegistry");
+
+dojo.json = {
+	jsonRegistry: new dojo.AdapterRegistry(),
+
+	register: function(name, check, wrap, /*optional*/ override){
+		/***
+
+			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.
+		***/
+
+		dojo.json.jsonRegistry.register(name, check, wrap, override);
+	},
+
+	evalJson: function(/* jsonString */ json){
+		// FIXME: should this accept mozilla's optional second arg?
+		try {
+			return eval("(" + json + ")");
+		}catch(e){
+			dojo.debug(e);
+			return json;
+		}
+	},
+
+	evalJSON: dojo.lang.forward("evalJson"),
+
+	serialize: function(o){
+		/***
+			Create a JSON serialization of an object, note that this doesn't
+			check for infinite recursion, so don't do that!
+		***/
+
+		var objtype = typeof(o);
+		if(objtype == "undefined"){
+			return "undefined";
+		}else if((objtype == "number")||(objtype == "boolean")){
+			return o + "";
+		}else if(o === null){
+			return "null";
+		}
+		var m = dojo.lang;
+		if(objtype == "string"){
+			return m.reprString(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 = m.reprString(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(",") + "}";
+	}
+};

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,14 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.provide("dojo.lang.Lang");
+
+dojo.require("dojo.lang.common");

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/Lang.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/Lang.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/Lang.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/Lang.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,12 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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");
+dj_deprecated("dojo.lang.Lang is deprecated, use dojo.lang instead");

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/__package__.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/__package__.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/__package__.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/__package__.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,23 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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.conditionalLoadModule({
+	common: [
+		"dojo.lang",
+		"dojo.lang.common",
+		"dojo.lang.assert",
+		"dojo.lang.array",
+		"dojo.lang.type",
+		"dojo.lang.func",
+		"dojo.lang.extras",
+		"dojo.lang.repr"
+	]
+});
+dojo.hostenv.moduleLoaded("dojo.lang.*");

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/array.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/array.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/array.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/array.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,175 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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(obj, name){
+	return (typeof obj[name] !== 'undefined');
+}
+
+dojo.lang.isEmpty = function(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.forEach = function(arr, unary_func, fix_length){
+	var isString = dojo.lang.isString(arr);
+	if(isString) { arr = arr.split(""); }
+	var il = arr.length;
+	for(var i=0; i< ((fix_length) ? il : arr.length); i++){
+		if(unary_func(arr[i], i, arr) == "break"){
+			break;
+		}
+	}
+}
+
+dojo.lang.map = function(arr, obj, unary_func){
+	var isString = dojo.lang.isString(arr);
+	if(isString){
+		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("");
+	} else {
+		return outArr;
+	}
+}
+
+dojo.lang.every = function(arr, callback, thisObject) {
+	var isString = dojo.lang.isString(arr);
+	if(isString) { arr = arr.split(""); }
+	if(Array.every) {
+		return Array.every(arr, callback, thisObject);
+	} else {
+		if(!thisObject) {
+			if(arguments.length >= 3) { dojo.raise("thisObject doesn't exist!"); }
+			thisObject = dj_global;
+		}
+
+		for(var i = 0; i < arr.length; i++) {
+			if(!callback.call(thisObject, arr[i], i, arr)) {
+				return false;
+			}
+		}
+		return true;
+	}
+}
+
+dojo.lang.some = function(arr, callback, thisObject) {
+	var isString = dojo.lang.isString(arr);
+	if(isString) { arr = arr.split(""); }
+	if(Array.some) {
+		return Array.some(arr, callback, thisObject);
+	} else {
+		if(!thisObject) {
+			if(arguments.length >= 3) { dojo.raise("thisObject doesn't exist!"); }
+			thisObject = dj_global;
+		}
+
+		for(var i = 0; i < arr.length; i++) {
+			if(callback.call(thisObject, arr[i], i, arr)) {
+				return true;
+			}
+		}
+		return false;
+	}
+}
+
+dojo.lang.filter = function(arr, callback, thisObject) {
+	var isString = dojo.lang.isString(arr);
+	if(isString) { arr = arr.split(""); }
+	if(Array.filter) {
+		var outArr = Array.filter(arr, callback, thisObject);
+	} else {
+		if(!thisObject) {
+			if(arguments.length >= 3) { dojo.raise("thisObject doesn't exist!"); }
+			thisObject = dj_global;
+		}
+
+		var 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("");
+	} else {
+		return outArr;
+	}
+}
+
+/**
+ * Creates a 1-D array out of all the arguments passed,
+ * unravelling any array-like objects in the process
+ *
+ * Ex:
+ * unnest(1, 2, 3) ==> [1, 2, 3]
+ * unnest(1, [2, [3], [[[4]]]]) ==> [1, 2, 3, 4]
+ */
+dojo.lang.unnest = function(/* ... */) {
+	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;
+}
+
+/**
+ * Converts an array-like object (i.e. arguments, DOMCollection)
+ * to an array
+**/
+dojo.lang.toArray = function(arrayLike, startOffset) {
+	var array = [];
+	for(var i = startOffset||0; i < arrayLike.length; i++) {
+		array.push(arrayLike[i]);
+	}
+	return array;
+}

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/assert.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/assert.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/assert.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/assert.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,121 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");
+
+// -------------------------------------------------------------------
+// Assertion methods
+// -------------------------------------------------------------------
+
+/**
+ * Throws an exception if the assertion fails.
+ *
+ * If the asserted condition is true, this method does nothing. If the
+ * condition is false, we throw an error with a error message.  
+ *
+ * @param	booleanValue	A boolean value, which needs to be true for the assertion to succeed.
+ * @param	message	Optional. A string describing the assertion.
+ * @throws	Throws an Error if 'booleanValue' is false.
+ */
+dojo.lang.assert = function(booleanValue, message){
+	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);
+	}
+}
+
+/**
+ * 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.
+ *
+ * Examples:
+ * <pre>
+ *   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);
+ * </pre>
+ *
+ * @scope	public function
+ * @param	value	Any literal value or object instance.
+ * @param	type	A class of object, or a literal type, or the string name of a type, or an array with a list of types.
+ * @param	message	Optional. A string describing the assertion.
+ * @throws	Throws an Error if 'value' is not of type 'type'.
+ */
+dojo.lang.assertType = function(value, type, message){
+	if(!dojo.lang.isOfType(value, type)){
+		if(!message){
+			if(!dojo.lang.assertType._errorMessage){
+				dojo.lang.assertType._errorMessage = "Type mismatch: dojo.lang.assertType() failed.";
+			}
+			message = dojo.lang.assertType._errorMessage;
+		}
+		dojo.lang.assert(false, message);
+	}
+}
+
+/**
+ * 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.
+ *
+ * Examples:
+ * <pre>
+ *   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});
+ * </pre>
+ *
+ * @scope	public function
+ * @param	object	An anonymous object.
+ * @param	expectedProperties	An array of strings (or an object with all the expected properties).
+ * @param	message	Optional. A string describing the assertion.
+ * @throws	Throws an Error if 'value' is not of type 'type'.
+ */
+dojo.lang.assertValidKeywords = function(object, expectedProperties, message){
+	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);
+			}
+		}
+	}
+}

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/common.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/common.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/common.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/common.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,162 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.require("dojo.lang");
+
+dojo.lang.mixin = function(obj, props){
+	var tobj = {};
+	for(var x in props){
+		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 && dojo.lang.isFunction(props["toString"]) && props["toString"] != obj["toString"]) {
+		obj.toString = props.toString;
+	}
+	return obj;
+}
+
+dojo.lang.extend = function(ctor, props){
+	this.mixin(ctor.prototype, props);
+}
+
+/**
+ * See if val is in arr. Call signatures:
+ *  find(array, value, identity) // recommended
+ *  find(value, array, identity)
+**/
+dojo.lang.find = function(arr, val, identity, findLast){
+	// support both (arr, val) and (val, arr)
+	if(!dojo.lang.isArrayLike(arr) && dojo.lang.isArrayLike(val)) {
+		var a = arr;
+		arr = val;
+		val = a;
+	}
+	var isString = dojo.lang.isString(arr);
+	if(isString) { arr = arr.split(""); }
+
+	if(findLast) {
+		var step = -1;
+		var i = arr.length - 1;
+		var end = -1;
+	} else {
+		var step = 1;
+		var i = 0;
+		var end = arr.length;
+	}
+	if(identity){
+		while(i != end) {
+			if(arr[i] === val){ return i; }
+			i += step;
+		}
+	}else{
+		while(i != end) {
+			if(arr[i] == val){ return i; }
+			i += step;
+		}
+	}
+	return -1;
+}
+
+dojo.lang.indexOf = dojo.lang.find;
+
+dojo.lang.findLast = function(arr, val, identity) {
+	return dojo.lang.find(arr, val, identity, true);
+}
+
+dojo.lang.lastIndexOf = dojo.lang.findLast;
+
+dojo.lang.inArray = function(arr, val){
+	return dojo.lang.find(arr, val) > -1;
+}
+
+/**
+ * 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(wh) {
+	return typeof wh == "object" || dojo.lang.isArray(wh) || dojo.lang.isFunction(wh);
+}
+
+dojo.lang.isArray = function(wh) {
+	return (wh instanceof Array || typeof wh == "array");
+}
+
+dojo.lang.isArrayLike = function(wh) {
+	if(dojo.lang.isString(wh)){ return false; }
+	if(dojo.lang.isFunction(wh)){ return false; } // keeps out built-in ctors (Number, String, ...) which have length properties
+	if(dojo.lang.isArray(wh)){ return true; }
+	if(typeof wh != "undefined" && wh
+		&& dojo.lang.isNumber(wh.length) && isFinite(wh.length)){ return true; }
+	return false;
+}
+
+dojo.lang.isFunction = function(wh) {
+	return (wh instanceof Function || typeof wh == "function");
+}
+
+dojo.lang.isString = function(wh) {
+	return (wh instanceof String || typeof wh == "string");
+}
+
+dojo.lang.isAlien = function(wh) {
+	return !dojo.lang.isFunction() && /\{\s*\[native code\]\s*\}/.test(String(wh));
+}
+
+dojo.lang.isBoolean = function(wh) {
+	return (wh instanceof Boolean || typeof wh == "boolean");
+}
+
+/**
+ * The following is***() functions are somewhat "unsafe". Fortunately,
+ * there are workarounds the the language provides and are mentioned
+ * in the WARNING messages.
+ *
+ * WARNING: In most cases, isNaN(wh) 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 (arr["1"] is the same as
+ * arr[1]) and isNaN will return false for both values ("1" and 1). Should you
+ * use isNumber("1"), that 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(wh) when possible
+ */
+dojo.lang.isNumber = function(wh) {
+	return (wh instanceof Number || typeof wh == "number");
+}
+
+/**
+ * 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
+ *
+ * FIXME: Should isUndefined go away since it is error prone?
+ */
+dojo.lang.isUndefined = function(wh) {
+	return ((wh == undefined)&&(typeof wh == "undefined"));
+}
+
+// end Crockford functions

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/extras.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/extras.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/extras.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/extras.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,74 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.require("dojo.lang.type");
+
+/**
+ * Sets a timeout in milliseconds to execute a function in a given context
+ * with optional arguments.
+ *
+ * setTimeout (Object context, function func, number delay[, arg1[, ...]]);
+ * setTimeout (function func, number delay[, arg1[, ...]]);
+ */
+dojo.lang.setTimeout = function(func, delay){
+	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 setTimeout(function () { func.apply(context, args); }, delay);
+}
+
+dojo.lang.getNameInObj = function(ns, item){
+	if(!ns){ ns = dj_global; }
+
+	for(var x in ns){
+		if(ns[x] === item){
+			return new String(x);
+		}
+	}
+	return null;
+}
+
+dojo.lang.shallowCopy = function(obj) {
+	var ret = {}, key;
+	for(key in obj) {
+		if(dojo.lang.isUndefined(ret[key])) {
+			ret[key] = obj[key];
+		}
+	}
+	return ret;
+}
+
+/**
+ * Return the first argument that isn't undefined
+ */
+dojo.lang.firstValued = function(/* ... */) {
+	for(var i = 0; i < arguments.length; i++) {
+		if(typeof arguments[i] != "undefined") {
+			return arguments[i];
+		}
+	}
+	return undefined;
+}

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/func.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/func.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/func.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/func.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,146 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");
+dojo.require("dojo.lang.type");
+
+/**
+ * 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) {
+	if(dojo.lang.isString(method)) {
+		var fcn = thisObject[method];
+	} else {
+		var fcn = method;
+	}
+
+	return function() {
+		return fcn.apply(thisObject, arguments);
+	}
+}
+
+dojo.lang.anonCtr = 0;
+dojo.lang.anon = {};
+dojo.lang.nameAnonFunc = function(anonFuncPtr, namespaceObj){
+	var nso = (namespaceObj || dojo.lang.anon);
+	if((dj_global["djConfig"])&&(djConfig["slowAnonFuncLookups"] == true)){
+		for(var x in nso){
+			if(nso[x] === anonFuncPtr){
+				return x;
+			}
+		}
+	}
+	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]);
+	}
+	var ecount = 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);
+}

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/repr.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/repr.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/repr.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/repr.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,92 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.lang.reprRegistry = new dojo.AdapterRegistry();
+dojo.lang.registerRepr = function(name, check, wrap, /*optional*/ override){
+        /***
+			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(obj){
+	/***
+		Return a "programmer representation" for an object
+	***/
+	if(typeof(obj) == "undefined"){
+		return "undefined";
+	}else if(obj === null){
+		return "null";
+	}
+
+	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 o.NAME;
+		}
+	}
+
+	if(typeof(obj) == "function"){
+		obj = (obj + "").replace(/^\s+/, "");
+		var idx = obj.indexOf("{");
+		if(idx != -1){
+			obj = obj.substr(0, idx) + "{...}";
+		}
+	}
+	return obj + "";
+}
+
+dojo.lang.reprArrayLike = function(arr){
+	try{
+		var na = dojo.lang.map(arr, dojo.lang.repr);
+		return "[" + na.join(", ") + "]";
+	}catch(e){ }
+};
+
+dojo.lang.reprString = function(str){ 
+	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");
+};
+
+dojo.lang.reprNumber = function(num){
+	return num + "";
+};
+
+(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);
+})();

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/type.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/type.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/type.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/lang/type.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,202 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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(wh) {
+	try {
+		if(dojo.lang.isArray(wh)) { return "array"; }
+		if(dojo.lang.isFunction(wh)) { return "function"; }
+		if(dojo.lang.isString(wh)) { return "string"; }
+		if(dojo.lang.isNumber(wh)) { return "number"; }
+		if(dojo.lang.isBoolean(wh)) { return "boolean"; }
+		if(dojo.lang.isAlien(wh)) { return "alien"; }
+		if(dojo.lang.isUndefined(wh)) { return "undefined"; }
+		// FIXME: should this go first?
+		for(var name in dojo.lang.whatAmI.custom) {
+			if(dojo.lang.whatAmI.custom[name](wh)) {
+				return name;
+			}
+		}
+		if(dojo.lang.isObject(wh)) { return "object"; }
+	} catch(E) {}
+	return "unknown";
+}
+/*
+ * dojo.lang.whatAmI.custom[typeName] = someFunction
+ * will return typeName is someFunction(wh) returns true
+ */
+dojo.lang.whatAmI.custom = {};
+
+/**
+ * Returns true for values that commonly represent numbers.
+ *
+ * Examples:
+ * <pre>
+ *   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
+ * </pre>
+ */
+dojo.lang.isNumeric = function(wh){
+	return (!isNaN(wh) && isFinite(wh) && (wh != null) &&
+			!dojo.lang.isBoolean(wh) && !dojo.lang.isArray(wh));
+}
+
+/**
+ * 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.
+ */
+dojo.lang.isBuiltIn = function(wh){
+	return (dojo.lang.isArray(wh)		|| 
+			dojo.lang.isFunction(wh)	|| 
+			dojo.lang.isString(wh)		|| 
+			dojo.lang.isNumber(wh)		|| 
+			dojo.lang.isBoolean(wh)		|| 
+			(wh == null)				|| 
+			(wh instanceof Error)		|| 
+			(typeof wh == "error") );
+}
+
+/**
+ * Returns true for any object where the value of the 
+ * property 'constructor' is 'Object'.  
+ * 
+ * Examples:
+ * <pre>
+ *   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
+ * </pre>
+ */
+dojo.lang.isPureObject = function(wh){
+	return ((wh != null) && dojo.lang.isObject(wh) && wh.constructor == Object);
+}
+
+/**
+ * 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.
+ *
+ * Examples:
+ * <pre>
+ *   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(xxxxx, 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(xxxxx, "undefined");               // returns true
+ * </pre>
+ *
+ * @param	value	Any literal value or object instance.
+ * @param	type	A class of object, or a literal type, or the string name of a type, or an array with a list of types.
+ * @return	Returns a boolean
+ */
+dojo.lang.isOfType = function(value, type) {
+	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;
+			}
+		}
+		return false;
+	}else{
+		if(dojo.lang.isString(type)){
+			type = type.toLowerCase();
+		}
+		switch (type) {
+			case Array:
+			case "array":
+				return dojo.lang.isArray(value);
+				break;
+			case Function:
+			case "function":
+				return dojo.lang.isFunction(value);
+				break;
+			case String:
+			case "string":
+				return dojo.lang.isString(value);
+				break;
+			case Number:
+			case "number":
+				return dojo.lang.isNumber(value);
+				break;
+			case "numeric":
+				return dojo.lang.isNumeric(value);
+				break;
+			case Boolean:
+			case "boolean":
+				return dojo.lang.isBoolean(value);
+				break;
+			case Object:
+			case "object":
+				return dojo.lang.isObject(value);
+				break;
+			case "pureobject":
+				return dojo.lang.isPureObject(value);
+				break;
+			case "builtin":
+				return dojo.lang.isBuiltIn(value);
+				break;
+			case "alien":
+				return dojo.lang.isAlien(value);
+				break;
+			case "undefined":
+				return dojo.lang.isUndefined(value);
+				break;
+			case null:
+			case "null":
+				return (value === null);
+				break;
+			case "optional":
+				return ((value === null) || dojo.lang.isUndefined(value));
+				break;
+			default:
+				if (dojo.lang.isFunction(type)) {
+					return (value instanceof type);
+				} else {
+					dojo.raise("dojo.lang.isOfType() was passed an invalid type");
+				}
+				break;
+		}
+	}
+	dojo.raise("If we get here, it means a bug was introduced above.");
+}

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/Logger.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/Logger.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/Logger.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/Logger.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,408 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free 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 stolen from nWidgets, 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.provide("dojo.log");
+dojo.require("dojo.lang");
+
+/*
+	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 = msg;
+	this.time = new Date();
+	// 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.lang.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){
+		var na = [dojo.logging.log.getLevel(type)];
+		if(typeof args == "array"){
+			na = na.concat(args);
+		}else if((typeof args == "object")&&(args["length"])){
+			na = na.concat(this.argsToArr(args));
+			/* for(var x=0; x<args.length; x++){
+				na.push(args[x]);
+			} */
+		}else{
+			na = na.concat(this.argsToArr(arguments).slice(1));
+			/* for(var x=1; x<arguments.length; x++){
+				na.push(arguments[x]);
+			} */
+		}
+		return this.log.apply(this, na);
+	}
+});
+
+void(function(){
+	var ptype = dojo.logging.Logger.prototype;
+	ptype.warn = ptype.warning;
+	ptype.err = ptype.error;
+	ptype.crit = ptype.critical;
+})();
+
+// the Handler class
+dojo.logging.LogHandler = function(level){
+	this.cutOffLevel = (level) ? level : 0;
+	this.formatter = null; // FIXME: default formatter?
+	this.data = [];
+	this.filters = [];
+}
+
+dojo.logging.LogHandler.prototype.setFormatter = function(fmtr){
+	// FIXME: need to vet that it is indeed a formatter object
+	dj_unimplemented("setFormatter");
+}
+
+dojo.logging.LogHandler.prototype.flush = function(){
+	dj_unimplemented("flush");
+}
+
+dojo.logging.LogHandler.prototype.close = function(){
+	dj_unimplemented("close");
+}
+
+dojo.logging.LogHandler.prototype.handleError = function(){
+	dj_unimplemented("handleError");
+}
+
+dojo.logging.LogHandler.prototype.handle = function(record){
+	// emits the passed record if it passes this object's filters
+	if((this.filter(record))&&(record.level>=this.cutOffLevel)){
+		this.emit(record);
+	}
+}
+
+dojo.logging.LogHandler.prototype.emit = function(record){
+	// do whatever is necessaray to actually log the record
+	dj_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);
+	
+}
+// prototype inheritance
+dojo.logging.MemoryLogHandler.prototype = new dojo.logging.LogHandler();
+
+// FIXME
+// dj_inherits(dojo.logging.MemoryLogHandler, 
+
+// over-ride base-class
+dojo.logging.MemoryLogHandler.prototype.emit = function(record){
+	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);
+// actual logging event handler
+dojo.logging.logQueueHandler.emit = function(record){
+	// we should probably abstract this in the future
+	var logStr = String(dojo.log.getLevelName(record.level)+": "+record.time.toLocaleTimeString())+": "+record.message;
+	if(!dj_undef("debug", dj_global)){
+		dojo.debug(logStr);
+	}else if((typeof dj_global["print"] == "function")&&(!dojo.render.html.capable)){
+		print(logStr);
+	}
+	this.data.push(record);
+	if(this.numRecords != -1){
+		while(this.data.length>this.numRecords){
+			this.data.shift();
+		}
+	}
+}
+
+dojo.logging.log.addHandler(dojo.logging.logQueueHandler);
+dojo.log = dojo.logging.log;

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/__package__.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/__package__.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/__package__.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/logging/__package__.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,15 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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.conditionalLoadModule({
+	common: ["dojo.logging.Logger", false, false],
+	rhino: ["dojo.logging.RhinoLogger"]
+});
+dojo.hostenv.moduleLoaded("dojo.logging.*");

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/math.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/math.js?rev=373998&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/math.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/math.js Tue Jan 31 21:39:49 2006
@@ -0,0 +1,134 @@
+/*
+	Copyright (c) 2004-2005, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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 (x) { return (x*Math.PI) / 180; }
+dojo.math.radToDeg = function (x) { return (x*180) / Math.PI; }
+
+dojo.math.factorial = function (n) {
+	if(n<1){ return 0; }
+	var retVal = 1;
+	for(var i=1;i<=n;i++){ retVal *= i; }
+	return retVal;
+}
+
+//The number of ways of obtaining an ordered subset of k elements from a set of n elements
+dojo.math.permutations = function (n,k) {
+	if(n==0 || k==0) return 1;
+	return (dojo.math.factorial(n) / dojo.math.factorial(n-k));
+}
+
+//The number of ways of picking n unordered outcomes from r possibilities
+dojo.math.combinations = function (n,r) {
+	if(n==0 || r==0) return 1;
+	return (dojo.math.factorial(n) / (dojo.math.factorial(n-r) * dojo.math.factorial(r)));
+}
+
+dojo.math.bernstein = function (t,n,i) {
+	return (dojo.math.combinations(n,i) * Math.pow(t,i) * Math.pow(1-t,n-i));
+}
+
+/**
+ * Returns random numbers with a Gaussian distribution, with the mean set at
+ * 0 and the variance set at 1.
+ *
+ * @return A random number from a Gaussian distribution
+ */
+dojo.math.gaussianRandom = function () {
+	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;
+}
+
+/**
+ * Calculates the mean of an Array of numbers.
+ *
+ * @return The mean of the numbers in the Array
+ */
+dojo.math.mean = function () {
+	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;
+}
+
+/**
+ * Extends Math.round by adding a second argument specifying the number of
+ * decimal places to round to.
+ *
+ * @param number The number to round
+ * @param places The number of decimal places to round to
+ * @return The rounded number
+ */
+// TODO: add support for significant figures
+dojo.math.round = function (number, places) {
+	if (!places) { var shift = 1; }
+	else { var shift = Math.pow(10, places); }
+	return Math.round(number * shift) / shift;
+}
+
+/**
+ * Calculates the standard deviation of an Array of numbers
+ *
+ * @return The standard deviation of the numbers
+ */
+dojo.math.sd = function () {
+	var array = dojo.lang.isArray(arguments[0]) ? arguments[0] : arguments;
+	return Math.sqrt(dojo.math.variance(array));
+}
+
+/**
+ * Calculates the variance of an Array of numbers
+ *
+ * @return The variance of the numbers
+ */
+dojo.math.variance = function () {
+	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);
+}
+
+/**
+ * Like range() in python
+**/
+dojo.math.range = function(a, b, step) {
+    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;
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org