Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/connection.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/connection.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/connection.js	(revision 0)
@@ -0,0 +1,8140 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\connection.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-min.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-min.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-min.js	(revision 0)
@@ -0,0 +1,880 @@
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\connection-min.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/README
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/README	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/README	(revision 0)
@@ -0,0 +1,1279 @@
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\README
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-debug.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-debug.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-debug.js	(revision 0)
@@ -0,0 +1,8440 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\connection-debug.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-debug.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-debug.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-debug.js	(revision 0)
@@ -0,0 +1,8440 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+		YAHOO.log('ActiveX Program Id  ' + id + ' added to _msxml_progid.', 'info', 'Connection');
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+		YAHOO.log('Use default POST header set to  ' + b, 'info', 'Connection');
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+			YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+			YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			YAHOO.log('Unable to create connection object.', 'error', 'Connection');
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+						YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+						YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
+					}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+								YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+								YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
+							}
+						}
+				}
+			}
+			catch(e)
+			{
+				YAHOO.log('Callback error: ' + e.message, 'error', 'Connection');
+			}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+				YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+		YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+					YAHOO.log('Upload callback.', 'info', 'Connection');
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+					YAHOO.log('Upload callback with scope.', 'info', 'Connection');
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+			YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+			YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
+
+			return true;
+		}
+		else{
+			YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
+		//dereference the connection object.
+		o = null;
+	}
+};

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\connection-debug.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-min.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-min.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/connection-min.js	(revision 0)
@@ -0,0 +1,880 @@
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved.  Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
+YAHOO.util.Connect={_msxml_progid:['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'],_http_header:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:'application/x-www-form-urlencoded',_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,setProgId:function(id)
+{this._msxml_progid.unshift(id);},setDefaultPostHeader:function(b)
+{this._use_default_post_header=b;},setPollingInterval:function(i)
+{if(typeof i=='number'&&isFinite(i)){this._polling_interval=i;}},createXhrObject:function(transactionId)
+{var obj,http;try
+{http=new XMLHttpRequest();obj={conn:http,tId:transactionId};}
+catch(e)
+{for(var i=0;i<this._msxml_progid.length;++i){try
+{http=new ActiveXObject(this._msxml_progid[i]);obj={conn:http,tId:transactionId};break;}
+catch(e){}}}
+finally
+{return obj;}},getConnectionObject:function()
+{var o;var tId=this._transaction_id;try
+{o=this.createXhrObject(tId);if(o){this._transaction_id++;}}
+catch(e){}
+finally
+{return o;}},asyncRequest:function(method,uri,callback,postData)
+{var o=this.getConnectionObject();if(!o){return null;}
+else{if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(o.tId,callback,uri);this.releaseObject(o);return;}
+if(method=='GET'){uri+="?"+this._sFormData;}
+else if(method=='POST'){postData=(postData?this._sFormData+"&"+postData:this._sFormData);}
+this._sFormData='';}
+o.conn.open(method,uri,true);if(this._isFormSubmit||(postData&&this._use_default_post_header)){this.initHeader('Content-Type',this._default_post_header);if(this._isFormSubmit){this._isFormSubmit=false;}}
+if(this._has_http_headers){this.setHeader(o);}
+this.handleReadyState(o,callback);o.conn.send(postData?postData:null);return o;}},handleReadyState:function(o,callback)
+{var oConn=this;if(callback&&callback.timeout){this._timeOut[o.tId]=window.setTimeout(function(){oConn.abort(o,callback,true);},callback.timeout);}
+this._poll[o.tId]=window.setInterval(function(){if(o.conn&&o.conn.readyState==4){window.clearInterval(oConn._poll[o.tId]);delete oConn._poll[o.tId];if(callback&&callback.timeout){delete oConn._timeOut[o.tId];}
+oConn.handleTransactionResponse(o,callback);}},this._polling_interval);},handleTransactionResponse:function(o,callback,isAbort)
+{if(!callback){this.releaseObject(o);return;}
+var httpStatus,responseObject;try
+{if(o.conn.status!==undefined&&o.conn.status!=0){httpStatus=o.conn.status;}
+else{httpStatus=13030;}}
+catch(e){httpStatus=13030;}
+if(httpStatus>=200&&httpStatus<300){try
+{responseObject=this.createResponseObject(o,callback.argument);if(callback.success){if(!callback.scope){callback.success(responseObject);}
+else{callback.success.apply(callback.scope,[responseObject]);}}}
+catch(e){}}
+else{try
+{switch(httpStatus){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:responseObject=this.createExceptionObject(o.tId,callback.argument,(isAbort?isAbort:false));if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}
+break;default:responseObject=this.createResponseObject(o,callback.argument);if(callback.failure){if(!callback.scope){callback.failure(responseObject);}
+else{callback.failure.apply(callback.scope,[responseObject]);}}}}
+catch(e){}}
+this.releaseObject(o);responseObject=null;},createResponseObject:function(o,callbackArg)
+{var obj={};var headerObj={};try
+{var headerStr=o.conn.getAllResponseHeaders();var header=headerStr.split('\n');for(var i=0;i<header.length;i++){var delimitPos=header[i].indexOf(':');if(delimitPos!=-1){headerObj[header[i].substring(0,delimitPos)]=header[i].substring(delimitPos+2);}}}
+catch(e){}
+obj.tId=o.tId;obj.status=o.conn.status;obj.statusText=o.conn.statusText;obj.getResponseHeader=headerObj;obj.getAllResponseHeaders=headerStr;obj.responseText=o.conn.responseText;obj.responseXML=o.conn.responseXML;if(typeof callbackArg!==undefined){obj.argument=callbackArg;}
+return obj;},createExceptionObject:function(tId,callbackArg,isAbort)
+{var COMM_CODE=0;var COMM_ERROR='communication failure';var ABORT_CODE=-1;var ABORT_ERROR='transaction aborted';var obj={};obj.tId=tId;if(isAbort){obj.status=ABORT_CODE;obj.statusText=ABORT_ERROR;}
+else{obj.status=COMM_CODE;obj.statusText=COMM_ERROR;}
+if(callbackArg){obj.argument=callbackArg;}
+return obj;},initHeader:function(label,value)
+{if(this._http_header[label]===undefined){this._http_header[label]=value;}
+else{this._http_header[label]=value+","+this._http_header[label];}
+this._has_http_headers=true;},setHeader:function(o)
+{for(var prop in this._http_header){if(this._http_header.hasOwnProperty(prop)){o.conn.setRequestHeader(prop,this._http_header[prop]);}}
+delete this._http_header;this._http_header={};this._has_http_headers=false;},setForm:function(formId,isUpload,secureUri)
+{this._sFormData='';if(typeof formId=='string'){var oForm=(document.getElementById(formId)||document.forms[formId]);}
+else if(typeof formId=='object'){var oForm=formId;}
+else{return;}
+if(isUpload){this.createFrame(secureUri?secureUri:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=oForm;return;}
+var oElement,oName,oValue,oDisabled;var hasSubmit=false;for(var i=0;i<oForm.elements.length;i++){oElement=oForm.elements[i];oDisabled=oForm.elements[i].disabled;oName=oForm.elements[i].name;oValue=oForm.elements[i].value;if(!oDisabled&&oName)
+{switch(oElement.type)
+{case'select-one':case'select-multiple':for(var j=0;j<oElement.options.length;j++){if(oElement.options[j].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text)+'&';}
+else{this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text)+'&';}}}
+break;case'radio':case'checkbox':if(oElement.checked){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';}
+break;case'file':case undefined:case'reset':case'button':break;case'submit':if(hasSubmit==false){this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';hasSubmit=true;}
+break;default:this._sFormData+=encodeURIComponent(oName)+'='+encodeURIComponent(oValue)+'&';break;}}}
+this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);},createFrame:function(secureUri){var frameId='yuiIO'+this._transaction_id;if(window.ActiveXObject){var io=document.createElement('<IFRAME id="'+frameId+'" name="'+frameId+'">');if(typeof secureUri=='boolean'){io.src='javascript:false';}
+else{io.src=secureUri;}}
+else{var io=document.createElement('IFRAME');io.id=frameId;io.name=frameId;}
+io.style.position='absolute';io.style.top='-1000px';io.style.left='-1000px';document.body.appendChild(io);},uploadFile:function(id,callback,uri){var frameId='yuiIO'+id;var io=document.getElementById(frameId);this._formNode.action=uri;this._formNode.enctype='multipart/form-data';this._formNode.method='POST';this._formNode.target=frameId;this._formNode.submit();this._formNode=null;this._isFileUpload=false;this._isFormSubmit=false;var uploadCallback=function()
+{var obj={};obj.tId=id;obj.responseText=io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;obj.responseXML=io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;obj.argument=callback.argument;if(callback.upload){if(!callback.scope){callback.upload(obj);}
+else{callback.upload.apply(callback.scope,[obj]);}}
+if(YAHOO.util.Event){YAHOO.util.Event.removeListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.detachEvent('onload',uploadCallback);}
+else{io.removeEventListener('load',uploadCallback,false);}
+setTimeout(function(){document.body.removeChild(io);},100);};if(YAHOO.util.Event){YAHOO.util.Event.addListener(io,"load",uploadCallback);}
+else if(window.ActiveXObject){io.attachEvent('onload',uploadCallback);}
+else{io.addEventListener('load',uploadCallback,false);}},abort:function(o,callback,isTimeout)
+{if(this.isCallInProgress(o)){o.conn.abort();window.clearInterval(this._poll[o.tId]);delete this._poll[o.tId];if(isTimeout){delete this._timeOut[o.tId];}
+this.handleTransactionResponse(o,callback,true);return true;}
+else{return false;}},isCallInProgress:function(o)
+{if(o.conn){return o.conn.readyState!=4&&o.conn.readyState!=0;}
+else{return false;}},releaseObject:function(o)
+{o.conn=null;o=null;}};

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\connection-min.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/connection.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/connection.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/connection.js	(revision 0)
@@ -0,0 +1,8140 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.3
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+	_http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+	_has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _use_default_post_header:true,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:'application/x-www-form-urlencoded',
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type object
+  */
+    _poll:{},
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type object
+  */
+    _timeOut:{},
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this._msxml_progid.unshift(id);
+	},
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+	setDefaultPostHeader:function(b)
+	{
+		this._use_default_post_header = b;
+	},
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+	setPollingInterval:function(i)
+	{
+		if(typeof i == 'number' && isFinite(i)){
+			this._polling_interval = i;
+		}
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and tId properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and tId properties
+					obj = { conn:http, tId:transactionId };
+					break;
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			if(this._isFormSubmit){
+				if(this._isFileUpload){
+					this.uploadFile(o.tId, callback, uri);
+					this.releaseObject(o);
+					return;
+				}
+
+				//If the specified HTTP method is GET, setForm() will return an
+				//encoded string that is concatenated to the uri to
+				//create a querystring.
+				if(method == 'GET'){
+					uri += "?" +  this._sFormData;
+				}
+				else if(method == 'POST'){
+					//If POST data exists in addition to the HTML form data,
+					//it will be concatenated to the form data.
+					postData = (postData?this._sFormData + "&" + postData:this._sFormData);
+				}
+				this._sFormData = '';
+			}
+
+			o.conn.open(method, uri, true);
+
+			if(this._isFormSubmit || (postData && this._use_default_post_header)){
+				this.initHeader('Content-Type', this._default_post_header);
+				if(this._isFormSubmit){
+					this._isFormSubmit = false;
+				}
+			}
+
+			if(this._has_http_headers){
+				this.setHeader(o);
+			}
+
+			this.handleReadyState(o, callback);
+			o.conn.send(postData?postData:null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+
+		var oConn = this;
+
+		if(callback && callback.timeout){
+			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+		}
+
+		this._poll[o.tId] = window.setInterval(
+			function(){
+				if(o.conn && o.conn.readyState == 4){
+					window.clearInterval(oConn._poll[o.tId]);
+					delete oConn._poll[o.tId];
+
+					if(callback && callback.timeout){
+						delete oConn._timeOut[o.tId];
+					}
+
+					oConn.handleTransactionResponse(o, callback);
+				}
+			}
+		,this._polling_interval);
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+		// If no valid callback is provided, then do not process any callback handling.
+		if(!callback){
+			this.releaseObject(o);
+			return;
+		}
+
+		var httpStatus, responseObject;
+
+		try
+		{
+			if(o.conn.status !== undefined && o.conn.status != 0){
+				httpStatus = o.conn.status;
+			}
+			else{
+				httpStatus = 13030;
+			}
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus >= 200 && httpStatus < 300){
+			try
+			{
+				responseObject = this.createResponseObject(o, callback.argument);
+				if(callback.success){
+					if(!callback.scope){
+						callback.success(responseObject);
+					}
+					else{
+						// If a scope property is defined, the callback will be fired from
+						// the context of the object.
+						callback.success.apply(callback.scope, [responseObject]);
+					}
+				}
+			}
+			catch(e){}
+		}
+		else{
+			try
+			{
+				switch(httpStatus){
+					// The following case labels are wininet.dll error codes that may be encountered.
+					case 12002: // Server timeout
+					case 12029: // 12029 to 12031 correspond to dropped connections.
+					case 12030:
+					case 12031:
+					case 12152: // Connection closed by server.
+					case 13030: // See above comments for variable status.
+						responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+						break;
+					default:
+						responseObject = this.createResponseObject(o, callback.argument);
+						if(callback.failure){
+							if(!callback.scope){
+								callback.failure(responseObject);
+							}
+							else{
+								callback.failure.apply(callback.scope, [responseObject]);
+							}
+						}
+				}
+			}
+			catch(e){}
+		}
+
+		this.releaseObject(o);
+		responseObject = null;
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+		var obj = {};
+		var headerObj = {};
+
+		try
+		{
+			var headerStr = o.conn.getAllResponseHeaders();
+			var header = headerStr.split('\n');
+			for(var i=0; i < header.length; i++){
+				var delimitPos = header[i].indexOf(':');
+				if(delimitPos != -1){
+					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
+				}
+			}
+		}
+		catch(e){}
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.getResponseHeader = headerObj;
+		obj.getAllResponseHeaders = headerStr;
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+
+		if(typeof callbackArg !== undefined){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+		var ABORT_CODE = -1;
+		var ABORT_ERROR = 'transaction aborted';
+
+		var obj = {};
+
+		obj.tId = tId;
+		if(isAbort){
+			obj.status = ABORT_CODE;
+			obj.statusText = ABORT_ERROR;
+		}
+		else{
+			obj.status = COMM_CODE;
+			obj.statusText = COMM_ERROR;
+		}
+
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		if(this._http_header[label] === undefined){
+			this._http_header[label] = value;
+		}
+		else{
+			// Concatenate multiple values, comma-delimited,
+			// for the same header label,
+			this._http_header[label] =  value + "," + this._http_header[label];
+		}
+
+		this._has_http_headers = true;
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		for(var prop in this._http_header){
+			if(this._http_header.hasOwnProperty(prop)){
+				o.conn.setRequestHeader(prop, this._http_header[prop]);
+			}
+		}
+		delete this._http_header;
+
+		this._http_header = {};
+		this._has_http_headers = false;
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	setForm:function(formId, isUpload, secureUri)
+	{
+		this._sFormData = '';
+		if(typeof formId == 'string'){
+			// Determine if the argument is a form id or a form name.
+			// Note form name usage is deprecated by supported
+			// here for legacy reasons.
+			var oForm = (document.getElementById(formId) || document.forms[formId]);
+		}
+		else if(typeof formId == 'object'){
+			// Treat argument as an HTML form object.
+			var oForm = formId;
+		}
+		else{
+			return;
+		}
+
+		// If the isUpload argument is true, setForm will call createFrame to initialize
+		// an iframe as the form target.
+		//
+		// The argument secureURI is also required by IE in SSL environments
+		// where the secureURI string is a fully qualified HTTP path, used to set the source
+		// of the iframe, to a stub resource in the same domain.
+		if(isUpload){
+			this.createFrame(secureUri?secureUri:null);
+			this._isFormSubmit = true;
+			this._isFileUpload = true;
+			this._formNode = oForm;
+
+			return;
+		}
+
+		var oElement, oName, oValue, oDisabled;
+		var hasSubmit = false;
+
+		// Iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			oDisabled = oForm.elements[i].disabled;
+			oName = oForm.elements[i].name;
+			oValue = oForm.elements[i].value;
+
+			// Do not submit fields that are disabled or
+			// do not have a name attribute value.
+			if(!oDisabled && oName)
+			{
+				switch (oElement.type)
+				{
+					case 'select-one':
+					case 'select-multiple':
+						for(var j=0; j<oElement.options.length; j++){
+							if(oElement.options[j].selected){
+								if(window.ActiveXObject){
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+								else{
+									this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+								}
+
+							}
+						}
+						break;
+					case 'radio':
+					case 'checkbox':
+						if(oElement.checked){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						}
+						break;
+					case 'file':
+						// stub case as XMLHttpRequest will only send the file path as a string.
+					case undefined:
+						// stub case for fieldset element which returns undefined.
+					case 'reset':
+						// stub case for input type reset button.
+					case 'button':
+						// stub case for input type button elements.
+						break;
+					case 'submit':
+						if(hasSubmit == false){
+							this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+							hasSubmit = true;
+						}
+						break;
+					default:
+						this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+						break;
+				}
+			}
+		}
+
+		this._isFormSubmit = true;
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+	},
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+	createFrame:function(secureUri){
+
+		// IE does not allow the setting of id and name attributes as object
+		// properties via createElement().  A different iframe creation
+		// pattern is required for IE.
+		var frameId = 'yuiIO' + this._transaction_id;
+		if(window.ActiveXObject){
+			var io = document.createElement('<IFRAME id="' + frameId + '" name="' + frameId + '">');
+
+			// IE will throw a security exception in an SSL environment if the
+			// iframe source isn't set.
+			if(typeof secureUri == 'boolean'){
+				io.src = 'javascript:false';
+			}
+			else{
+				io.src = secureUri;
+			}
+		}
+		else{
+			var io = document.createElement('IFRAME');
+			io.id = frameId;
+			io.name = frameId;
+		}
+
+		io.style.position = 'absolute';
+		io.style.top = '-1000px';
+		io.style.left = '-1000px';
+
+		document.body.appendChild(io);
+	},
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+	uploadFile:function(id, callback, uri){
+
+		var frameId = 'yuiIO' + id;
+		var io = document.getElementById(frameId);
+
+		// Initialize the HTML form properties in case they are
+		// not defined in the HTML form.
+		this._formNode.action = uri;
+		this._formNode.enctype = 'multipart/form-data';
+		this._formNode.method = 'POST';
+		this._formNode.target = frameId;
+		this._formNode.submit();
+
+		// Reset form status properties.
+		this._formNode = null;
+		this._isFileUpload = false;
+		this._isFormSubmit = false;
+
+		// Create the upload callback handler that fires when the iframe
+		// receives the load event.  Subsequently, the event handler is detached
+		// and the iframe removed from the document.
+
+		var uploadCallback = function()
+		{
+			var obj = {};
+
+			obj.tId = id;
+			obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
+			obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+			obj.argument = callback.argument;
+
+			if(callback.upload){
+				if(!callback.scope){
+					callback.upload(obj);
+				}
+				else{
+					callback.upload.apply(callback.scope, [obj]);
+				}
+			}
+
+			if(YAHOO.util.Event){
+				YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+			}
+			else if(window.ActiveXObject){
+				io.detachEvent('onload', uploadCallback);
+			}
+			else{
+				io.removeEventListener('load', uploadCallback, false);
+			}
+			setTimeout(function(){ document.body.removeChild(io); }, 100);
+		};
+
+
+		// Bind the onload handler to the iframe to detect the file upload response.
+		if(YAHOO.util.Event){
+			YAHOO.util.Event.addListener(io, "load", uploadCallback);
+		}
+		else if(window.ActiveXObject){
+			io.attachEvent('onload', uploadCallback);
+		}
+		else{
+			io.addEventListener('load', uploadCallback, false);
+		}
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+	abort:function(o, callback, isTimeout)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			window.clearInterval(this._poll[o.tId]);
+			delete this._poll[o.tId];
+			if(isTimeout){
+				delete this._timeOut[o.tId];
+			}
+
+			this.handleTransactionResponse(o, callback, true);
+
+			return true;
+		}
+		else{
+			return false;
+		}
+	},
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		// if the XHR object assigned to the transaction has not been dereferenced,
+		// then check its readyState status.  Otherwise, return false.
+		if(o.conn){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+		else{
+			//The XHR object has been destroyed.
+			return false;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+		//dereference the XHR instance.
+		o.conn = null;
+		//dereference the connection object.
+		o = null;
+	}
+};

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\connection.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/connection/README
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/connection/README	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/connection/README	(revision 0)
@@ -0,0 +1,1279 @@
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Connection Manager Release Notes
+
+*** version 0.11.3 ***
+
+* YUI Event dependency for file uploading is now optional.
+
+* uploadFile() now sets unique IDs for each file upload transaction to prevent
+iframe collisions with parallel uploads.
+
+* The callback object now has property responseXML to provide support for file
+upload transactions that return an XML document.
+
+* setForm() will verify if a select option value attribute is present and use
+its value, including empty string, before using the text node value.
+
+* Modified polling mechanism in handleReadyState() and
+handleTransactionResponse() to prevent infinite polling if JavaScript errors
+occur in the user-defined callback.
+
+* createFrame() will now accept a boolean argument of true to set the frame
+source to "javascript:false" to prevent IE from throwing security warnings in an
+HTTPS environment.
+
+* setHeader() now enumerates through the _http_header object using
+hasOwnProperty() to prevent collisions with members added to Object via
+prototype.
+
+* If using setForm() and asyncRequest includes a POST data argument, the data
+will be concatenated to the HTML form POST message.
+
+*** version 0.11.2 ***
+
+* No revisions.
+
+*** version 0.11.1 ***
+
+* uploadFile() now verifies the existence of callback.upload before invoking
+callback, with or without object scope.
+
+*** version 0.11.0 ***
+
+* Each transaction can be defined with a timeout threshold, in milliseconds,
+through the callback object.  If the threshold is reached, and the transaction
+hasn't yet completed, the transaction will call abort().
+
+* abort() will now accept a callback object as the second argument.  The
+failure callback will receive a response object to indicate the transaction was
+aborted.
+
+* setForm() will now support file uploads by setting the second argument to
+true (e.g., YAHOO.util.Connect.setForm(formObject, true).  File upload does not
+use the callback success or failure handler.  Instead, it uses a new callback
+object handler: upload.
+
+* HTML form submit will no longer submit form fields without a defined name
+attribute.
+
+* The default POST header of 'Content-Type','application/x-www-form-urlencoded'
+can be overridden by calling setDefaultPostHeader(false).  This
+will remove the default header from non-HTML form, POST submissions.
+
+* setHeader() now enumerates through the _http_header object with
+propertyIsEnumerable to prevent collisions with members added to Object via
+prototype.
+
+*** version 0.10.0 ***
+
+* handleTransactionResponse() now treats the full HTTP 2xx range as a success
+case, instead of just HTTP 200.
+
+* To accommodate multiple field values in Mozilla/Firefox, multiple initHeader
+calls with the same label will now result in the values concatenated to a
+comma- delimited string value.
+Example:
+Setting Content-Type:'application/x-www-form-urlencoded' and Content-
+Type:'text/xml' will result in Content-Type:'application/x-www-form-urlencoded,
+text/xml'.
+
+* Default polling interval lowered to 50ms.
+
+* YAHOO.util.Connect.setPollingInterval() will allow you to set a polling
+interval -- in milliseconds -- to override the default value.
+
+* YAHOO.util.Connect.getResponseHeader[headerLabel] now supported as a response
+object property to provide symmetry with the native XHR object's property.
+Example:
+YAHOO.util.Connect.getResponseHeader['Content-Length'] will return the value
+for the Content-Length header, if the header is available.
+
+* YAHOO.util.Connect.allResponseHeaders property renamed to
+getAllResponseHeaders to provide symmetry with the native XHR object's
+property.
+
+* YAHOO.util.Connect.setForm() now supports HTTP GET as well as HTTP POST.
+
+* YAHOO.util.Connect.setForm() now accepts an HTML form object as well as its
+name attribute value.
+
+* YAHOO.util.Connect.setForm() will not submit HTML form fields that are
+disabled or do not have a name attribute value.
+
+* [FIXED] Response exceptions result in infinite callback loop in
+Mozilla/Firefox.
+
+* [FIXED] YAHOO.util.Connect.abort() now properly clears polling interval.
+
+* [FIXED] isCallInProgress() now verifies whether XHR instance still exists,
+and returns false if the connection object is no longer available.
+
+*** version 0.9.0 ***
+
+* Initial release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\connection\README
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/event-debug.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/event-debug.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/event-debug.js	(revision 0)
@@ -0,0 +1,13539 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\event-debug.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/event.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/event.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/event.js	(revision 0)
@@ -0,0 +1,13269 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\event.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/event-min.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/event-min.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/event-min.js	(revision 0)
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\event-min.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/README
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/README	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/README	(revision 0)
@@ -0,0 +1,739 @@
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\README
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/event-debug.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/event-debug.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/event-debug.js	(revision 0)
@@ -0,0 +1,13539 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+        YAHOO.log( "Creating " + this, "info", "Event" );
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+            YAHOO.log( "Firing "       + this  + ", " +
+                       "args: "        + args  + ", " +
+                       "subscribers: " + len,
+                       "info", "Event"                  );
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                    YAHOO.log( this.type + "->" + (i+1) + ": " +  s, "info", "Event" );
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    // this.logger.debug("unable to attach event " + sType);
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // this.logger.debug("Adding handler: " + el + ", " + sType);
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    // this.logger.debug("adding DOM event: " + el.id +
+                    // ", " + sType);
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // this.logger.debug("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    // this.logger.debug("Error, function is not valid " + fn);
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    // this.logger.debug("cached listener not found");
+                    return false;
+                }
+
+                // this.logger.debug("Removing handler: " + el + ", " + sType);
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // this.logger.debug("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+                // this.logger.debug(o.constructor.toString())
+                // this.logger.debug(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // this.logger.debug("tryPreloadAttach");
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            // this.logger.debug("attaching: " + d[this.EL]);
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\event-debug.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/event-min.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/event-min.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/event-min.js	(revision 0)
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}
+/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txt Version: 0.11.4*/ YAHOO.util.CustomEvent=function(_1,_2,_3){this.type=_1;this.scope=_2||window;this.silent=_3;this.subscribers=[];if(!this.silent){}};YAHOO.util.CustomEvent.prototype={subscribe:function(fn,_5,_6){this.subscribers.push(new YAHOO.util.Subscriber(fn,_5,_6));},unsubscribe:function(fn,_7){var _8=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,_7)){this._delete(i);_8=true;}}return _8;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return;}var _12=[];for(var i=0;i<arguments.length;++i){_12.push(arguments[i]);}if(!this.silent){}for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}var _13=(s.override)?s.obj:this.scope;s.fn.call(_13,this.type,_12,s.obj);}}},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}},_delete:function(_14){var s=this.subscribers[_14];if(s){delete s.fn;delete s.obj;}this.subscribers.splice(_14,1);},toString:function(){return "CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,_16){this.fn=fn;this.obj=obj||null;this.override=(_16);};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){return (this.fn==fn&&this.obj==obj);};YAHOO.util.Subscriber.prototype.toString=function(){return "Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var _17=false;var _18=[];var _19=[];var _20=[];var _21=[];var _22=[];var _23=0;var _24=[];var _25=[];var _26=0;return {POLL_RETRYS:200,POLL_INTERVAL:50,EL:0,TYPE:1,FN:2,WFN:3,SCOPE:3,ADJ_SCOPE:4,isSafari:(/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),isIE:(!this.isSafari&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),addDelayedListener:function(el,_28,fn,_29,_30){_19[_19.length]=[el,_28,fn,_29,_30];if(_17){_23=this.POLL_RETRYS;this.startTimeout(0);}},startTimeout:function(_31){var i=(_31||_31===0)?_31:this.POLL_INTERVAL;var _32=this;var _33=function(){_32._tryPreloadAttach();};this.timeout=setTimeout(_33,i);},onAvailable:function(_34,_35,_36,_37){_24.push({id:_34,fn:_35,obj:_36,override:_37});_23=this.POLL_RETRYS;this.startTimeout(0);},addListener:function(el,_38,fn,_39,_40){if(!fn||!fn.call){return false;}if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=(this.on(el[i],_38,fn,_39,_40)&&ok);}return ok;}else{if(typeof el=="string"){var oEl=this.getEl(el);if(_17&&oEl){el=oEl;}else{this.addDelayedListener(el,_38,fn,_39,_40);return true;}}}if(!el){return false;}if("unload"==_38&&_39!==this){_20[_20.length]=[el,_38,fn,_39,_40];return true;}var _43=(_40)?_39:el;var _44=function(e){return fn.call(_43,YAHOO.util.Event.getEvent(e),_39);};var li=[el,_38,fn,_44,_43];var _47=_18.length;_18[_47]=li;if(this.useLegacyEvent(el,_38)){var _48=this.getLegacyIndex(el,_38);if(_48==-1||el!=_21[_48][0]){_48=_21.length;_25[el.id+_38]=_48;_21[_48]=[el,_38,el["on"+_38]];_22[_48]=[];el["on"+_38]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),_48);};}_22[_48].push(li);}else{if(el.addEventListener){el.addEventListener(_38,_44,false);}else{if(el.attachEvent){el.attachEvent("on"+_38,_44);}}}return true;},fireLegacyEvent:function(e,_49){var ok=true;var le=_22[_49];for(var i=0,len=le.length;i<len;++i){var li=le[i];if(li&&li[this.WFN]){var _51=li[this.ADJ_SCOPE];var ret=li[this.WFN].call(_51,e);ok=(ok&&ret);}}return ok;},getLegacyIndex:function(el,_53){var key=this.generateId(el)+_53;if(typeof _25[key]=="undefined"){return -1;}else{return _25[key];}},useLegacyEvent:function(el,_55){if(!el.addEventListener&&!el.attachEvent){return true;}else{if(this.isSafari){if("click"==_55||"dblclick"==_55){return true;}}}return false;},removeListener:function(el,_56,fn,_57){if(!fn||!fn.call){return false;}var i,len;if(typeof el=="string"){el=this.getEl(el);}else{if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],_56,fn)&&ok);}return ok;}}if("unload"==_56){for(i=0,len=_20.length;i<len;i++){var li=_20[i];if(li&&li[0]==el&&li[1]==_56&&li[2]==fn){_20.splice(i,1);return true;}}return false;}var _58=null;if("undefined"==typeof _57){_57=this._getCacheIndex(el,_56,fn);}if(_57>=0){_58=_18[_57];}if(!el||!_58){return false;}if(this.useLegacyEvent(el,_56)){var _59=this.getLegacyIndex(el,_56);var _60=_22[_59];if(_60){for(i=0,len=_60.length;i<len;++i){li=_60[i];if(li&&li[this.EL]==el&&li[this.TYPE]==_56&&li[this.FN]==fn){_60.splice(i,1);}}}}else{if(el.removeEventListener){el.removeEventListener(_56,_58[this.WFN],false);}else{if(el.detachEvent){el.detachEvent("on"+_56,_58[this.WFN]);}}}delete _18[_57][this.WFN];delete _18[_57][this.FN];_18.splice(_57,1);return true;},getTarget:function(ev,_62){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(_64){if(_64&&_64.nodeName&&"#TEXT"==_64.nodeName.toUpperCase()){return _64.parentNode;}else{return _64;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}return y;},getXY:function(ev){return [this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else{if(ev.type=="mouseover"){t=ev.fromElement;}}}return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(e){return t;}}return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}c=c.caller;}}return ev;},getCharCode:function(ev){return ev.charCode||((ev.type=="keypress")?ev.keyCode:0);},_getCacheIndex:function(el,_68,fn){for(var i=0,len=_18.length;i<len;++i){var li=_18[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==_68){return i;}}return -1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+_26;++_26;el.id=id;}return id;},_isValidCollection:function(o){return (o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){_17=true;var EU=YAHOO.util.Event;EU._simpleRemove(window,"load",EU._load);},_tryPreloadAttach:function(){if(this.locked){return false;}this.locked=true;var _72=!_17;if(!_72){_72=(_23>0);}var _73=[];for(var i=0,len=_19.length;i<len;++i){var d=_19[i];if(d){var el=this.getEl(d[this.EL]);if(el){this.on(el,d[this.TYPE],d[this.FN],d[this.SCOPE],d[this.ADJ_SCOPE]);delete _19[i];}else{_73.push(d);}}}_19=_73;var _75=[];for(i=0,len=_24.length;i<len;++i){var _76=_24[i];if(_76){el=this.getEl(_76.id);if(el){var _77=(_76.override)?_76.obj:el;_76.fn.call(_77,_76.obj);delete _24[i];}else{_75.push(_76);}}}_23=(_73.length===0&&_75.length===0)?0:_23-1;if(_72){this.startTimeout();}this.locked=false;return true;},purgeElement:function(el,_78,_79){var _80=this.getListeners(el,_79);if(_80){for(var i=0,len=_80.length;i<len;++i){var l=_80[i];this.removeListener(el,l.type,l.fn);}}if(_78&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],_78,_79);}}},getListeners:function(el,_82){var _83=[];if(_18&&_18.length>0){for(var i=0,len=_18.length;i<len;++i){var l=_18[i];if(l&&l[this.EL]===el&&(!_82||_82===l[this.TYPE])){_83.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.SCOPE],adjust:l[this.ADJ_SCOPE],index:i});}}}return (_83.length)?_83:null;},_unload:function(e){var EU=YAHOO.util.Event;for(var i=0,len=_20.length;i<len;++i){var l=_20[i];if(l){var _84=(l[EU.ADJ_SCOPE])?l[EU.SCOPE]:window;l[EU.FN].call(_84,EU.getEvent(e),l[EU.SCOPE]);delete _20[i];l=null;}}if(_18&&_18.length>0){var j=_18.length;while(j){var _86=j-1;l=_18[_86];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],_86);}l=null;j=j-1;}EU.clearCache();}for(i=0,len=_21.length;i<len;++i){delete _21[i][0];delete _21[i];}EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return [dd.scrollTop,dd.scrollLeft];}else{if(db){return [db.scrollTop,db.scrollLeft];}else{return [0,0];}}},_simpleAdd:function(el,_88,fn,_89){if(el.addEventListener){el.addEventListener(_88,fn,(_89));}else{if(el.attachEvent){el.attachEvent("on"+_88,fn);}}},_simpleRemove:function(el,_90,fn,_91){if(el.removeEventListener){el.removeEventListener(_90,fn,(_91));}else{if(el.detachEvent){el.detachEvent("on"+_90,fn);}}}};}();YAHOO.util.Event.on=YAHOO.util.Event.addListener;if(document&&document.body){YAHOO.util.Event._load();}else{YAHOO.util.Event._simpleAdd(window,"load",YAHOO.util.Event._load);}YAHOO.util.Event._simpleAdd(window,"unload",YAHOO.util.Event._unload);YAHOO.util.Event._tryPreloadAttach();}

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\event-min.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/event.js
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/event.js	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/event.js	(revision 0)
@@ -0,0 +1,13269 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version: 0.11.4
+*/
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String}  type The type of event, which is passed to the callback
+ *                  when the event fires
+ * @param {Object}  oScope The context the event will fire from.  "this" will
+ *                  refer to this object in the callback.  Default value:
+ *                  the window object.  The listener can override this.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ *                  the log system
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent) {
+
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @property type
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from by default.  Defaults to the window
+     * obj
+     * @property scope
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * By default all custom events are logged in the debug build, set silent
+     * to true to disable logging for this event.
+     * @property silent
+     * @type boolean
+     */
+    this.silent = silent;
+
+    /**
+     * The subscribers to this event
+     * @property subscribers
+     * @type Subscriber[]
+     */
+    this.subscribers = [];
+
+    if (!this.silent) {
+    }
+
+    // Only add subscribe events for events that are not generated by CustomEvent
+    //if (oScope && (oScope.constructor != this.constructor)) {
+
+        /*
+         * Custom events provide a custom event that fires whenever there is
+         * a new subscriber to the event.  This provides an opportunity to
+         * handle the case where there is a non-repeating event that has
+         * already fired has a new subscriber.
+         *
+         * type CustomEvent
+         */
+        //this.subscribeEvent =
+                //new YAHOO.util.CustomEvent("subscribe", this, true);
+
+    //}
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @method subscribe
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        //if (this.subscribeEvent) {
+            //this.subscribeEvent.fire(fn, obj, bOverride);
+        //}
+
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @method unsubscribe
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     * @method fire
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        var len=this.subscribers.length;
+        if (!len && this.silent) {
+            return;
+        }
+
+        var args = [];
+
+        for (var i=0; i<arguments.length; ++i) {
+            args.push(arguments[i]);
+        }
+
+        if (!this.silent) {
+        }
+
+        for (i=0; i<len; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                if (!this.silent) {
+                }
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, args, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     * @method unsubscribeAll
+     */
+    unsubscribeAll: function() {
+        for (var i=0, len=this.subscribers.length; i<len; ++i) {
+            this._delete(len - 1 - i);
+        }
+    },
+
+    /**
+     * @method _delete
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        // delete this.subscribers[index];
+        this.subscribers.splice(index, 1);
+    },
+
+    /**
+     * @method toString
+     */
+    toString: function() {
+         return "CustomEvent: " + "'" + this.type  + "', " +
+             "scope: " + this.scope;
+
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+
+    /**
+     * The callback that will be execute when the event fires
+     * @property fn
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @property obj
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @property override
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+    return "Subscriber { obj: " + (this.obj || "")  +
+           ", override: " +  (this.override || "no") + " }";
+};
+
+// The first instance of Event will win if it is loaded more than once.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @namespace YAHOO.util
+ * @class Event
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @property loadComplete
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @property listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @property delayedListeners
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @property unloadListeners
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @property legacyEvents
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @property legacyHandlers
+         * @private
+         */
+        var legacyHandlers = [];
+
+        /**
+         * The number of times to poll after window.onload.  This number is
+         * increased if additional late-bound handlers are requested after
+         * the page load.
+         * @property retryCount
+         * @private
+         */
+        var retryCount = 0;
+
+        /**
+         * onAvailable listeners
+         * @property onAvailStack
+         * @private
+         */
+        var onAvailStack = [];
+
+        /**
+         * Lookup table for legacy events
+         * @property legacyMap
+         * @private
+         */
+        var legacyMap = [];
+
+        /**
+         * Counter for auto id generation
+         * @property counter
+         * @private
+         */
+        var counter = 0;
+
+        return { // PREPROCESS
+
+            /**
+             * The number of times we should look for elements that are not
+             * in the DOM at the time the event is requested after the document
+             * has been loaded.  The default is 200@amp;50 ms, so it will poll
+             * for 10 seconds or until all outstanding handlers are bound
+             * (whichever comes first).
+             * @property POLL_RETRYS
+             * @type int
+             */
+            POLL_RETRYS: 200,
+
+            /**
+             * The poll interval in milliseconds
+             * @property POLL_INTERVAL
+             * @type int
+             */
+            POLL_INTERVAL: 50,
+
+            /**
+             * Element to bind, int constant
+             * @property EL
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @property TYPE
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @property FN
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @property WFN
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @property SCOPE
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @property ADJ_SCOPE
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @property isSafari
+             * @private
+             */
+            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
+
+            /**
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             * @property isIE
+             * @private
+             */
+            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
+                    navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * @method addDelayedListener
+             * @private
+             */
+            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
+                delayedListeners[delayedListeners.length] =
+                    [el, sType, fn, oScope, bOverride];
+
+                // If this happens after the inital page load, we need to
+                // reset the poll counter so that we continue to search for
+                // the element for a fixed period of time.
+                if (loadComplete) {
+                    retryCount = this.POLL_RETRYS;
+                    this.startTimeout(0);
+                    // this._tryPreloadAttach();
+                }
+            },
+
+            /**
+             * @method startTimeout
+             * @private
+             */
+            startTimeout: function(interval) {
+                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
+                var self = this;
+                var callback = function() { self._tryPreloadAttach(); };
+                this.timeout = setTimeout(callback, i);
+            },
+
+            /**
+             * Executes the supplied callback when the item with the supplied
+             * id is found.  This is meant to be used to execute behavior as
+             * soon as possible as the page loads.  If you use this after the
+             * initial page load it will poll for a fixed time for the element.
+             * The number of times it will poll and the frequency are
+             * configurable.  By default it will poll for 10 seconds.
+             *
+             * @method onAvailable
+             *
+             * @param {string}   p_id the id of the element to look for.
+             * @param {function} p_fn what to execute when the element is found.
+             * @param {object}   p_obj an optional object to be passed back as
+             *                   a parameter to p_fn.
+             * @param {boolean}  p_override If set to true, p_fn will execute
+             *                   in the scope of p_obj
+             *
+             */
+            onAvailable: function(p_id, p_fn, p_obj, p_override) {
+                onAvailStack.push( { id:       p_id,
+                                     fn:       p_fn,
+                                     obj:      p_obj,
+                                     override: p_override } );
+
+                retryCount = this.POLL_RETRYS;
+                this.startTimeout(0);
+                // this._tryPreloadAttach();
+            },
+
+            /**
+             * Appends an event handler
+             *
+             * @method addListener
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    var oEl = this.getEl(el);
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete && oEl) {
+                        el = oEl;
+                    } else {
+                        // defer adding the event until onload fires
+                        this.addDelayedListener(el,
+                                                sType,
+                                                fn,
+                                                oScope,
+                                                bOverride);
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+
+                    // Add a new dom0 wrapper if one is not detected for this
+                    // element
+                    if ( legacyIndex == -1 ||
+                                el != legacyEvents[legacyIndex][0] ) {
+
+                        legacyIndex = legacyEvents.length;
+                        legacyMap[el.id + sType] = legacyIndex;
+
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    //legacyHandlers[legacyIndex].push(index);
+                    legacyHandlers[legacyIndex].push(li);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // IE
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @method fireLegacyEvent
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                var ok = true;
+
+                var le = legacyHandlers[legacyIndex];
+                for (var i=0,len=le.length; i<len; ++i) {
+                    var li = le[i];
+                    if ( li && li[this.WFN] ) {
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @method getLegacyIndex
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                var key = this.generateId(el) + sType;
+                if (typeof legacyMap[key] == "undefined") {
+                    return -1;
+                } else {
+                    return legacyMap[key];
+                }
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @method useLegacyEvent
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+                if (!el.addEventListener && !el.attachEvent) {
+                    return true;
+                } else if (this.isSafari) {
+                    if ("click" == sType || "dblclick" == sType) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @method removeListener
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn, index) {
+
+                if (!fn || !fn.call) {
+                    return false;
+                }
+
+                var i, len;
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (i=0,len=el.length; i<len; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                if ("unload" == sType) {
+
+                    for (i=0, len=unloadListeners.length; i<len; i++) {
+                        var li = unloadListeners[i];
+                        if (li &&
+                            li[0] == el &&
+                            li[1] == sType &&
+                            li[2] == fn) {
+                                unloadListeners.splice(i, 1);
+                                return true;
+                        }
+                    }
+
+                    return false;
+                }
+
+                var cacheItem = null;
+
+                //var index = arguments[3];
+
+                if ("undefined" == typeof index) {
+                    index = this._getCacheIndex(el, sType, fn);
+                }
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    var llist = legacyHandlers[legacyIndex];
+                    if (llist) {
+                        for (i=0, len=llist.length; i<len; ++i) {
+                            li = llist[i];
+                            if (li &&
+                                li[this.EL] == el &&
+                                li[this.TYPE] == sType &&
+                                li[this.FN] == fn) {
+                                    llist.splice(i, 1);
+                            }
+                        }
+                    }
+
+                } else if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                listeners.splice(index, 1);
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @method getTarget
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node.  @deprecated, the text node is
+             *                  now resolved automatically
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * In some cases, some browsers will return a text node inside
+             * the actual element that was targeted.  This normalizes the
+             * return value for getTarget and getRelatedTarget.
+             * @method resolveTextNode
+             * @param {HTMLElement} node to resolve
+             * @return  the normized node
+             */
+            resolveTextNode: function(node) {
+                if (node && node.nodeName &&
+                        "#TEXT" == node.nodeName.toUpperCase()) {
+                    return node.parentNode;
+                } else {
+                    return node;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @method getPageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @method getPageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the pageX and pageY properties as an indexed array.
+             * @method getXY
+             * @type int[]
+             */
+            getXY: function(ev) {
+                return [this.getPageX(ev), this.getPageY(ev)];
+            },
+
+            /**
+             * Returns the event's related target
+             * @method getRelatedTarget
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return this.resolveTextNode(t);
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @method getTime
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @method stopEvent
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @method stopPropagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @method preventDefault
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Finds the event in the window object, the caller's arguments, or
+             * in the arguments of another method in the callstack.  This is
+             * executed automatically for events registered through the event
+             * manager, so the implementer should not normally need to execute
+             * this function at all.
+             * @method getEvent
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @method getCharCode
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
+            },
+
+            /**
+             * Locating the saved event handler data by function ref
+             *
+             * @method _getCacheIndex
+             * @private
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0,len=listeners.length; i<len; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Generates an unique ID for the element if it does not already
+             * have one.
+             * @method generateId
+             * @param el the element
+             * @return {string} the id of the element
+             */
+            generateId: function(el) {
+                var id = el.id;
+
+                if (!id) {
+                    id = "yuievtautoid-" + counter;
+                    ++counter;
+                    el.id = id;
+                }
+
+                return id;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @method _isValidCollection
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             * @private
+             */
+            _isValidCollection: function(o) {
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * @property elCache
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @method getEl
+             * @private
+             */
+            getEl: function(id) {
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             * @deprecated
+             * @private
+             */
+            clearCache: function() { },
+
+            /**
+             * hook up any deferred listeners
+             * @method _load
+             * @private
+             */
+            _load: function(e) {
+                loadComplete = true;
+                var EU = YAHOO.util.Event;
+                EU._simpleRemove(window, "load", EU._load);
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting to attach to DOM Nodes as soon as they are
+             * available
+             * @method _tryPreloadAttach
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                if (this.locked) {
+                    return false;
+                }
+
+                this.locked = true;
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+                if (!tryAgain) {
+                    tryAgain = (retryCount > 0);
+                }
+
+                // Delayed listeners
+                var stillDelayed = [];
+
+                for (var i=0,len=delayedListeners.length; i<len; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        } else {
+                            stillDelayed.push(d);
+                        }
+                    }
+                }
+
+                delayedListeners = stillDelayed;
+
+                // onAvailable
+                var notAvail = [];
+                for (i=0,len=onAvailStack.length; i<len ; ++i) {
+                    var item = onAvailStack[i];
+                    if (item) {
+                        el = this.getEl(item.id);
+
+                        if (el) {
+                            var scope = (item.override) ? item.obj : el;
+                            item.fn.call(scope, item.obj);
+                            delete onAvailStack[i];
+                        } else {
+                            notAvail.push(item);
+                        }
+                    }
+                }
+
+                retryCount = (stillDelayed.length === 0 &&
+                                    notAvail.length === 0) ? 0 : retryCount - 1;
+
+                if (tryAgain) {
+                    this.startTimeout();
+                }
+
+                this.locked = false;
+
+                return true;
+
+            },
+
+            /**
+             * Removes all listeners attached to the given element via addListener.
+             * Optionally, the node's children can also be purged.
+             * Optionally, you can specify a specific type of event to remove.
+             * @method purgeElement
+             * @param {HTMLElement} el the element to purge
+             * @param {boolean} recurse recursively purge this element's children
+             * as well.  Use with caution.
+             * @param {string} sType optional type of listener to purge. If
+             * left out, all listeners will be removed
+             */
+            purgeElement: function(el, recurse, sType) {
+                var elListeners = this.getListeners(el, sType);
+                if (elListeners) {
+                    for (var i=0,len=elListeners.length; i<len ; ++i) {
+                        var l = elListeners[i];
+                        // can't use the index on the changing collection
+                        //this.removeListener(el, l.type, l.fn, l.index);
+                        this.removeListener(el, l.type, l.fn);
+                    }
+                }
+
+                if (recurse && el && el.childNodes) {
+                    for (i=0,len=el.childNodes.length; i<len ; ++i) {
+                        this.purgeElement(el.childNodes[i], recurse, sType);
+                    }
+                }
+            },
+
+            /**
+             * Returns all listeners attached to the given element via addListener.
+             * Optionally, you can specify a specific type of event to return.
+             * @method getListeners
+             * @param el {HTMLElement} the element to inspect
+             * @param sType {string} optional type of listener to return. If
+             * left out, all listeners will be returned
+             * @return {Object} the listener. Contains the following fields:
+             *    type:   (string)   the type of event
+             *    fn:     (function) the callback supplied to addListener
+             *    obj:    (object)   the custom object supplied to addListener
+             *    adjust: (boolean)  whether or not to adjust the default scope
+             *    index:  (int)      its position in the Event util listener cache
+             */
+            getListeners: function(el, sType) {
+                var elListeners = [];
+                if (listeners && listeners.length > 0) {
+                    for (var i=0,len=listeners.length; i<len ; ++i) {
+                        var l = listeners[i];
+                        if ( l  && l[this.EL] === el &&
+                                (!sType || sType === l[this.TYPE]) ) {
+                            elListeners.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.SCOPE],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+
+                return (elListeners.length) ? elListeners : null;
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             * @method _unload
+             * @private
+             */
+            _unload: function(e) {
+
+                var EU = YAHOO.util.Event;
+
+                for (var i=0,len=unloadListeners.length; i<len; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[EU.ADJ_SCOPE]) ? l[EU.SCOPE]: window;
+                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.SCOPE] );
+                        delete unloadListeners[i];
+                        l=null;
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    //for (i=0,len=listeners.length; i<len ; ++i) {
+                    var j = listeners.length;
+                    while (j) {
+                        var index = j-1;
+                        l = listeners[index];
+                        if (l) {
+                            EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                    l[EU.FN], index);
+                        }
+
+                        l=null;
+
+                        j = j - 1;
+                    }
+
+                    EU.clearCache();
+                }
+
+                for (i=0,len=legacyEvents.length; i<len; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+
+                EU._simpleRemove(window, "unload", EU._unload);
+
+            },
+
+            /**
+             * Returns scrollLeft
+             * @method _getScrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @method _getScrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @method _getScroll
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement, db = document.body;
+                if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            },
+
+            /**
+             * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleAdd: function (el, sType, fn, capture) {
+                if (el.addEventListener) {
+                    el.addEventListener(sType, fn, (capture));
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, fn);
+                }
+            },
+
+            /**
+             * Basic remove listener
+             *
+             * @param el the elment to bind the handler to
+             * @param {string} sType the type of event handler
+             * @param {function} fn the callback to invoke
+             * @param {boolen} capture or bubble phase
+             * @private
+             */
+            _simpleRemove: function (el, sType, fn, capture) {
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, fn, (capture));
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, fn);
+                }
+            }
+        };
+
+    } ();
+
+    /**
+     * YAHOO.util.Event.on is an alias for addListener
+     * @method on
+     * @see addListener
+     */
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event._simpleAdd(window, "load", YAHOO.util.Event._load);
+    }
+    YAHOO.util.Event._simpleAdd(window, "unload", YAHOO.util.Event._unload);
+    YAHOO.util.Event._tryPreloadAttach();
+}
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\event.js
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-platform-web/standard/src/main/webapp/yui/event/README
===================================================================
--- xwiki-platform-web/standard/src/main/webapp/yui/event/README	(revision 0)
+++ xwiki-platform-web/standard/src/main/webapp/yui/event/README	(revision 0)
@@ -0,0 +1,739 @@
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+YUI Library - Event - Release Notes
+
+0.11.4
+
+   * Fixed a memory leak that occured when the utility was hosted in an iframe.
+
+   * Fixed an issue with Safari click listeners when listeners were removed.
+
+0.11.3
+
+   * The listener cache is now pruned when events are removed.  This fixes
+     a performance issue when adding many listeners, removing them, and
+     adding them again repeatedly.
+
+   * Safari click listeners will work correctly if a bound element is removed
+     from the DOM and a new element with the same ID is added.
+
+   * Removed the code that automatically unsubscribed custom event listeners.
+
+0.11.0
+
+   * Added Event.purgeElement which will remove all listeners added via
+     addListener from the supplied element.  If an optional "type" parameter
+     is supplied, only events of that type will be removed.  Optionally, the
+     purge can be performed recursively on the element's children as well.
+
+   * Added Event.getListeners which will return all listeners attached to
+     a given element.. either all listeners or listeners of a specific type.
+
+   * getTarget now automatically resolves text nodes.  The optional parameter
+     for this feature is now deprecated.
+
+   * getRelatedTarget now resolves text nodes for the browsers that return the
+     text node rather than its host HTML element.
+
+   * CustomEvent now logs the custom event activity if the logger widget is
+   available
+
+0.10.0
+
+   * Added Safari dblclick to the list of legacy events.
+
+   * When multiple identical event handlers are defined, multiple calls
+     to removeListener can now remove all of them.
+
+   * removeListener works properly for unload events
+
+   * Legacy event bookkeeping is more efficient, improving the performance for
+     adding Safari click events.
+
+   * _unload() is more efficient, improving the page transition experience in
+     Safari in particular.
+
+   * addListener, removeListener now return false if the function argument is
+     not valid.
+
+   * Fixed an operator precedence issue in getCharCode.
+
+   * Added Event.getXY, which returns [Event.getPageX(e), Event.getPageY(e)]
+
+   * Added Event.onAvailable, which will execute the callback when the element
+     with the supplied id is found.  Currently searches periodically until the
+     window load event or for up to 10 seconds after the onAvailable method
+     was executed.
+
+   * The lazy listener attachment process now will poll beyond the window load
+     event in order to better handle the case when a listener is defined
+     late in the page but before the element is in the dom.
+
+   * Fixed browser detection for Opera installations reporting as IE.
+
+   * It is now possible to remove and re-add legacy events (Safari click event).
+
+
+
+
+
+

