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/05/23 01:11:13 UTC

svn commit: r408783 [4/27] - in /tapestry/tapestry4/trunk: examples/TimeTracker/src/context/ framework/src/descriptor/META-INF/ framework/src/java/org/apache/tapestry/ framework/src/java/org/apache/tapestry/dojo/ framework/src/java/org/apache/tapestry/...

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/flash6_gateway.swf
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/flash6_gateway.swf?rev=408783&view=auto
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry4/trunk/framework/src/js/dojo/flash6_gateway.swf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/iframe_history.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/iframe_history.html?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/iframe_history.html (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/iframe_history.html Mon May 22 16:10:12 2006
@@ -0,0 +1,50 @@
+<!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>The Dojo Toolkit</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
+	<script type="text/javascript">
+	// <!--
+	var noInit = false;
+	var domain = "";
+	// document.domain = "localhost";
+	function init(){
+		// parse the query string if there is one to try to get args that
+		// we can act on
+		var sparams = document.location.search;
+		if(sparams.length >= 0){
+			if(sparams.charAt(0) == "?"){
+				sparams = sparams.substring(1);
+			}
+			var ss = (sparams.indexOf("&amp;") >= 0) ? "&amp;" : "&";
+			sparams = sparams.split(ss);
+			for(var x=0; x<sparams.length; x++){
+				var tp = sparams[x].split("=");
+				if(typeof window[tp[0]] != "undefined"){
+					window[tp[0]] = ((tp[1]=="true")||(tp[1]=="false")) ? eval(tp[1]) : tp[1];
+				}
+			}
+		}
+
+		if(noInit){ return; }
+		if(domain.length > 0){
+			document.domain = domain;
+		}
+		if((window.parent != window)&&(window.parent["dojo"])){
+			var pdj = window.parent.dojo;
+			if(pdj["undo"] && pdj["undo"]["browser"]){
+				pdj.undo.browser.iframeLoaded(null, window.location);
+			}
+		}
+	}
+	// -->
+	</script>
+</head>
+<body onload="try{ init(); }catch(e){ alert(e); }">
+	<h4>The Dojo Toolkit -- iframe_history.html</h4>
+
+	<p>This file is used in Dojo's back/fwd button management.</p>
+</body>
+</html>

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/AdapterRegistry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/AdapterRegistry.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/AdapterRegistry.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/AdapterRegistry.js Mon May 22 16:10:12 2006
@@ -0,0 +1,72 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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(){
+    /***
+        A registry to facilitate adaptation.
+
+        Pairs is an array of [name, check, wrap] triples
+        
+        All check/wrap functions in this registry should be of the same arity.
+    ***/
+    this.pairs = [];
+}
+
+dojo.lang.extend(dojo.AdapterRegistry, {
+    register: function (name, check, wrap, /* optional */ override){
+        /***
+			The check function should return true if the given arguments are
+			appropriate for the wrap function.
+
+			If override is given and true, the check function will be given
+			highest priority.  Otherwise, it will be the lowest priority
+			adapter.
+        ***/
+
+        if (override) {
+            this.pairs.unshift([name, check, wrap]);
+        } else {
+            this.pairs.push([name, check, wrap]);
+        }
+    },
+
+    match: function (/* ... */) {
+        /***
+			Find an adapter for the given arguments.
+
+			If no suitable adapter is found, throws NotFound.
+        ***/
+        for(var i = 0; i < this.pairs.length; i++){
+            var pair = this.pairs[i];
+            if(pair[1].apply(this, arguments)){
+                return pair[2].apply(this, arguments);
+            }
+        }
+		throw new Error("No match found");
+        // dojo.raise("No match found");
+    },
+
+    unregister: function (name) {
+        /***
+			Remove a named adapter from the registry
+        ***/
+        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;
+    }
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/Deferred.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/Deferred.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/Deferred.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/Deferred.js Mon May 22 16:10:12 2006
@@ -0,0 +1,309 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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;
+	},
+
+	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);
+		}
+	}
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation.js Mon May 22 16:10:12 2006
@@ -0,0 +1,12 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Animation.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Animation.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Animation.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Animation.js Mon May 22 16:10:12 2006
@@ -0,0 +1,218 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");
+
+/*
+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.Line*/ curve, /*int*/ duration, /*Decimal?*/ accel, /*int?*/ repeatCount, /*int?*/ rate) {
+	// public properties
+	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(gotoStart) {
+		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() {
+		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() {
+		if( !this._active || this._paused ) {
+			this.play();
+		} else {
+			this.pause();
+		}
+	},
+
+	gotoPercent: function(pct, andPlay) {
+		clearTimeout(this._timer);
+		this._active = true;
+		this._paused = true;
+		this._percent = pct;
+		if( andPlay ) { this.play(); }
+	},
+
+	stop: function(gotoEnd) {
+		clearTimeout(this._timer);
+		var step = this._percent / 100;
+		if( gotoEnd ) {
+			step = 1;
+		}
+		// where is fps defined here?
+		var e = new dojo.animation.AnimationEvent(this, "stop", this.curve.getValue(step),
+			this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent, Math.round(fps));
+		if(typeof this.handler == "function") { this.handler(e); }
+		if(typeof this.onStop == "function") { this.onStop(e); }
+		this._active = false;
+		this._paused = false;
+	},
+
+	status: function() {
+		if( this._active ) {
+			return this._paused ? "paused" : "playing";
+		} else {
+			return "stopped";
+		}
+	},
+
+	// "private" methods
+	_cycle: function() {
+		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();
+					}
+				}
+			}
+		}
+	}
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationEvent.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationEvent.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationEvent.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationEvent.js Mon May 22 16:10:12 2006
@@ -0,0 +1,40 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");
+
+dojo.animation.AnimationEvent = function(anim, type, coords, sTime, cTime, eTime, dur, pct, fps) {
+	this.type = type; // "animate", "begin", "end", "play", "pause", "stop"
+	this.animation = anim;
+
+	this.coords = coords;
+	this.x = coords[0];
+	this.y = coords[1];
+	this.z = coords[2];
+
+	this.startTime = sTime;
+	this.currentTime = cTime;
+	this.endTime = eTime;
+
+	this.duration = dur;
+	this.percent = pct;
+	this.fps = fps;
+};
+dojo.lang.extend(dojo.animation.AnimationEvent, {
+	coordsAsInts: function() {
+		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;
+	}
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationSequence.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationSequence.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationSequence.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/AnimationSequence.js Mon May 22 16:10:12 2006
@@ -0,0 +1,136 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.animation.AnimationSequence = function(repeatCount){
+	this._anims = [];
+	this.repeatCount = repeatCount || 0;
+}
+
+dojo.lang.extend(dojo.animation.AnimationSequence, {
+	repeateCount: 0,
+
+	_anims: [],
+	_currAnim: -1,
+
+	onBegin: null,
+	onEnd: null,
+	onNext: null,
+	handler: null,
+
+	add: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			this._anims.push(arguments[i]);
+			arguments[i]._animSequence = this;
+		}
+	},
+
+	remove: function(anim) {
+		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() {
+		for(var i = 0; i < this._anims.length; i++) {
+			this._anims[i]._animSequence = null;
+		}
+		this._anims = [];
+		this._currAnim = -1;
+	},
+
+	clear: function() {
+		this.removeAll();
+	},
+
+	play: function(gotoStart) {
+		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() {
+		if( this._anims[this._currAnim] ) {
+			this._anims[this._currAnim].pause();
+		}
+	},
+
+	playPause: function() {
+		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() {
+		if( this._anims[this._currAnim] ) {
+			this._anims[this._currAnim].stop();
+		}
+	},
+
+	status: function() {
+		if( this._anims[this._currAnim] ) {
+			return this._anims[this._currAnim].status();
+		} else {
+			return "stopped";
+		}
+	},
+
+	_setCurrent: function(anim) {
+		for(var i = 0; i < this._anims.length; i++) {
+			if( this._anims[i] == anim ) {
+				this._currAnim = i;
+				break;
+			}
+		}
+	},
+
+	_playNext: function() {
+		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;
+			}
+		}
+	}
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Timer.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Timer.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Timer.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/Timer.js Mon May 22 16:10:12 2006
@@ -0,0 +1,39 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.func");
+
+dojo.animation.Timer = function(intvl){
+	var timer = null;
+	this.isRunning = false;
+	this.interval = intvl;
+
+	this.onTick = function(){};
+	this.onStart = null;
+	this.onStop = null;
+
+	this.setInterval = function(ms){
+		if (this.isRunning) window.clearInterval(timer);
+		this.interval = ms;
+		if (this.isRunning) timer = window.setInterval(dojo.lang.hitch(this, "onTick"), this.interval);
+	};
+
+	this.start = function(){
+		if (typeof this.onStart == "function") this.onStart();
+		this.isRunning = true;
+		timer = window.setInterval(this.onTick, this.interval);
+	};
+	this.stop = function(){
+		if (typeof this.onStop == "function") this.onStop();
+		this.isRunning = false;
+		window.clearInterval(timer);
+	};
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/__package__.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/__package__.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/__package__.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/animation/__package__.js Mon May 22 16:10:12 2006
@@ -0,0 +1,18 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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.*");

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/behavior.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/behavior.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/behavior.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/behavior.js Mon May 22 16:10:12 2006
@@ -0,0 +1,248 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap1.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap1.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap1.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap1.js Mon May 22 16:10:12 2006
@@ -0,0 +1,284 @@
+/**
+* @file bootstrap1.js
+*
+* bootstrap file that runs before hostenv_*.js file.
+*
+* @author Copyright 2004 Mark D. Anderson (mda@discerning.com)
+* @author Licensed under the Academic Free License 2.1 http://www.opensource.org/licenses/afl-2.1.php
+*
+* $Id: bootstrap1.js 4030 2006-05-16 02:16:57Z bill $
+*/
+
+/**
+ * The global djConfig can be set prior to loading the library, to override
+ * certain settings.  It does not exist under dojo.* so that it can be set
+ * before the dojo variable exists. Setting any of these variables *after* the
+ * library has loaded does nothing at all. The variables that can be set are
+ * as follows:
+ */
+
+/**
+ * dj_global is an alias for the top-level global object in the host
+ * environment (the "window" object in a browser).
+ */
+var dj_global = this; //typeof window == 'undefined' ? this : window;
+
+/**
+ *  True if name is defined, either on obj or globally if obj is false
+ *  Note that 'defined' and 'exists' are not the same concept. 
+ */
+function dj_undef(name, obj){
+	if(!obj){ obj = dj_global; }
+	// exception if obj is not an Object
+	return (typeof obj[name] == "undefined");
+}
+
+/**
+ * djConfig is the global configuration object 
+ */
+if(dj_undef("djConfig")){ 
+	var djConfig = {}; 
+}
+
+/**
+ * dojo is the root variable of (almost all) our public symbols.
+ */
+if(dj_undef("dojo")){ 
+	var dojo = {}; 
+}
+
+dojo.version = {
+	major: 0, minor: 3, patch: 0, flag: "+",
+	revision: Number("$Rev: 4030 $".match(/[0-9]+/)[0]),
+	toString: function(){
+		with(dojo.version){
+			return major + "." + minor + "." + patch + flag + " (" + revision + ")";
+		}
+	}
+}
+
+/**
+ * get 'obj[name]' if it is defined, otherwise create as Object if 'create' is true, otherwise return null
+ * caveat: 'defined' and 'exists' are not the same concept
+ */
+dojo.evalProp = function(name, obj, create){
+	return (obj && !dj_undef(name, obj) ? obj[name] : (create ? (obj[name]={}) : undefined));
+}
+
+/**
+ * Parse a reference specified as a string descriptor into an object reference and a property name.
+ */
+dojo.parseObjPath = function(objpath, context, create){
+	var obj = (context ? context : dj_global);
+	var names = objpath.split('.');
+	var prop = names.pop();
+	for (var i=0,l=names.length;i<l && obj;i++){
+		obj = dojo.evalProp(names[i], obj, create);
+	}
+	return {obj: obj, prop: prop};
+}
+
+/*
+ * evaluate a string like "A.B" without using eval.
+ */
+dojo.evalObjPath = function(objpath, create){
+	if(typeof objpath != "string"){ 
+		return dj_global; 
+	}
+	// fast path for no periods
+	if(objpath.indexOf('.') == -1){
+		return dojo.evalProp(objpath, dj_global, create);
+	}
+	with (dojo.parseObjPath(objpath, dj_global, create)){
+		return dojo.evalProp(prop, obj, create);
+	}	
+}
+
+// ****************************************************************
+// global public utils
+// ****************************************************************
+
+/*
+ * utility to print an Error. 
+ * TODO: overriding Error.prototype.toString won't accomplish this?
+ * ... since natively generated Error objects do not always reflect such things?
+ */
+dojo.errorToString = function(excep){
+	return ((!dj_undef("message", excep)) ? excep.message : (dj_undef("description", excep) ? excep : excep.description ));
+}
+
+/**
+* Throws an Error object given the string err. For now, will also do a println
+* to the user first.
+*/
+dojo.raise = function(message, excep){
+	if(excep){
+		message = message + ": "+dojo.errorToString(excep);
+	}
+	
+	var he = dojo.hostenv;
+	if((!dj_undef("hostenv", dojo))&&(!dj_undef("println", dojo.hostenv))){ 
+		dojo.hostenv.println("FATAL: " + message);
+	}
+	throw Error(message);
+}
+
+//Stub functions so things don't break.
+dojo.debug = function(){}
+dojo.debugShallow = function(obj){}
+dojo.profile = { start: function(){}, end: function(){}, stop: function(){}, dump: function(){} };
+
+/**
+ * We put eval() in this separate function to keep down the size of the trapped
+ * evaluation context.
+ *
+ * Note that:
+ * - 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.
+*/
+function dj_eval(s){ return dj_global.eval ? dj_global.eval(s) : eval(s); }
+
+
+/**
+ * Convenience for throwing an exception because some function is not
+ * implemented.
+ */
+dojo.unimplemented = function(funcname, extra){
+	// FIXME: need to move this away from dj_*
+	var mess = "'" + funcname + "' not implemented";
+	if((!dj_undef(extra))&&(extra)){ mess += " " + extra; }
+	dojo.raise(mess);
+}
+
+/**
+ * Convenience for informing of deprecated behaviour.
+ */
+dojo.deprecated = function(behaviour, extra, removal){
+	var mess = "DEPRECATED: " + behaviour;
+	if(extra){ mess += " " + extra; }
+	if(removal){ mess += " -- will be removed in version: " + removal; }
+	dojo.debug(mess);
+}
+
+/**
+ * Does inheritance
+ */
+dojo.inherits = function(subclass, superclass){
+	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;
+	// DEPRICATED: super is a reserved word, use 'superclass'
+	subclass['super'] = superclass.prototype;
+}
+
+// an object that authors use determine what host we are running under
+dojo.render = (function(){
+
+	function vscaffold(prefs, names){
+		var tmp = {
+			capable: false,
+			support: {
+				builtin: false,
+				plugin: false
+			},
+			prefixes: prefs
+		};
+		for(var x in names){
+			tmp[x] = 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(){
+
+	// default configuration options
+	var config = {
+		isDebug: false,
+		allowQueryConfig: false,
+		baseScriptUri: "",
+		baseRelativePath: "",
+		libraryScriptUri: "",
+		iePreventClobber: false,
+		ieClobberMinimal: true,
+		preventBackButtonFix: true,
+		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)',
+
+		/**
+		 * Return the name of the hostenv.
+		 */
+		getName: function(){ return this.name_; },
+
+		/**
+		* Return the version of the hostenv.
+		*/
+		getVersion: function(){ return this.version_; },
+
+		/**
+		 * Read the plain/text contents at the specified uri.  If getText() is
+		 * not implemented, then it is necessary to override loadUri() with an
+		 * implementation that doesn't rely on it.
+		 */
+		getText: function(uri){
+			dojo.unimplemented('getText', "uri=" + uri);
+		}
+	};
+})();
+
+/**
+ * Return the base script uri that other scripts are found relative to.
+ * It is either the empty string, or a non-empty string ending in '/'.
+ */
+dojo.hostenv.getBaseScriptUri = function(){
+	if(djConfig.baseScriptUri.length){ 
+		return djConfig.baseScriptUri;
+	}
+	var uri = new String(djConfig.libraryScriptUri||djConfig.baseRelativePath);
+	if (!uri) { dojo.raise("Nothing returned by getLibraryScriptUri(): " + uri); }
+
+	var lastslash = uri.lastIndexOf('/');
+	djConfig.baseScriptUri = djConfig.baseRelativePath;
+	return djConfig.baseScriptUri;
+}

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap2.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap2.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap2.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/bootstrap2.js Mon May 22 16:10:12 2006
@@ -0,0 +1,174 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free 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");
+	}
+
+	//Support compatibility packages. Right now this only allows setting one
+	//compatibility package. Might need to revisit later down the line to support
+	//more than one.
+	if((this["djConfig"])&&(djConfig["compat"])){
+		tmps.push("compat/" + djConfig["compat"] + ".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);
+			}
+		}
+	}
+})();
+
+// Localization routines
+
+/**
+ * The locale to look for string bundles if none are defined for your locale.  Translations for all strings
+ * should be provided in this locale.
+ */
+//TODO: this really belongs in translation metadata, not in code
+dojo.fallback_locale = 'en';
+
+/**
+ * Returns canonical form of locale, as used by Dojo.  All variants are case-insensitive and are separated by '-'
+ * as specified in RFC 3066
+ */
+dojo.normalizeLocale = function(locale) {
+	return locale ? locale.toLowerCase() : dojo.locale;
+};
+
+/**
+ * requireLocalization() is for loading translated bundles provided within a package in the namespace.
+ * Contents are typically strings, but may be any name/value pair, represented in JSON format.
+ * A bundle is structured in a program as follows:
+ *
+ * <package>/
+ *  nls/
+ *   de/
+ *    mybundle.js
+ *   de-at/
+ *    mybundle.js
+ *   en/
+ *    mybundle.js
+ *   en-us/
+ *    mybundle.js
+ *   en-gb/
+ *    mybundle.js
+ *   es/
+ *    mybundle.js
+ *  ...etc
+ *
+ * where package is part of the namespace as used by dojo.require().  Each directory is named for a
+ * locale as specified by RFC 3066, (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
+ *
+ * For a given locale, string bundles will be loaded for that locale and all general locales above it, as well
+ * as a system-specified fallback.  For example, "de_at" will also load "de" and "en".  Lookups will traverse
+ * the locales in this order.  A build step can preload the bundles to avoid data redundancy and extra network hits.
+ *
+ * @param modulename package in which the bundle is found
+ * @param bundlename bundle name, typically the filename without the '.js' suffix
+ * @param locale the locale to load (optional)  By default, the browser's user locale as defined
+ *	in dojo.locale
+ */
+dojo.requireLocalization = function(modulename, bundlename, locale /*optional*/){
+
+	dojo.debug("EXPERIMENTAL: dojo.requireLocalization"); //dojo.experimental
+
+	var syms = dojo.hostenv.getModuleSymbols(modulename);
+	var modpath = syms.concat("nls").join("/");
+
+	locale = dojo.normalizeLocale(locale);
+
+	var elements = locale.split('-');
+	var searchlist = [];
+	for(var i = elements.length; i > 0; i--){
+		searchlist.push(elements.slice(0, i).join('-'));
+	}
+	if(searchlist[searchlist.length-1] != dojo.fallback_locale){
+		searchlist.push(dojo.fallback_locale);
+	}
+
+	var bundlepackage = [modulename, "_nls", bundlename].join(".");
+	var bundle = dojo.hostenv.startPackage(bundlepackage);
+	dojo.hostenv.loaded_modules_[bundlepackage] = bundle;
+	
+	var inherit = false;
+	for(var i = searchlist.length - 1; i >= 0; i--){
+		var loc = searchlist[i];
+		var pkg = [bundlepackage, loc].join(".");
+		var loaded = false;
+		if(!dojo.hostenv.findModule(pkg)){
+			// Mark loaded whether it's found or not, so that further load attempts will not be made
+			dojo.hostenv.loaded_modules_[pkg] = null;
+
+			var filespec = [modpath, loc, bundlename].join("/") + '.js';
+			loaded = dojo.hostenv.loadPath(filespec, null, function(hash) {
+ 				bundle[loc] = hash;
+ 				if(inherit){
+					// Use mixins approach to copy string references from inherit bundle, but skip overrides.
+					for(var x in inherit){
+						if(!bundle[loc][x]){
+							bundle[loc][x] = inherit[x];
+						}
+					}
+ 				}
+/*
+				// Use prototype to point to other bundle, then copy in result from loadPath
+				bundle[loc] = new function(){};
+				if(inherit){ bundle[loc].prototype = inherit; }
+				for(var i in hash){ bundle[loc][i] = hash[i]; }
+*/
+			});
+		}else{
+			loaded = true;
+		}
+		if(loaded && bundle[loc]){
+			inherit = bundle[loc];
+		}
+	}
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/browser_debug.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/browser_debug.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/browser_debug.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/browser_debug.js Mon May 22 16:10:12 2006
@@ -0,0 +1,162 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License 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");
+
+function removeComments(contents){
+	contents = new String((!contents) ? "" : contents);
+	// clobber all comments
+	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|hosetnv.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){
+	if(dojo.hostenv.loadedUris[uri]){
+		return true; // fixes endless recursion opera trac 471
+	}
+	try{
+		var text = this.getText(uri, null, true);
+		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.writeIncludes = function(){
+	for(var x=removals.length-1; x>=0; x--){
+		dojo.clobberLastObject(removals[x]);
+	}
+	var depList = [];
+	var seen = {};
+	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=4; 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>");
+
+	// 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;
+}

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/ArrayList.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/ArrayList.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/ArrayList.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/ArrayList.js Mon May 22 16:10:12 2006
@@ -0,0 +1,146 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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||","));
+	};
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/BinaryTree.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/BinaryTree.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/BinaryTree.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/BinaryTree.js Mon May 22 16:10:12 2006
@@ -0,0 +1,203 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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 : 0,
+	Inorder : 1,
+	Postorder : 2
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Collections.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Collections.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Collections.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Collections.js Mon May 22 16:10:12 2006
@@ -0,0 +1,125 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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={Collections:true};
+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 namespace.  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];
+	};
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Dictionary.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Dictionary.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Dictionary.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Dictionary.js Mon May 22 16:10:12 2006
@@ -0,0 +1,129 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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);
+		}
+	}
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Graph.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Graph.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Graph.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Graph.js Mon May 22 16:10:12 2006
@@ -0,0 +1,153 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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);
+	};
+}

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Queue.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Queue.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Queue.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Queue.js Mon May 22 16:10:12 2006
@@ -0,0 +1,87 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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);
+	};
+};

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Set.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Set.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Set.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/Set.js Mon May 22 16:10:12 2006
@@ -0,0 +1,84 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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");
+
+//	straight up sets are based on arrays or array-based collections.
+dojo.collections.Set = new function(){
+	this.union = function(setA, 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(setA.toArray());
+		var e = setB.getIterator();
+		while(!e.atEnd()){
+			var item=e.get();
+			if(!result.contains(item)){
+				result.add(item);
+			}
+		}
+		return result;
+	};
+	this.intersection = function(setA, 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 = setB.getIterator();
+		while(!e.atEnd()){
+			var item=e.get();
+			if(setA.contains(item)){
+				result.add(item);
+			}
+		}
+		return result;
+	};
+	//	returns everything in setA that is not in setB.
+	this.difference = function(setA, 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;
+	};
+	this.isSubSet = function(setA, 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 e = setA.getIterator();
+		while(!e.atEnd()){
+			if(!setB.contains(e.get())){
+				return false;
+			}
+		}
+		return true;
+	};
+	this.isSuperSet = function(setA, 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 e = setB.getIterator();
+		while(!e.atEnd()){
+			if(!setA.contains(e.get())){
+				return false;
+			}
+		}
+		return true;
+	};
+}();

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/SkipList.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/SkipList.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/SkipList.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/collections/SkipList.js Mon May 22 16:10:12 2006
@@ -0,0 +1,146 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.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.current = list.head;
+		this.atEnd = false;
+		this.moveNext = function(){
+			if (this.atEnd) return !this.atEnd;
+			this.current = this.current.nodes[0];
+			this.atEnd = (this.current == null);
+			return !this.atEnd;
+		};
+		this.reset = function(){
+			this.current = null;
+		};
+	}
+
+	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; 
+	};
+}