Property changes on: xwiki-platform-web\standard\src\main\webapp\yui\event\README
___________________________________________________________________
Name: svn:eol-style
   + native

Index: xwiki-product-enterprise/wiki/src/main/resources/XWiki/Treeview
===================================================================
--- xwiki-product-enterprise/wiki/src/main/resources/XWiki/Treeview	(revision 9211)
+++ xwiki-product-enterprise/wiki/src/main/resources/XWiki/Treeview	(working copy)
@@ -12,9 +12,9 @@
 <customClass></customClass>
 <contentAuthor>XWiki.Admin</contentAuthor>
 <creationDate>1181560077000</creationDate>
-<date>1181637097000</date>
-<contentUpdateDate>1181637097000</contentUpdateDate>
-<version>1.3</version>
+<date>1207908899000</date>
+<contentUpdateDate>1207908899000</contentUpdateDate>
+<version>11.1</version>
 <title></title>
 <template></template>
 <defaultTemplate></defaultTemplate>
@@ -53,56 +53,99 @@
 <tags/>
 </property>
 </object>
-<content>## Note: This implementation doesn't scale for large wikis. In order to support
-## large wikis we need to dynamically load node data when nodes are expanded
-## instead of loading all nodes at once.
+<content>#if($request.nodeName)
+  #set ($hiddenSpaces = ["XWiki", "Admin", "Panels"])
+  #set ($hiddenPages = ["Main.WebRss", "Main.WebSearch", "Main.LuceneSearch", "Main.BlogRss", "Blog.Macros", "Main.TagsRss", "Main.RegisterNewUserAction", "Main.SpaceIndex", "Blog.Category"])
+  #set ($blackListedPages = ["WebPreferences"])
+  #set($node = $request.get("nodeName"))
+  $response.setContentType("text/xml") 
+  &lt;?xml version="1.0" encoding="UTF-8"?&gt;
+  &lt;results&gt;
+  #set($res = "false") 
+  #foreach ($page in $xwiki.searchDocuments("doc.web = '$node' and (doc.parent = '${node}.WebHome' or doc.parent = '' or doc.parent is null or doc.parent not like '${node}%') order by doc.name"))
+   #if (($page != "${node}.WebHome") &amp;&amp; (!$hiddenPages.contains($page) || ($hiddenPages.contains($page) &amp;&amp; $xwiki.hasAdminRights())))
+    #set($index = $page.indexOf(".") + 1)
+    #set($pageName = $page.substring($index))
+    #if (!$blackListedPages.contains($pageName) || ($blackListedPages.contains($pageName) &amp;&amp; $xwiki.hasAdminRights()))
+       #set($res = "true")
+       &lt;rs label="$pageName.replaceAll('"', '\\\"')" parent="$page"&gt;$xwiki.getURL("${page}")&lt;/rs&gt;
+    #end
+   #end
+  #end
+  #if($res == "false")
+ 	#set($ppp = $node.replaceAll("'", "''"))
+ 	#set($space = $xwiki.search("select distinct doc.web from XWikiDocument doc where doc.name= '$ppp' order by 1"))
+ 	#foreach ($page in $xwiki.searchDocuments("doc.parent = '$space.get(0).$ppp' order by doc.name"))
+   	  #if (!$hiddenPages.contains($page) || ($hiddenPages.contains($page) &amp;&amp; $xwiki.hasAdminRights()))
+      	#set($index = $page.indexOf(".") + 1)
+      	#set($pageName = $page.substring($index))
+      	#if (!$blackListedPages.contains($pageName) || ($blackListedPages.contains($pageName) &amp;&amp; $xwiki.hasAdminRights()))
+        	#set($res = "true")
+        	&lt;rs label="$pageName.replaceAll('"', '\\\"')" parent="$page"&gt;$xwiki.getURL("${page}")&lt;/rs&gt;
+      	#end
+      #end
+    #end
+  #end
+  &lt;/results&gt;
+#else
 &lt;script type='text/javascript' src='${request.contextPath}/yui/yahoo/yahoo-min.js' &gt;&lt;/script&gt;
 &lt;script type='text/javascript' src='${request.contextPath}/yui/treeview/treeview-min.js' &gt;&lt;/script&gt;
 &lt;script type='text/javascript' src='${request.contextPath}/yui/treeview/checknode.js' &gt;&lt;/script&gt;
+&lt;script type='text/javascript' src='${request.contextPath}/yui/event/event-min.js' &gt;&lt;/script&gt;
+&lt;script type='text/javascript' src='${request.contextPath}/yui/connection/connection-min.js' &gt;&lt;/script&gt;
 &lt;div id="treeview"&gt;&lt;/div&gt;
+{pre}
 &lt;script type="text/javascript"&gt;
-  function treeInit()
-  {
-    var tree = new YAHOO.widget.TreeView("treeview");
-    var root = tree.getRoot();
-    var nodeObject;
-    #set ($hiddenSpaces = ["XWiki", "Admin", "Panels"])
-    #set ($hiddenPages = ["Main.WebRss", "Main.WebSearch", "Main.LuceneSearch", "Main.BlogRss", "Blog.Macros", "Main.TagsRss", "Main.RegisterNewUserAction", "Main.SpaceIndex", "Blog.Category"])
-    #set ($blackListedPages = ["WebPreferences"])
-    #macro(addNodeChildren $space $parent $nodeName)
-      #set($ppp = $parent.replaceAll("'", "''"))
-      #foreach ($page in $xwiki.searchDocuments("doc.parent = '$ppp' order by doc.name"))
-        #if (!$hiddenPages.contains($page) || ($hiddenPages.contains($page) &amp;&amp; $xwiki.hasAdminRights()))
-          #set ($index = $page.indexOf(".") + 1)
-          #set($pageName = $page.substring($index))
-          #if (!$blackListedPages.contains($pageName) || ($blackListedPages.contains($pageName) &amp;&amp; $xwiki.hasAdminRights()))
-            nodeObject = { label: "$pageName.replaceAll('"', '\\\"')", href:"$xwiki.getURL("${page}")" };
-            var ${nodeName}1 = new YAHOO.widget.TextNode(nodeObject, $nodeName, false); 
-            #addNodeChildren($space $page "${nodeName}1")
-          #end
-        #end
-      #end
-    #end
-    // Add spaces as top level nodes
-    #foreach ($space in $xwiki.spaces)
-      #if (!$hiddenSpaces.contains($space) || ($hiddenSpaces.contains($space) and $xwiki.hasAdminRights()))
-        nodeObject = { label: "$space", href:"$xwiki.getURL("${space}.WebHome")" };
-        var spaceNode = new YAHOO.widget.MenuNode(nodeObject, root, false); 
-        #foreach ($page in $xwiki.searchDocuments("doc.web = '$space' and (doc.parent = '${space}.WebHome' or doc.parent = '' or doc.parent is null or doc.parent not like '${space}%') order by doc.name"))
-          #if (($page != "${space}.WebHome") &amp;&amp; (!$hiddenPages.contains($page) || ($hiddenPages.contains($page) &amp;&amp; $xwiki.hasAdminRights())))
-            #set ($index = $page.indexOf(".") + 1)
-            #set($pageName = $page.substring($index))
-            #if (!$blackListedPages.contains($pageName) || ($blackListedPages.contains($pageName) &amp;&amp; $xwiki.hasAdminRights()))
-              nodeObject = { label: "$pageName.replaceAll('"', '\\\"')", href:"$xwiki.getURL("${page}")" };
-              var node = new YAHOO.widget.TextNode(nodeObject, spaceNode, false); 
-              #addNodeChildren($space $page "node")
-            #end
-          #end
-        #end
-      #end
-    #end
-    tree.draw();
-  }
-  treeInit(); 
+var tree;
+
+function loadNodeData(node, fnLoadComplete)  {
+  var url = "$doc.getURL()?xpage=plain&amp;nodeName="+node.label;
+  var callback = {
+   success: function(oResponse) {
+     var xml = oResponse.responseXML;
+     var results = xml.getElementsByTagName('results')[0].childNodes;
+     for (var i = 0; i &lt; results.length; i++)
+	if (results[i].hasChildNodes()) {
+	 var nodeObject = {label: results[i].getAttribute('label'), href: results[i].childNodes[0].nodeValue};
+         var tempNode = new YAHOO.widget.TextNode(nodeObject, node, false);
+     }
+     oResponse.argument.fnLoadComplete();
+   },
+   failure: function(oResponse) {
+	oResponse.argument.fnLoadComplete();
+   },
+   argument: {
+		"node": node,
+		"fnLoadComplete": fnLoadComplete
+   },
+   timeout: 7000
+  };
+  YAHOO.util.Connect.asyncRequest('GET', url, callback);
+}
+  
+function buildTree() 
+{
+ var tree = new YAHOO.widget.TreeView("treeview");
+ //turn dynamic loading on for entire tree:
+ tree.setDynamicLoad(loadNodeData, 1);
+ var root = tree.getRoot();
+ #set ($hiddenSpaces = ["XWiki", "Admin", "Panels"])
+ #set ($hiddenPages = ["Main.WebRss", "Main.WebSearch", "Main.LuceneSearch", "Main.BlogRss", "Blog.Macros", "Main.TagsRss", "Main.RegisterNewUserAction", "Main.SpaceIndex", "Blog.Category"])
+ #set ($blackListedPages = ["WebPreferences"])
+ // Add spaces as top level nodes
+ #foreach ($space in $xwiki.spaces)
+   #if (!$hiddenSpaces.contains($space) || ($hiddenSpaces.contains($space) &amp;&amp; $xwiki.hasAdminRights()))
+     nodeObject = { label: "$space", href:"$xwiki.getURL("${space}.WebHome")" };
+     var spaceNode = new YAHOO.widget.TextNode(nodeObject, root, false); 
+   #end
+ #end
+ tree.draw();
+}
+
+     
+//once the DOM has loaded, we can go ahead and set up our tree:
+Event.observe(window, "load", buildTree);
 &lt;/script&gt;
-</content></xwikidoc>
\ No newline at end of file
+{/pre}
+#end
+</content></xwikidoc>
