/*yahoo.js*/
/*
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 0.12.0
*/ 

/**
* The YAHOO object is the single global object used by YUI Library.  It
* contains utility function for setting up namespaces, inheritance, and
* logging.  YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
* created automatically for and used by the library.
* @module yahoo
* @title  YAHOO Global
*/

/**
* The YAHOO global namespace object
* @class YAHOO
* @static
*/
if (typeof YAHOO == "undefined") {
	var YAHOO = {};
}

/**
* Returns the namespace specified and creates it if it doesn't exist
* <pre>
* YAHOO.namespace("property.package");
* YAHOO.namespace("YAHOO.property.package");
* </pre>
* Either of the above would create YAHOO.property, then
* YAHOO.property.package
*
* Be careful when naming packages. Reserved words may work in some browsers
* and not others. For instance, the following will fail in Safari:
* <pre>
* YAHOO.namespace("really.long.nested.namespace");
* </pre>
* This fails because "long" is a future reserved word in ECMAScript
*
* @method namespace
* @static
* @param  {String*} arguments 1-n namespaces to create 
* @return {Object}  A reference to the last namespace object created
*/
YAHOO.namespace = function() {
	var a=arguments, o=null, i, j, d;
	for (i=0; i<a.length; ++i) {
		d=a[i].split(".");
		o=YAHOO;

		// YAHOO is implied, so it is ignored if it is included
		for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; ++j) {
			o[d[j]]=o[d[j]] || {};
			o=o[d[j]];
		}
	}

	return o;
};

/**
* Uses YAHOO.widget.Logger to output a log message, if the widget is available.
*
* @method log
* @static
* @param  {String}  msg  The message to log.
* @param  {String}  cat  The log category for the message.  Default
*						categories are "info", "warn", "error", time".
*						Custom categories can be used as well. (opt)
* @param  {String}  src  The source of the the message (opt)
* @return {Boolean}	  True if the log operation was successful.
*/
YAHOO.log = function(msg, cat, src) {
	var l=YAHOO.widget.Logger;
	if(l && l.log) {
		return l.log(msg, cat, src);
	} else {
		return false;
	}
};

/**
* Utility to set up the prototype, constructor and superclass properties to
* support an inheritance strategy that can chain constructors and methods.
*
* @method extend
* @static
* @param {Function} subc   the object to modify
* @param {Function} superc the object to inherit
* @param {String[]} overrides  additional properties/methods to add to the
*							  subclass prototype.  These will override the
*							  matching items obtained from the superclass 
*							  if present.
*/
YAHOO.extend = function(subc, superc, overrides) {
	var F = function() {};
	F.prototype=superc.prototype;
	subc.prototype=new F();
	subc.prototype.constructor=subc;
	subc.superclass=superc.prototype;
	if (superc.prototype.constructor == Object.prototype.constructor) {
		superc.prototype.constructor=superc;
	}

	if (overrides) {
		for (var i in overrides) {
			subc.prototype[i]=overrides[i];
		}
	}
};

/**
* Applies all prototype properties in the supplier to the receiver if the
* receiver does not have these properties yet.  Optionally, one or more
* methods/properties can be specified (as additional parameters).  This
* option will overwrite the property if receiver has it already.
*
* @method augment
* @static
* @param {Function} r  the object to receive the augmentation
* @param {Function} s  the object that supplies the properties to augment
* @param {String*}  arguments zero or more properties methods to augment the
*							 receiver with.  If none specified, everything
*							 in the supplier will be used unless it would
*							 overwrite an existing property in the receiver
*/
YAHOO.augment = function(r, s) {
	var rp=r.prototype, sp=s.prototype, a=arguments, i, p;
	if (a[2]) {
		for (i=2; i<a.length; ++i) {
			rp[a[i]] = sp[a[i]];
		}
	} else {
		for (p in sp) { 
			if (!rp[p]) {
				rp[p] = sp[p];
			}
		}
	}
};

YAHOO.namespace("util", "widget", "example");

/*dom.js*/
/*
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 0.12.0
*/

/**
* The dom module provides helper methods for manipulating Dom elements.
* @module dom
*
*/

(function() {
	var Y = YAHOO.util,	 // internal shorthand
		getStyle,		   // for load time browser branching
		setStyle,		   // ditto
		id_counter = 0,	 // for use with generateId
		propertyCache = {}; // for faster hyphen converts

	// brower detection
	var ua = navigator.userAgent.toLowerCase(),
		isOpera = (ua.indexOf('opera') > -1),
		isSafari = (ua.indexOf('safari') > -1),
		isGecko = (!isOpera && !isSafari && ua.indexOf('gecko') > -1),
		isIE = (!isOpera && ua.indexOf('msie') > -1);

	// regex cache
	var patterns = {
		HYPHEN: /(-[a-z])/i
	};


	var toCamel = function(property) {
		if ( !patterns.HYPHEN.test(property) ) {
			return property; // no hyphens
		}

		if (propertyCache[property]) { // already converted
			return propertyCache[property];
		}

		while( patterns.HYPHEN.exec(property) ) {
			property = property.replace(RegExp.$1,
					RegExp.$1.substr(1).toUpperCase());
		}

		propertyCache[property] = property;
		return property;
		//return property.replace(/-([a-z])/gi, function(m0, m1) {return m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari bug
	};

	// branching at load instead of runtime
	if (document.defaultView && document.defaultView.getComputedStyle) { // W3C DOM method
		getStyle = function(el, property) {
			var value = null;

			var computed = document.defaultView.getComputedStyle(el, '');
			if (computed) { // test computed before touching for safari
				value = computed[toCamel(property)];
			}

			return el.style[property] || value;
		};
	} else if (document.documentElement.currentStyle && isIE) { // IE method
		getStyle = function(el, property) {
			switch( toCamel(property) ) {
				case 'opacity' :// IE opacity uses filter
					var val = 100;
					try { // will error if no DXImageTransform
						val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;

					} catch(e) {
						try { // make sure its in the document
							val = el.filters('alpha').opacity;
						} catch(e) {
						}
					}
					return val / 100;
					break;
				default:
					// test currentStyle before touching
					var value = el.currentStyle ? el.currentStyle[property] : null;
					return ( el.style[property] || value );
			}
		};
	} else { // default to inline only
		getStyle = function(el, property) { return el.style[property]; };
	}

	if (isIE) {
		setStyle = function(el, property, val) {
			switch (property) {
				case 'opacity':
					if ( typeof el.style.filter == 'string' ) { // in case not appended
						el.style.filter = 'alpha(opacity=' + val * 100 + ')';

						if (!el.currentStyle || !el.currentStyle.hasLayout) {
							el.style.zoom = 1; // when no layout or cant tell
						}
					}
					break;
				default:
				el.style[property] = val;
			}
		};
	} else {
		setStyle = function(el, property, val) {
			el.style[property] = val;
		};
	}

	/**
	 * Provides helper methods for DOM elements.
	 * @namespace YAHOO.util
	 * @class Dom
	 */
	YAHOO.util.Dom = {
		/**
		 * Returns an HTMLElement reference.
		 * @method get
		 * @param {String | HTMLElement |Array} el Accepts a string to use as an ID for getting a DOM reference, an actual DOM reference, or an Array of IDs and/or HTMLElements.
		 * @return {HTMLElement | Array} A DOM reference to an HTML element or an array of HTMLElements.
		 */
		get: function(el) {
			if (!el) { return null; } // nothing to work with

			if (typeof el != 'string' && !(el instanceof Array) ) { // assuming HTMLElement or HTMLCollection, so pass back as is
				return el;
			}

			if (typeof el == 'string') { // ID
				return document.getElementById(el);
			}
			else { // array of ID's and/or elements
				var collection = [];
				for (var i = 0, len = el.length; i < len; ++i) {
					collection[collection.length] = Y.Dom.get(el[i]);
				}

				return collection;
			}

			return null; // safety, should never happen
		},

		/**
		 * Normalizes currentStyle and ComputedStyle.
		 * @method getStyle
		 * @param {String | HTMLElement |Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
		 * @param {String} property The style property whose value is returned.
		 * @return {String | Array} The current value of the style property for the element(s).
		 */
		getStyle: function(el, property) {
			property = toCamel(property);

			var f = function(element) {
				return getStyle(element, property);
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
		 * @method setStyle
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
		 * @param {String} property The style property to be set.
		 * @param {String} val The value to apply to the given property.
		 */
		setStyle: function(el, property, val) {
			property = toCamel(property);

			var f = function(element) {
				setStyle(element, property, val);

			};

			Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
		 * @method getXY
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
		 * @return {Array} The XY position of the element(s)
		 */
		getXY: function(el) {
			var f = function(el) {

			// has to be part of document to have pageXY
				if (el.parentNode === null || el.offsetParent === null ||
						this.getStyle(el, 'display') == 'none') {
					return false;
				}

				var parentNode = null;
				var pos = [];
				var box;

				if (el.getBoundingClientRect) { // IE
					box = el.getBoundingClientRect();
					var doc = document;
					if ( !this.inDocument(el) && parent.document != document) {// might be in a frame, need to get its scroll
						doc = parent.document;

						if ( !this.isAncestor(doc.documentElement, el) ) {
							return false;
						}

					}

					var scrollTop = Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
					var scrollLeft = Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);

					return [box.left + scrollLeft, box.top + scrollTop];
				}
				else { // safari, opera, & gecko
					pos = [el.offsetLeft, el.offsetTop];
					parentNode = el.offsetParent;
					if (parentNode != el) {
						while (parentNode) {
							pos[0] += parentNode.offsetLeft;
							pos[1] += parentNode.offsetTop;
							parentNode = parentNode.offsetParent;
						}
					}
					if (isSafari && this.getStyle(el, 'position') == 'absolute' ) { // safari doubles in some cases
						pos[0] -= document.body.offsetLeft;
						pos[1] -= document.body.offsetTop;
					}
				}

				if (el.parentNode) { parentNode = el.parentNode; }
				else { parentNode = null; }

				while (parentNode && parentNode.tagName.toUpperCase() != 'BODY' && parentNode.tagName.toUpperCase() != 'HTML')
				{ // account for any scrolled ancestors
					if (Y.Dom.getStyle(parentNode, 'display') != 'inline') { // work around opera inline scrollLeft/Top bug
						pos[0] -= parentNode.scrollLeft;
						pos[1] -= parentNode.scrollTop;
					}

					if (parentNode.parentNode) {
						parentNode = parentNode.parentNode;
					} else { parentNode = null; }
				}


				return pos;
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
		 * @method getX
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
		 * @return {String | Array} The X position of the element(s)
		 */
		getX: function(el) {
			var f = function(el) {
				return Y.Dom.getXY(el)[0];
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
		 * @method getY
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
		 * @return {String | Array} The Y position of the element(s)
		 */
		getY: function(el) {
			var f = function(el) {
				return Y.Dom.getXY(el)[1];
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Set the position of an html element in page coordinates, regardless of how the element is positioned.
		 * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
		 * @method setXY
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
		 * @param {Array} pos Contains X & Y values for new position (coordinates are page-based)
		 * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
		 */
		setXY: function(el, pos, noRetry) {
			var f = function(el) {
				var style_pos = this.getStyle(el, 'position');
				if (style_pos == 'static') { // default to relative
					this.setStyle(el, 'position', 'relative');
					style_pos = 'relative';
				}

				var pageXY = this.getXY(el);
				if (pageXY === false) { // has to be part of doc to have pageXY
					return false;
				}

				var delta = [ // assuming pixels; if not we will have to retry
					parseInt( this.getStyle(el, 'left'), 10 ),
					parseInt( this.getStyle(el, 'top'), 10 )
				];

				if ( isNaN(delta[0]) ) {// in case of 'auto'
					delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
				}
				if ( isNaN(delta[1]) ) { // in case of 'auto'
					delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
				}

				if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
				if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }

				var newXY = this.getXY(el);

				// if retry is true, try one more time if we miss
				if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
					this.setXY(el, pos, true);
				}

			};

			Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
		 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
		 * @method setX
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
		 * @param {Int} x The value to use as the X coordinate for the element(s).
		 */
		setX: function(el, x) {
			Y.Dom.setXY(el, [x, null]);
		},

		/**
		 * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
		 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
		 * @method setY
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
		 * @param {Int} x To use as the Y coordinate for the element(s).
		 */
		setY: function(el, y) {
			Y.Dom.setXY(el, [null, y]);
		},

		/**
		 * Returns the region position of the given element.
		 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
		 * @method getRegion
		 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
		 * @return {Region | Array} A Region or array of Region instances containing "top, left, bottom, right" member data.
		 */
		getRegion: function(el) {
			var f = function(el) {
				var region = new Y.Region.getRegion(el);
				return region;
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Returns the width of the client (viewport).
		 * @method getClientWidth
		 * @deprecated Now using getViewportWidth.  This interface left intact for back compat.
		 * @return {Int} The width of the viewable area of the page.
		 */
		getClientWidth: function() {
			return Y.Dom.getViewportWidth();
		},

		/**
		 * Returns the height of the client (viewport).
		 * @method getClientHeight
		 * @deprecated Now using getViewportHeight.  This interface left intact for back compat.
		 * @return {Int} The height of the viewable area of the page.
		 */
		getClientHeight: function() {
			return Y.Dom.getViewportHeight();
		},

		/**
		 * Returns a array of HTMLElements with the given class.
		 * For optimized performance, include a tag and/or root node when possible.
		 * @method getElementsByClassName
		 * @param {String} className The class name to match against
		 * @param {String} tag (optional) The tag name of the elements being collected
		 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point
		 * @return {Array} An array of elements that have the given class name
		 */
		getElementsByClassName: function(className, tag, root) {
			var method = function(el) { return Y.Dom.hasClass(el, className); };
			return Y.Dom.getElementsBy(method, tag, root);
		},

		/**
		 * Determines whether an HTMLElement has the given className.
		 * @method hasClass
		 * @param {String | HTMLElement | Array} el The element or collection to test
		 * @param {String} className the class name to search for
		 * @return {Boolean | Array} A boolean value or array of boolean values
		 */
		hasClass: function(el, className) {
			var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');

			var f = function(el) {
				return re.test(el['className']);
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Adds a class name to a given element or collection of elements.
		 * @method addClass
		 * @param {String | HTMLElement | Array} el The element or collection to add the class to
		 * @param {String} className the class name to add to the class attribute
		 */
		addClass: function(el, className) {
			var f = function(el) {
				if (this.hasClass(el, className)) { return; } // already present


				el['className'] = [el['className'], className].join(' ');
			};

			Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Removes a class name from a given element or collection of elements.
		 * @method removeClass
		 * @param {String | HTMLElement | Array} el The element or collection to remove the class from
		 * @param {String} className the class name to remove from the class attribute
		 */
		removeClass: function(el, className) {
			var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');

			var f = function(el) {
				if (!this.hasClass(el, className)) { return; } // not present


				var c = el['className'];
				el['className'] = c.replace(re, ' ');
				if ( this.hasClass(el, className) ) { // in case of multiple adjacent
					this.removeClass(el, className);
				}

			};

			Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Replace a class with another class for a given element or collection of elements.
		 * If no oldClassName is present, the newClassName is simply added.
		 * @method replaceClass
		 * @param {String | HTMLElement | Array} el The element or collection to remove the class from
		 * @param {String} oldClassName the class name to be replaced
		 * @param {String} newClassName the class name that will be replacing the old class name
		 */
		replaceClass: function(el, oldClassName, newClassName) {
			if (oldClassName === newClassName) { // avoid infinite loop
				return false;
			}

			var re = new RegExp('(?:^|\\s+)' + oldClassName + '(?:\\s+|$)', 'g');

			var f = function(el) {

				if ( !this.hasClass(el, oldClassName) ) {
					this.addClass(el, newClassName); // just add it if nothing to replace
					return; // note return
				}

				el['className'] = el['className'].replace(re, ' ' + newClassName + ' ');

				if ( this.hasClass(el, oldClassName) ) { // in case of multiple adjacent
					this.replaceClass(el, oldClassName, newClassName);
				}
			};

			Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Generates a unique ID
		 * @method generateId
		 * @param {String | HTMLElement | Array} el (optional) An optional element array of elements to add an ID to (no ID is added if one is already present).
		 * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen").
		 * @return {String | Array} The generated ID, or array of generated IDs (or original ID if already present on an element)
		 */
		generateId: function(el, prefix) {
			prefix = prefix || 'yui-gen';
			el = el || {};

			var f = function(el) {
				if (el) {
					el = Y.Dom.get(el);
				} else {
					el = {}; // just generating ID in this case
				}

				if (!el.id) {
					el.id = prefix + id_counter++;
				} // dont override existing


				return el.id;
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy.
		 * @method isAncestor
		 * @param {String | HTMLElement} haystack The possible ancestor
		 * @param {String | HTMLElement} needle The possible descendent
		 * @return {Boolean} Whether or not the haystack is an ancestor of needle
		 */
		isAncestor: function(haystack, needle) {
			haystack = Y.Dom.get(haystack);
			if (!haystack || !needle) { return false; }

			var f = function(needle) {
				if (haystack.contains && !isSafari) { // safari "contains" is broken
					return haystack.contains(needle);
				}
				else if ( haystack.compareDocumentPosition ) {
					return !!(haystack.compareDocumentPosition(needle) & 16);
				}
				else { // loop up and test each parent
					var parent = needle.parentNode;

					while (parent) {
						if (parent == haystack) {
							return true;
						}
						else if (!parent.tagName || parent.tagName.toUpperCase() == 'HTML') {
							return false;
						}

						parent = parent.parentNode;
					}
					return false;
				}
			};

			return Y.Dom.batch(needle, f, Y.Dom, true);
		},

		/**
		 * Determines whether an HTMLElement is present in the current document.
		 * @method inDocument
		 * @param {String | HTMLElement} el The element to search for
		 * @return {Boolean} Whether or not the element is present in the current document
		 */
		inDocument: function(el) {
			var f = function(el) {
				return this.isAncestor(document.documentElement, el);
			};

			return Y.Dom.batch(el, f, Y.Dom, true);
		},

		/**
		 * Returns a array of HTMLElements that pass the test applied by supplied boolean method.
		 * For optimized performance, include a tag and/or root node when possible.
		 * @method getElementsBy
		 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument.

		 * @param {String} tag (optional) The tag name of the elements being collected
		 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point
		 */
		getElementsBy: function(method, tag, root) {
			tag = tag || '*';
			root = Y.Dom.get(root) || document;

			var nodes = [];
			var elements = root.getElementsByTagName(tag);

			if ( !elements.length && (tag == '*' && root.all) ) {
				elements = root.all; // IE < 6
			}

			for (var i = 0, len = elements.length; i < len; ++i) {
				if ( method(elements[i]) ) { nodes[nodes.length] = elements[i]; }
			}


			return nodes;
		},

		/**
		 * Returns an array of elements that have had the supplied method applied.
		 * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) ).
		 * @method batch
		 * @param {String | HTMLElement | Array} el (optional) An element or array of elements to apply the method to
		 * @param {Function} method The method to apply to the element(s)
		 * @param {Any} o (optional) An optional arg that is passed to the supplied method
		 * @param {Boolean} override (optional) Whether or not to override the scope of "method" with "o"
		 * @return {HTMLElement | Array} The element(s) with the method applied
		 */
		batch: function(el, method, o, override) {
			var id = el;
			el = Y.Dom.get(el);

			var scope = (override) ? o : window;

			if (!el || el.tagName || !el.length) { // is null or not a collection (tagName for SELECT and others that can be both an element and a collection)
				if (!el) {
					return false;
				}
				return method.call(scope, el, o);
			}

			var collection = [];

			for (var i = 0, len = el.length; i < len; ++i) {
				if (!el[i]) {
					id = el[i];
				}
				collection[collection.length] = method.call(scope, el[i], o);
			}

			return collection;
		},

		/**
		 * Returns the height of the document.
		 * @method getDocumentHeight
		 * @return {Int} The height of the actual document (which includes the body and its margin).
		 */
		getDocumentHeight: function() {
			var scrollHeight = (document.compatMode != 'CSS1Compat') ? document.body.scrollHeight : document.documentElement.scrollHeight;

			var h = Math.max(scrollHeight, Y.Dom.getViewportHeight());
			return h;
		},

		/**
		 * Returns the width of the document.
		 * @method getDocumentWidth
		 * @return {Int} The width of the actual document (which includes the body and its margin).
		 */
		getDocumentWidth: function() {
			var scrollWidth = (document.compatMode != 'CSS1Compat') ? document.body.scrollWidth : document.documentElement.scrollWidth;
			var w = Math.max(scrollWidth, Y.Dom.getViewportWidth());
			return w;
		},

		/**
		 * Returns the current height of the viewport.
		 * @method getViewportHeight
		 * @return {Int} The height of the viewable area of the page (excludes scrollbars).
		 */
		getViewportHeight: function() {
			var height = self.innerHeight; // Safari, Opera
			var mode = document.compatMode;

			if ( (mode || isIE) && !isOpera ) { // IE, Gecko
				height = (mode == 'CSS1Compat') ?
						document.documentElement.clientHeight : // Standards
						document.body.clientHeight; // Quirks
			}

			return height;
		},

		/**
		 * Returns the current width of the viewport.
		 * @method getViewportWidth
		 * @return {Int} The width of the viewable area of the page (excludes scrollbars).
		 */

		getViewportWidth: function() {
			var width = self.innerWidth;  // Safari
			var mode = document.compatMode;

			if (mode || isIE) { // IE, Gecko, Opera
				width = (mode == 'CSS1Compat') ?
						document.documentElement.clientWidth : // Standards
						document.body.clientWidth; // Quirks
			}
			return width;
		}
	};
})();
/**
* A region is a representation of an object on a grid.  It is defined
* by the top, right, bottom, left extents, so is rectangular by default.  If
* other shapes are required, this class could be extended to support it.
* @namespace YAHOO.util
* @class Region
* @param {Int} t the top extent
* @param {Int} r the right extent
* @param {Int} b the bottom extent
* @param {Int} l the left extent
* @constructor
*/
YAHOO.util.Region = function(t, r, b, l) {

	/**
	 * The region's top extent
	 * @property top
	 * @type Int
	 */
	this.top = t;

	/**
	 * The region's top extent as index, for symmetry with set/getXY
	 * @property 1
	 * @type Int
	 */
	this[1] = t;

	/**
	 * The region's right extent
	 * @property right
	 * @type int
	 */
	this.right = r;

	/**
	 * The region's bottom extent
	 * @property bottom
	 * @type Int
	 */
	this.bottom = b;

	/**
	 * The region's left extent
	 * @property left
	 * @type Int
	 */
	this.left = l;

	/**
	 * The region's left extent as index, for symmetry with set/getXY
	 * @property 0
	 * @type Int
	 */
	this[0] = l;
};

/**
* Returns true if this region contains the region passed in
* @method contains
* @param  {Region}  region The region to evaluate
* @return {Boolean}		True if the region is contained with this region,
*						  else false
*/
YAHOO.util.Region.prototype.contains = function(region) {
	return ( region.left   >= this.left   &&
			 region.right  <= this.right  &&
			 region.top	>= this.top	&&
			 region.bottom <= this.bottom	);

};

/**
* Returns the area of the region
* @method getArea
* @return {Int} the region's area
*/
YAHOO.util.Region.prototype.getArea = function() {
	return ( (this.bottom - this.top) * (this.right - this.left) );
};

/**
* Returns the region where the passed in region overlaps with this one
* @method intersect
* @param  {Region} region The region that intersects
* @return {Region}		The overlap region, or null if there is no overlap
*/
YAHOO.util.Region.prototype.intersect = function(region) {
	var t = Math.max( this.top,	region.top	);
	var r = Math.min( this.right,  region.right  );
	var b = Math.min( this.bottom, region.bottom );
	var l = Math.max( this.left,   region.left   );

	if (b >= t && r >= l) {
		return new YAHOO.util.Region(t, r, b, l);
	} else {
		return null;
	}
};

/**
* Returns the region representing the smallest region that can contain both
* the passed in region and this region.
* @method union
* @param  {Region} region The region that to create the union with
* @return {Region}		The union region
*/
YAHOO.util.Region.prototype.union = function(region) {
	var t = Math.min( this.top,	region.top	);
	var r = Math.max( this.right,  region.right  );
	var b = Math.max( this.bottom, region.bottom );
	var l = Math.min( this.left,   region.left   );

	return new YAHOO.util.Region(t, r, b, l);
};

/**
* toString
* @method toString
* @return string the region properties
*/
YAHOO.util.Region.prototype.toString = function() {
	return ( "Region {"	+
			 "top: "	   + this.top	+
			 ", right: "   + this.right  +
			 ", bottom: "  + this.bottom +
			 ", left: "	+ this.left   +
			 "}" );
};

/**
* Returns a region that is occupied by the DOM element
* @method getRegion
* @param  {HTMLElement} el The element
* @return {Region}		 The region that the element occupies
* @static
*/
YAHOO.util.Region.getRegion = function(el) {
	var p = YAHOO.util.Dom.getXY(el);

	var t = p[1];
	var r = p[0] + el.offsetWidth;
	var b = p[1] + el.offsetHeight;
	var l = p[0];

	return new YAHOO.util.Region(t, r, b, l);
};

/////////////////////////////////////////////////////////////////////////////

/**
* A point is a region that is special in that it represents a single point on
* the grid.
* @namespace YAHOO.util
* @class Point
* @param {Int} x The X position of the point
* @param {Int} y The Y position of the point
* @constructor
* @extends YAHOO.util.Region
*/
YAHOO.util.Point = function(x, y) {
  if (x instanceof Array) { // accept output from Dom.getXY
	  y = x[1];
	  x = x[0];
  }

	/**
	 * The X position of the point, which is also the right, left and index zero (for Dom.getXY symmetry)
	 * @property x
	 * @type Int
	 */

	this.x = this.right = this.left = this[0] = x;

	/**
	 * The Y position of the point, which is also the top, bottom and index one (for Dom.getXY symmetry)
	 * @property y
	 * @type Int
	 */
	this.y = this.top = this.bottom = this[1] = y;
};

YAHOO.util.Point.prototype = new YAHOO.util.Region();

/*event.js*/
/*																																					  
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 0.12.0
*/ 

/**
* 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, signature) {

	/**
	 * 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;

	/**
	 * Custom events support two styles of arguments provided to the event
	 * subscribers.  
	 * <ul>
	 * <li>YAHOO.util.CustomEvent.LIST: 
	 *   <ul>
	 *   <li>param1: event name</li>
	 *   <li>param2: array of arguments sent to fire</li>
	 *   <li>param3: <optional> a custom object supplied by the subscriber</li>
	 *   </ul>
	 * </li>
	 * <li>YAHOO.util.CustomEvent.FLAT
	 *   <ul>
	 *   <li>param1: the first argument passed to fire.  If you need to
	 *		   pass multiple parameters, use and array or object literal</li>
	 *   <li>param2: <optional> a custom object supplied by the subscriber</li>
	 *   </ul>
	 * </li>
	 * </ul>
	 *   @property signature
	 *   @type int
	 */
	this.signature = signature || YAHOO.util.CustomEvent.LIST;

	/**
	 * The subscribers to this event
	 * @property subscribers
	 * @type Subscriber[]
	 */
	this.subscribers = [];

	if (!this.silent) {
	}

	var onsubscribeType = "_YUICEOnSubscribe";

	// Only add subscribe events for events that are not generated by 
	// CustomEvent
	if (type !== onsubscribeType) {

		/**
		 * 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.  
		 *
		 * @event subscribeEvent
		 * @type YAHOO.util.CustomEvent
		 * @param {Function} fn The function to execute
		 * @param {Object}   obj An object to be passed along when the event 
		 *					   fires
		 * @param {boolean|Object}  override If true, the obj passed in becomes 
		 *								   the execution scope of the listener.
		 *								   if an object, that object becomes the
		 *								   the execution scope.
		 */
		this.subscribeEvent = 
				new YAHOO.util.CustomEvent(onsubscribeType, this, true);

	} 
};

/**
* Subscriber listener sigature constant.  The LIST type returns three
* parameters: the event type, the array of args passed to fire, and
* the optional custom object
* @property YAHOO.util.CustomEvent.LIST
* @static
* @type int
*/
YAHOO.util.CustomEvent.LIST = 0;

/**
* Subscriber listener sigature constant.  The FLAT type returns two
* parameters: the first argument passed to fire and the optional 
* custom object
* @property YAHOO.util.CustomEvent.FLAT
* @static
* @type int
*/
YAHOO.util.CustomEvent.FLAT = 1;

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|Object}  override If true, the obj passed in becomes 
	 *								   the execution scope of the listener.
	 *								   if an object, that object becomes the
	 *								   the execution scope.
	 */
	subscribe: function(fn, obj, override) {
		if (this.subscribeEvent) {
			this.subscribeEvent.fire(fn, obj, override);
		}

		this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );
	},

	/**
	 * Unsubscribes the caller from this event
	 * @method unsubscribe
	 * @param {Function} fn  The function to execute
	 * @param {Object}   obj  The custom object passed to subscribe (optional)
	 * @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:
	 *   <ul>
	 *   <li>The type of event</li>
	 *   <li>All of the arguments fire() was executed with as an array</li>
	 *   <li>The custom object (if any) that was passed into the subscribe() 
	 *	   method</li>
	 *   </ul>
	 * @method fire 
	 * @param {Object*} arguments an arbitrary set of parameters to pass to 
	 *							the handler.
	 */
	fire: function() {
		var len=this.subscribers.length;
		if (!len && this.silent) {
			return true;
		}

		var args=[], ret=true, i;

		for (i=0; i<arguments.length; ++i) {
			args.push(arguments[i]);
		}

		var argslength = args.length;

		if (!this.silent) {
		}

		for (i=0; i<len; ++i) {
			var s = this.subscribers[i];
			if (s) {
				if (!this.silent) {
				}

				var scope = s.getScope(this.scope);

				if (this.signature == YAHOO.util.CustomEvent.FLAT) {
					var param = null;
					if (args.length > 0) {
						param = args[0];
					}
					ret = s.fn.call(scope, param, s.obj);
				} else {
					ret = s.fn.call(scope, this.type, args, s.obj);
				}
				if (false === ret) {
					if (!this.silent) {
					}

					//break;
					return false;
				}
			}
		}

		return true;
	},

	/**
	 * 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}  override If true, the obj passed in becomes the execution
*							scope of the listener
* @class Subscriber
* @constructor
*/
YAHOO.util.Subscriber = function(fn, obj, override) {

	/**
	 * 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.  If override is an object, that 
	 * object becomes the scope.
	 * @property override
	 * @type boolean|object
	 */
	this.override = override;

};

/**
* Returns the execution scope for this listener.  If override was set to true
* the custom obj will be the scope.  If override is an object, that is the
* scope, otherwise the default scope will be used.
* @method getScope
* @param {Object} defaultScope the scope to use if this listener does not
*							  override it.
*/
YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
	if (this.override) {
		if (this.override === true) {
			return this.obj;
		} else {
			return this.override;
		}
	}
	return defaultScope;
};

/**
* 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) {
	if (obj) {
		return (this.fn == fn && this.obj == obj);
	} else {
		return (this.fn == fn);
	}
};

/**
* @method toString
*/
YAHOO.util.Subscriber.prototype.toString = function() {
	return "Subscriber { obj: " + (this.obj || "")  + 
		   ", override: " +  (this.override || "no") + " }";
};

/**
* The Event Utility provides utilities for managing DOM Events and tools
* for building event systems
*
* @module event
* @title Event Utility
* @namespace YAHOO.util
* @requires yahoo
*/

// 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.
*
* @class Event
* @static
*/
	YAHOO.util.Event = function() {

		/**
		 * True after the onload event has fired
		 * @property loadComplete
		 * @type boolean
		 * @static
		 * @private
		 */
		var loadComplete =  false;

		/**
		 * Cache of wrapped listeners
		 * @property listeners
		 * @type array
		 * @static
		 * @private
		 */
		var listeners = [];

		/**
		 * User-defined unload function that will be fired before all events
		 * are detached
		 * @property unloadListeners
		 * @type array
		 * @static
		 * @private
		 */
		var unloadListeners = [];

		/**
		 * Cache of DOM0 event handlers to work around issues with DOM2 events
		 * in Safari
		 * @property legacyEvents
		 * @static
		 * @private
		 */
		var legacyEvents = [];

		/**
		 * Listener stack for DOM0 events
		 * @property legacyHandlers
		 * @static
		 * @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
		 * @static
		 * @private
		 */
		var retryCount = 0;

		/**
		 * onAvailable listeners
		 * @property onAvailStack
		 * @static
		 * @private
		 */
		var onAvailStack = [];

		/**
		 * Lookup table for legacy events
		 * @property legacyMap
		 * @static
		 * @private
		 */
		var legacyMap = [];

		/**
		 * Counter for auto id generation
		 * @property counter
		 * @static
		 * @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
			 * @static
			 * @final
			 */
			POLL_RETRYS: 200,

			/**
			 * The poll interval in milliseconds
			 * @property POLL_INTERVAL
			 * @type int
			 * @static
			 * @final
			 */
			POLL_INTERVAL: 20,

			/**
			 * Element to bind, int constant
			 * @property EL
			 * @type int
			 * @static
			 * @final
			 */
			EL: 0,

			/**
			 * Type of event, int constant
			 * @property TYPE
			 * @type int
			 * @static
			 * @final
			 */
			TYPE: 1,

			/**
			 * Function to execute, int constant
			 * @property FN
			 * @type int
			 * @static
			 * @final
			 */
			FN: 2,

			/**
			 * Function wrapped for scope correction and cleanup, int constant
			 * @property WFN
			 * @type int
			 * @static
			 * @final
			 */
			WFN: 3,

			/**
			 * Object passed in by the user that will be returned as a 
			 * parameter to the callback, int constant
			 * @property OBJ
			 * @type int
			 * @static
			 * @final
			 */
			OBJ: 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
			 * @static
			 * @final
			 */
			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
			 * @static
			 */
			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
			 * @static
			 */
			isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && 
					navigator.userAgent.match(/msie/gi)),

			/**
			 * poll handle
			 * @property _interval
			 * @private
			 */
			_interval: null,

			/**
			 * @method startInterval
			 * @static
			 * @private
			 */
			startInterval: function() {
				if (!this._interval) {
					var self = this;
					var callback = function() { self._tryPreloadAttach(); };
					this._interval = setInterval(callback, this.POLL_INTERVAL);
					// 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
			 *
			 * @static
			 */
			onAvailable: function(p_id, p_fn, p_obj, p_override) {
				onAvailStack.push( { id:		 p_id, 
									 fn:		 p_fn, 
									 obj:		p_obj, 
									 override:   p_override, 
									 checkReady: false	} );

				retryCount = this.POLL_RETRYS;
				this.startInterval();
			},

			/**
			 * Works the same way as onAvailable, but additionally checks the
			 * state of sibling elements to determine if the content of the
			 * available element is safe to modify.
			 *
			 * @method onContentReady
			 *
			 * @param {string}   p_id the id of the element to look for.
			 * @param {function} p_fn what to execute when the element is ready.
			 * @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
			 *
			 * @static
			 */
			onContentReady: function(p_id, p_fn, p_obj, p_override) {
				onAvailStack.push( { id:		 p_id, 
									 fn:		 p_fn, 
									 obj:		p_obj, 
									 override:   p_override,
									 checkReady: true	  } );

				retryCount = this.POLL_RETRYS;
				this.startInterval();
			},

			/**
			 * 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}   obj	An arbitrary object that will be 
			 *							 passed as a parameter to the handler
			 * @param {boolean}  override  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.
			 * @static
			 */
			addListener: function(el, sType, fn, obj, override) {

				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, 
									   obj, 
									   override) && 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 (oEl) {
						el = oEl;
					} else {
						// defer adding the event until the element is available
						this.onAvailable(el, function() {
						   YAHOO.util.Event.on(el, sType, fn, obj, override);
						});

						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 && obj !== this) {
					unloadListeners[unloadListeners.length] =
							[el, sType, fn, obj, override];
					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 = el;
				if (override) {
					if (override === true) {
						scope = obj;
					} else {
						scope = override;
					}
				}

				// wrap the function so we can return the obj object when
				// the event fires;
				var wrappedFn = function(e) {
						return fn.call(scope, YAHOO.util.Event.getEvent(e), 
								obj);
					};

				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);

				} else {
					this._simpleAdd(el, sType, wrappedFn, false);
				}

				return true;
				
			},

			/**
			 * When using legacy events, the handler is routed to this object
			 * so we can fire our custom listener stack.
			 * @method fireLegacyEvent
			 * @static
			 * @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
			 * @static
			 * @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
			 * @static
			 * @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.  If fn is
			 * undefined, then all event handlers for the type of event are 
			 * removed.
			 * @return {boolean} true if the unbind was successful, false 
			 * otherwise.
			 * @static
			 */
			removeListener: function(el, sType, fn) {
				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 (!fn || !fn.call) {
					//return false;
					return this.purgeElement(el, false, sType);
				}

				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;

				// The index is a hidden parameter; needed to remove it from
				// the method signature because it was tempting users to
				// try and take advantage of it, which is not possible.
				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);
									break;
							}
						}
					}

				} else {
					this._simpleRemove(el, sType, cacheItem[this.WFN], false);
				}

				// 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
			 * @static
			 */
			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 node to resolve
			 * @return {HTMLElement} the normized node
			 * @static
			 */
			resolveTextNode: function(node) {
				// if (node && node.nodeName && 
						// "#TEXT" == node.nodeName.toUpperCase()) {
				if (node && 3 == node.nodeType) {
					return node.parentNode;
				} else {
					return node;
				}
			},

			/**
			 * Returns the event's pageX
			 * @method getPageX
			 * @param {Event} ev the event
			 * @return {int} the event's pageX
			 * @static
			 */
			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
			 * @static
			 */
			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[]
			 * @static
			 */
			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
			 * @static
			 */
			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
			 * @static
			 */
			getTime: function(ev) {
				if (!ev.time) {
					var t = new Date().getTime();
					try {
						ev.time = t;
					} catch(e) { 
						return t;
					}
				}

				return ev.time;
			},

			/**
			 * Convenience method for stopPropagation + preventDefault
			 * @method stopEvent
			 * @param {Event} ev the event
			 * @static
			 */
			stopEvent: function(ev) {
				this.stopPropagation(ev);
				this.preventDefault(ev);
			},

			/**
			 * Stops event propagation
			 * @method stopPropagation
			 * @param {Event} ev the event
			 * @static
			 */
			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
			 * @static
			 */
			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} e the event parameter from the handler
			 * @return {Event} the event 
			 * @static
			 */
			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
			 * @static
			 */
			getCharCode: function(ev) {
				return ev.charCode || ev.keyCode || 0;
			},

			/**
			 * Locating the saved event handler data by function ref
			 *
			 * @method _getCacheIndex
			 * @static
			 * @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 to create the id for
			 * @return {string} the resulting id of the element
			 * @static
			 */
			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
			 * @static
			 * @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
			 * @static
			 */
			elCache: {},

			/**
			 * We cache elements bound by id because when the unload event 
			 * fires, we can no longer use document.getElementById
			 * @method getEl
			 * @static
			 * @private
			 */
			getEl: function(id) {
				return document.getElementById(id);
			},

			/**
			 * Clears the element cache
			 * @deprecated Elements are not cached any longer
			 * @method clearCache
			 * @static
			 * @private
			 */
			clearCache: function() { },

			/**
			 * hook up any deferred listeners
			 * @method _load
			 * @static
			 * @private
			 */
			_load: function(e) {
				loadComplete = true;
				var EU = YAHOO.util.Event;
				// Remove the listener to assist with the IE memory issue, but not
				// for other browsers because FF 1.0x does not like it.
				if (this.isIE) {
					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
			 * @static
			 * @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);
				}

				// onAvailable
				var notAvail = [];
				for (var i=0,len=onAvailStack.length; i<len ; ++i) {
					var item = onAvailStack[i];
					if (item) {
						var el = this.getEl(item.id);

						if (el) {
							// The element is available, but not necessarily ready

							if ( !item.checkReady || 
									loadComplete || 
									el.nextSibling ||
									(document && document.body) ) {

								var scope = el;
								if (item.override) {
									if (item.override === true) {
										scope = item.obj;
									} else {
										scope = item.override;
									}
								}
								item.fn.call(scope, item.obj);
								delete onAvailStack[i];
							}
						} else {
							notAvail.push(item);
						}
					}
				}

				retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;

				if (tryAgain) {
					this.startInterval();
				} else {
					clearInterval(this._interval);
					this._interval = null;
				}

				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
			 * @static
			 */
			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:
			 * &nbsp;&nbsp;type:   (string)   the type of event
			 * &nbsp;&nbsp;fn:	 (function) the callback supplied to addListener
			 * &nbsp;&nbsp;obj:	(object)   the custom object supplied to addListener
			 * &nbsp;&nbsp;adjust: (boolean)  whether or not to adjust the default scope
			 * &nbsp;&nbsp;index:  (int)	  its position in the Event util listener cache
			 * @static
			 */		   
			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.OBJ],
								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
			 * @static
			 * @private
			 */
			_unload: function(e) {

				var EU = YAHOO.util.Event, i, j, l, len, index;

				for (i=0,len=unloadListeners.length; i<len; ++i) {
					l = unloadListeners[i];
					if (l) {
						var scope = window;
						if (l[EU.ADJ_SCOPE]) {
							if (l[EU.ADJ_SCOPE] === true) {
								scope = l[EU.OBJ];
							} else {
								scope = l[EU.ADJ_SCOPE];
							}
						}
						l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ] );
						delete unloadListeners[i];
						l=null;
						scope=null;
					}
				}

				if (listeners && listeners.length > 0) {
					j = listeners.length;
					while (j) {
						index = j-1;
						l = listeners[index];
						if (l) {
							EU.removeListener(l[EU.EL], l[EU.TYPE], 
									l[EU.FN], index);
						} 
						j = j - 1;
					}
					l=null;

					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
			 * @static
			 * @private
			 */
			_getScrollLeft: function() {
				return this._getScroll()[1];
			},

			/**
			 * Returns scrollTop
			 * @method _getScrollTop
			 * @static
			 * @private
			 */
			_getScrollTop: function() {
				return this._getScroll()[0];
			},

			/**
			 * Returns the scrollTop and scrollLeft.  Used to calculate the 
			 * pageX and pageY in Internet Explorer
			 * @method _getScroll
			 * @static
			 * @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
			 *
			 * @method _simpleAdd
			 * @param {HTMLElement} el	  the element to bind the handler to
			 * @param {string}	  sType   the type of event handler
			 * @param {function}	fn	  the callback to invoke
			 * @param {boolen}	  capture capture or bubble phase
			 * @static
			 * @private
			 */
			_simpleAdd: function () {
				if (window.addEventListener) {
					return function(el, sType, fn, capture) {
						el.addEventListener(sType, fn, (capture));
					};
				} else if (window.attachEvent) {
					return function(el, sType, fn, capture) {
						el.attachEvent("on" + sType, fn);
					};
				} else {
					return function(){};
				}
			}(),

			/**
			 * Basic remove listener
			 *
			 * @method _simpleRemove
			 * @param {HTMLElement} el	  the element to bind the handler to
			 * @param {string}	  sType   the type of event handler
			 * @param {function}	fn	  the callback to invoke
			 * @param {boolen}	  capture capture or bubble phase
			 * @static
			 * @private
			 */
			_simpleRemove: function() {
				if (window.removeEventListener) {
					return function (el, sType, fn, capture) {
						el.removeEventListener(sType, fn, (capture));
					};
				} else if (window.detachEvent) {
					return function (el, sType, fn) {
						el.detachEvent("on" + sType, fn);
					};
				} else {
					return function(){};
				}
			}()
		};

	}();

	(function() {
		var EU = YAHOO.util.Event;

		/**
		 * YAHOO.util.Event.on is an alias for addListener
		 * @method on
		 * @see addListener
		 * @static
		 */
		EU.on = EU.addListener;

		// YAHOO.mix(EU, YAHOO.util.EventProvider.prototype);
		// EU.createEvent("DOMContentReady");
		// EU.subscribe("DOMContentReady", EU._load);

		if (document && document.body) {
			EU._load();
		} else {
			// EU._simpleAdd(document, "DOMContentLoaded", EU._load);
			EU._simpleAdd(window, "load", EU._load);
		}
		EU._simpleAdd(window, "unload", EU._unload);
		EU._tryPreloadAttach();
	})();
}

/**
* EventProvider is designed to be used with YAHOO.augment to wrap 
* CustomEvents in an interface that allows events to be subscribed to 
* and fired by name.  This makes it possible for implementing code to
* subscribe to an event that either has not been created yet, or will
* not be created at all.
*
* @Class EventProvider
*/
YAHOO.util.EventProvider = function() { };

YAHOO.util.EventProvider.prototype = {

	/**
	 * Private storage of custom events
	 * @property __yui_events
	 * @type Object[]
	 * @private
	 */
	__yui_events: null,

	/**
	 * Private storage of custom event subscribers
	 * @property __yui_subscribers
	 * @type Object[]
	 * @private
	 */
	__yui_subscribers: null,
	
	/**
	 * Subscribe to a CustomEvent by event type
	 *
	 * @method subscribe
	 * @param p_type	 {string}   the type, or name of the event
	 * @param p_fn	   {function} the function to exectute when the event fires
	 * @param p_obj
	 * @param p_obj	  {Object}   An object to be passed along when the event 
	 *							  fires
	 * @param p_override {boolean}  If true, the obj passed in becomes the 
	 *							  execution scope of the listener
	 */
	subscribe: function(p_type, p_fn, p_obj, p_override) {

		this.__yui_events = this.__yui_events || {};
		var ce = this.__yui_events[p_type];

		if (ce) {
			ce.subscribe(p_fn, p_obj, p_override);
		} else {
			this.__yui_subscribers = this.__yui_subscribers || {};
			var subs = this.__yui_subscribers;
			if (!subs[p_type]) {
				subs[p_type] = [];
			}
			subs[p_type].push(
				{ fn: p_fn, obj: p_obj, override: p_override } );
		}
	},

	/**
	 * Unsubscribes the from the specified event
	 * @method unsubscribe
	 * @param p_type {string}   The type, or name of the event
	 * @param p_fn   {Function} The function to execute
	 * @param p_obj  {Object}   The custom object passed to subscribe (optional)
	 * @return {boolean} true if the subscriber was found and detached.
	 */
	unsubscribe: function(p_type, p_fn, p_obj) {
		this.__yui_events = this.__yui_events || {};
		var ce = this.__yui_events[p_type];
		if (ce) {
			return ce.unsubscribe(p_fn, p_obj);
		} else {
			return false;
		}
	},

	/**
	 * Creates a new custom event of the specified type.  If a custom event
	 * by that name already exists, it will not be re-created.  In either
	 * case the custom event is returned. 
	 *
	 * @method createEvent
	 *
	 * @param p_type {string} the type, or name of the event
	 * @param p_config {object} optional config params.  Valid properties are:
	 *
	 *  <ul>
	 *	<li>
	 *	  scope: defines the default execution scope.  If not defined
	 *	  the default scope will be this instance.
	 *	</li>
	 *	<li>
	 *	  silent: if true, the custom event will not generate log messages.
	 *	  This is false by default.
	 *	</li>
	 *	<li>
	 *	  onSubscribeCallback: specifies a callback to execute when the
	 *	  event has a new subscriber.  This will fire immediately for
	 *	  each queued subscriber if any exist prior to the creation of
	 *	  the event.
	 *	</li>
	 *  </ul>
	 *
	 *  @return {CustomEvent} the custom event
	 *
	 */
	createEvent: function(p_type, p_config) {

		this.__yui_events = this.__yui_events || {};
		var opts = p_config || {};
		var events = this.__yui_events;

		if (events[p_type]) {
		} else {

			var scope  = opts.scope  || this;
			var silent = opts.silent || null;

			var ce = new YAHOO.util.CustomEvent(p_type, scope, silent,
					YAHOO.util.CustomEvent.FLAT);
			events[p_type] = ce;

			if (opts.onSubscribeCallback) {
				ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
			}

			this.__yui_subscribers = this.__yui_subscribers || {};
			var qs = this.__yui_subscribers[p_type];

			if (qs) {
				for (var i=0; i<qs.length; ++i) {
					ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);
				}
			}
		}

		return events[p_type];
	},

  /**
	 * Fire a custom event by name.  The callback functions will be executed
	 * from the scope specified when the event was created, and with the 
	 * following parameters:
	 *   <ul>
	 *   <li>The first argument fire() was executed with</li>
	 *   <li>The custom object (if any) that was passed into the subscribe() 
	 *	   method</li>
	 *   </ul>
	 * @method fireEvent
	 * @param p_type	{string}  the type, or name of the event
	 * @param arguments {Object*} an arbitrary set of parameters to pass to 
	 *							the handler.
	 * @return {boolean} the return value from CustomEvent.fire, or null if 
	 *				   the custom event does not exist.
	 */
	fireEvent: function(p_type, arg1, arg2, etc) {

		this.__yui_events = this.__yui_events || {};
		var ce = this.__yui_events[p_type];

		if (ce) {
			var args = [];
			for (var i=1; i<arguments.length; ++i) {
				args.push(arguments[i]);
			}
			return ce.fire.apply(ce, args);
		} else {
			return null;
		}
	},

	/**
	 * Returns true if the custom event of the provided type has been created
	 * with createEvent.
	 * @method hasEvent
	 * @param type {string} the type, or name of the event
	 */
	hasEvent: function(type) {
		if (this.__yui_events) {
			if (this.__yui_events[type]) {
				return true;
			}
		}
		return false;
	}

};


/*tabview.js*/
/*
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 0.12.0
*/
(function() {

	YAHOO.util.Lang = {
		isArray: function(val) { // frames lose type, so test constructor string
			if (val.constructor && val.constructor.toString().indexOf('Array') > -1) {
				return true;
			} else {
				return YAHOO.util.Lang.isObject(val) && val.constructor == Array;
			}
		},

		isBoolean: function(val) {
			return typeof val == 'boolean';
		},

		isFunction: function(val) {
			return typeof val == 'function';
		},

		isNull: function(val) {
			return val === null;
		},

		isNumber: function(val) {
			return !isNaN(val);
		},

		isObject: function(val) {
			return typeof val == 'object' || YAHOO.util.Lang.isFunction(val);
		},

		isString: function(val) {
			return typeof val == 'string';
		},

		isUndefined: function(val) {
			return typeof val == 'undefined';
		}
	};
})();/**
* Provides Attribute configurations.
* @namespace YAHOO.util
* @class Attribute
* @constructor
* @param hash {Object} The intial Attribute.
* @param {YAHOO.util.AttributeProvider} The owner of the Attribute instance.
*/

YAHOO.util.Attribute = function(hash, owner) {
	if (owner) {
		this.owner = owner;
		this.configure(hash, true);
	}
};

YAHOO.util.Attribute.prototype = {
	/**
	 * The name of the attribute.
	 * @property name
	 * @type String
	 */
	name: undefined,

	/**
	 * The value of the attribute.
	 * @property value
	 * @type String
	 */
	value: null,

	/**
	 * The owner of the attribute.
	 * @property owner
	 * @type YAHOO.util.AttributeProvider
	 */
	owner: null,

	/**
	 * Whether or not the attribute is read only.
	 * @property readOnly
	 * @type Boolean
	 */
	readOnly: false,

	/**
	 * Whether or not the attribute can only be written once.
	 * @property writeOnce
	 * @type Boolean
	 */
	writeOnce: false,

	/**
	 * The attribute's initial configuration.
	 * @private
	 * @property _initialConfig
	 * @type Object
	 */
	_initialConfig: null,

	/**
	 * Whether or not the attribute's value has been set.
	 * @private
	 * @property _written
	 * @type Boolean
	 */
	_written: false,

	/**
	 * The method to use when setting the attribute's value.
	 * The method recieves the new value as the only argument.
	 * @property method
	 * @type Function
	 */
	method: null,

	/**
	 * The validator to use when setting the attribute's value.
	 * @property validator
	 * @type Function
	 * @return Boolean
	 */
	validator: null,

	/**
	 * Retrieves the current value of the attribute.
	 * @method getValue
	 * @return {any} The current value of the attribute.
	 */
	getValue: function() {
		return this.value;
	},

	/**
	 * Sets the value of the attribute and fires beforeChange and change events.
	 * @method setValue
	 * @param {Any} value The value to apply to the attribute.
	 * @param {Boolean} silent If true the change events will not be fired.
	 * @return {Boolean} Whether or not the value was set.
	 */
	setValue: function(value, silent) {
		var beforeRetVal;
		var owner = this.owner;
		var name = this.name;

		var event = {
			type: name,
			prevValue: this.getValue(),
			newValue: value
		};

		if (this.readOnly || ( this.writeOnce && this._written) ) {
			return false; // write not allowed
		}

		if (this.validator && !this.validator.call(owner, value) ) {
			return false; // invalid value
		}

		if (!silent) {
			beforeRetVal = owner.fireBeforeChangeEvent(event);
			if (beforeRetVal === false) {
				YAHOO.log('setValue ' + name +
						'cancelled by beforeChange event', 'info', 'Attribute');
				return false;
			}
		}

		if (this.method) {
			this.method.call(owner, value);
		}

		this.value = value;
		this._written = true;

		event.type = name;

		if (!silent) {
			this.owner.fireChangeEvent(event);
		}

		return true;
	},

	/**
	 * Allows for configuring the Attribute's properties.
	 * @method configure
	 * @param {Object} map A key-value map of Attribute properties.
	 * @param {Boolean} init Whether or not this should become the initial config.
	 */
	configure: function(map, init) {
		map = map || {};
		this._written = false; // reset writeOnce
		this._initialConfig = this._initialConfig || {};

		for (var key in map) {
			if ( key && map.hasOwnProperty(key) ) {
				this[key] = map[key];
				if (init) {
					this._initialConfig[key] = map[key];
				}
			}
		}
	},

	/**
	 * Resets the value to the initial config value.
	 * @method resetValue
	 * @return {Boolean} Whether or not the value was set.
	 */
	resetValue: function() {
		return this.setValue(this._initialConfig.value);
	},

	/**
	 * Resets the attribute config to the initial config state.
	 * @method resetConfig
	 */
	resetConfig: function() {
		this.configure(this._initialConfig);
	},

	/**
	 * Resets the value to the current value.
	 * Useful when values may have gotten out of sync with actual properties.
	 * @method refresh
	 * @return {Boolean} Whether or not the value was set.
	 */
	refresh: function(silent) {
		this.setValue(this.value, silent);
	}
};(function() {
	var Lang = YAHOO.util.Lang;

	/*
	Copyright (c) 2006, Yahoo! Inc. All rights reserved.
	Code licensed under the BSD License:
	http://developer.yahoo.net/yui/license.txt
	*/

	/**
	 * Provides and manages YAHOO.util.Attribute instances
	 * @namespace YAHOO.util
	 * @class AttributeProvider
	 * @uses YAHOO.util.EventProvider
	 */
	YAHOO.util.AttributeProvider = function() {};

	YAHOO.util.AttributeProvider.prototype = {

		/**
		 * A key-value map of Attribute configurations
		 * @property _configs
		 * @protected (may be used by subclasses and augmentors)
		 * @private
		 * @type {Object}
		 */
		_configs: null,
		/**
		 * Returns the current value of the attribute.
		 * @method get
		 * @param {String} key The attribute whose value will be returned.
		 */
		get: function(key){
			var configs = this._configs || {};
			var config = configs[key];

			if (!config) {
				YAHOO.log(key + ' not found', 'error', 'AttributeProvider');
				return undefined;
			}

			return config.value;
		},

		/**
		 * Sets the value of a config.
		 * @method set
		 * @param {String} key The name of the attribute
		 * @param {Any} value The value to apply to the attribute
		 * @param {Boolean} silent Whether or not to suppress change events
		 * @return {Boolean} Whether or not the value was set.
		 */
		set: function(key, value, silent){
			var configs = this._configs || {};
			var config = configs[key];

			if (!config) {
				YAHOO.log('set failed: ' + key + ' not found',
						'error', 'AttributeProvider');
				return false;
			}

			return config.setValue(value, silent);
		},

		/**
		 * Returns an array of attribute names.
		 * @method getAttributeKeys
		 * @return {Array} An array of attribute names.
		 */
		getAttributeKeys: function(){
			var configs = this._configs;
			var keys = [];
			var config;
			for (var key in configs) {
				config = configs[key];
				if ( configs.hasOwnProperty(key) &&
						!Lang.isUndefined(config) ) {
					keys[keys.length] = key;
				}
			}

			return keys;
		},

		/**
		 * Sets multiple attribute values.
		 * @method setAttributes
		 * @param {Object} map  A key-value map of attributes
		 * @param {Boolean} silent Whether or not to suppress change events
		 */
		setAttributes: function(map, silent){
			for (var key in map) {
				if ( map.hasOwnProperty(key) ) {
					this.set(key, map[key], silent);
				}
			}
		},

		/**
		 * Resets the specified attribute's value to its initial value.
		 * @method resetValue
		 * @param {String} key The name of the attribute
		 * @param {Boolean} silent Whether or not to suppress change events
		 * @return {Boolean} Whether or not the value was set
		 */
		resetValue: function(key, silent){
			var configs = this._configs || {};
			if (configs[key]) {
				this.set(key, configs[key]._initialConfig.value, silent);
				return true;
			}
			return false;
		},

		/**
		 * Sets the attribute's value to its current value.
		 * @method refresh
		 * @param {String | Array} key The attribute(s) to refresh
		 * @param {Boolean} silent Whether or not to suppress change events
		 */
		refresh: function(key, silent){
			var configs = this._configs;

			key = ( ( Lang.isString(key) ) ? [key] : key ) ||
					this.getAttributeKeys();

			for (var i = 0, len = key.length; i < len; ++i) {
				if ( // only set if there is a value and not null
					configs[key[i]] &&
					! Lang.isUndefined(configs[key[i]].value) &&
					! Lang.isNull(configs[key[i]].value) ) {
					configs[key[i]].refresh(silent);
				}
			}
		},

		/**
		 * Adds an Attribute to the AttributeProvider instance.
		 * @method register
		 * @param {String} key The attribute's name
		 * @param {Object} map A key-value map containing the
		 * attribute's properties.
		 */
		register: function(key, map) {
			this._configs = this._configs || {};

			if (this._configs[key]) { // dont override
				return false;
			}

			map.name = key;
			this._configs[key] = new YAHOO.util.Attribute(map, this);
			return true;
		},

		/**
		 * Returns the attribute's properties.
		 * @method getAttributeConfig
		 * @param {String} key The attribute's name
		 * @private
		 * @return {object} A key-value map containing all of the
		 * attribute's properties.
		 */
		getAttributeConfig: function(key) {
			var configs = this._configs || {};
			var config = configs[key] || {};
			var map = {}; // returning a copy to prevent overrides

			for (key in config) {
				if ( config.hasOwnProperty(key) ) {
					map[key] = config[key];
				}
			}

			return map;
		},

		/**
		 * Sets or updates an Attribute instance's properties.
		 * @method configureAttribute
		 * @param {String} key The attribute's name.
		 * @param {Object} map A key-value map of attribute properties
		 * @param {Boolean} init Whether or not this should become the intial config.
		 */
		configureAttribute: function(key, map, init) {
			var configs = this._configs || {};

			if (!configs[key]) {
				YAHOO.log('unable to configure, ' + key + ' not found',
						'error', 'AttributeProvider');
				return false;
			}

			configs[key].configure(map, init);
		},

		/**
		 * Resets an attribute to its intial configuration.
		 * @method resetAttributeConfig
		 * @param {String} key The attribute's name.
		 * @private
		 */
		resetAttributeConfig: function(key){
			var configs = this._configs || {};
			configs[key].resetConfig();
		},

		/**
		 * Fires the attribute's beforeChange event.
		 * @method fireBeforeChangeEvent
		 * @param {String} key The attribute's name.
		 * @param {Obj} e The event object to pass to handlers.
		 */
		fireBeforeChangeEvent: function(e) {
			var type = 'before';
			type += e.type.charAt(0).toUpperCase() + e.type.substr(1) + 'Change';
			e.type = type;
			return this.fireEvent(e.type, e);
		},

		/**
		 * Fires the attribute's change event.
		 * @method fireChangeEvent
		 * @param {String} key The attribute's name.
		 * @param {Obj} e The event object to pass to the handlers.
		 */
		fireChangeEvent: function(e) {
			e.type += 'Change';
			return this.fireEvent(e.type, e);
		}
	};

	YAHOO.augment(YAHOO.util.AttributeProvider, YAHOO.util.EventProvider);
})();(function() {
// internal shorthand
var Dom = YAHOO.util.Dom,
	Lang = YAHOO.util.Lang,
	EventPublisher = YAHOO.util.EventPublisher,
	AttributeProvider = YAHOO.util.AttributeProvider;

/**
* Element provides an interface to an HTMLElement's attributes and common
* methods.  Other commonly used attributes are added as well.
* @namespace YAHOO.util
* @class Element
* @uses YAHOO.util.AttributeProvider
* @constructor
* @param el {HTMLElement | String} The html element that
* represents the Element.
* @param {Object} map A key-value map of initial config names and values
*/
YAHOO.util.Element = function(el, map) {
	if (arguments.length) {
		this.init(el, map);
	}
};

YAHOO.util.Element.prototype = {
	/**
	 * Dom events supported by the Element instance.
	 * @property DOM_EVENTS
	 * @type Object
	 */
	DOM_EVENTS: null,

	/**
	 * Wrapper for HTMLElement method.
	 * @method appendChild
	 * @param {Boolean} deep Whether or not to do a deep clone
	 */
	appendChild: function(child) {
		child = child.get ? child.get('element') : child;
		this.get('element').appendChild(child);
	},

	/**
	 * Wrapper for HTMLElement method.
	 * @method getElementsByTagName
	 * @param {String} tag The tagName to collect
	 */
	getElementsByTagName: function(tag) {
		return this.get('element').getElementsByTagName(tag);
	},

	/**
	 * Wrapper for HTMLElement method.
	 * @method hasChildNodes
	 * @return {Boolean} Whether or not the element has childNodes
	 */
	hasChildNodes: function() {
		return this.get('element').hasChildNodes();
	},

	/**
	 * Wrapper for HTMLElement method.
	 * @method insertBefore
	 * @param {HTMLElement} element The HTMLElement to insert
	 * @param {HTMLElement} before The HTMLElement to insert
	 * the element before.
	 */
	insertBefore: function(element, before) {
		element = element.get ? element.get('element') : element;
		before = (before && before.get) ? before.get('element') : before;

		this.get('element').insertBefore(element, before);
	},

	/**
	 * Wrapper for HTMLElement method.
	 * @method removeChild
	 * @param {HTMLElement} child The HTMLElement to remove
	 */
	removeChild: function(child) {
		child = child.get ? child.get('element') : child;
		this.get('element').removeChild(child);
		return true;
	},

	/**
	 * Wrapper for HTMLElement method.
	 * @method replaceChild
	 * @param {HTMLElement} newNode The HTMLElement to insert
	 * @param {HTMLElement} oldNode The HTMLElement to replace
	 */
	replaceChild: function(newNode, oldNode) {
		newNode = newNode.get ? newNode.get('element') : newNode;
		oldNode = oldNode.get ? oldNode.get('element') : oldNode;
		return this.get('element').replaceChild(newNode, oldNode);
	},


	/**
	 * Registers Element specific attributes.
	 * @method initAttributes
	 * @param {Object} map A key-value map of initial attribute configs
	 */
	initAttributes: function(map) {
		map = map || {};
		var element = Dom.get(map.element) || null;

		/**
		 * The HTMLElement the Element instance refers to.
		 * @config element
		 * @type HTMLElement
		 */
		this.register('element', {
			value: element,
			readOnly: true
		 });
	},

	/**
	 * Adds a listener for the given event.  These may be DOM or
	 * customEvent listeners.  Any event that is fired via fireEvent
	 * can be listened for.  All handlers receive an event object.
	 * @method addListener
	 * @param {String} type The name of the event to listen for
	 * @param {Function} fn The handler to call when the event fires
	 * @param {Any} obj A variable to pass to the handler
	 * @param {Object} scope The object to use for the scope of the handler
	 */
	addListener: function(type, fn, obj, scope) {
		var el = this.get('element');
		var scope = scope || this;

		el = this.get('id') || el;

		if (!this._events[type]) { // create on the fly
			if ( this.DOM_EVENTS[type] ) {
				YAHOO.util.Event.addListener(el, type, function(e) {
					if (e.srcElement && !e.target) { // supplement IE with target
						e.target = e.srcElement;
					}
					this.fireEvent(type, e);
				}, obj, scope);
			}

			this.createEvent(type, this);
			this._events[type] = true;
		}

		this.subscribe.apply(this, arguments); // notify via customEvent
	},


	/**
	 * Alias for addListener
	 * @method on
	 * @param {String} type The name of the event to listen for
	 * @param {Function} fn The function call when the event fires
	 * @param {Any} obj A variable to pass to the handler
	 * @param {Object} scope The object to use for the scope of the handler
	 */
	on: function() { this.addListener.apply(this, arguments); },


	/**
	 * Remove an event listener
	 * @method removeListener
	 * @param {String} type The name of the event to listen for
	 * @param {Function} fn The function call when the event fires
	 */
	removeListener: function(type, fn) {
		this.unsubscribe.apply(this, arguments);
	},

	/**
	 * Wrapper for Dom method.
	 * @method addClass
	 * @param {String} className The className to add
	 */
	addClass: function(className) {
		Dom.addClass(this.get('element'), className);
	},

	/**
	 * Wrapper for Dom method.
	 * @method getElementsByClassName
	 * @param {String} className The className to collect
	 * @param {String} tag (optional) The tag to use in
	 * conjunction with class name
	 * @return {Array} Array of HTMLElements
	 */
	getElementsByClassName: function(className, tag) {
		return Dom.getElementsByClassName(className, tag,
				this.get('element') );
	},

	/**
	 * Wrapper for Dom method.
	 * @method hasClass
	 * @param {String} className The className to add
	 * @return {Boolean} Whether or not the element has the class name
	 */
	hasClass: function(className) {
		return Dom.hasClass(this.get('element'), className);
	},

	/**
	 * Wrapper for Dom method.
	 * @method removeClass
	 * @param {String} className The className to remove
	 */
	removeClass: function(className) {
		return Dom.removeClass(this.get('element'), className);
	},

	/**
	 * Wrapper for Dom method.
	 * @method replaceClass
	 * @param {String} oldClassName The className to replace
	 * @param {String} newClassName The className to add
	 */
	replaceClass: function(oldClassName, newClassName) {
		return Dom.replaceClass(this.get('element'),
				oldClassName, newClassName);
	},

	/**
	 * Wrapper for Dom method.
	 * @method setStyle
	 * @param {String} property The style property to set
	 * @param {String} value The value to apply to the style property
	 */
	setStyle: function(property, value) {
		return Dom.setStyle(this.get('element'),  property, value);
	},

	/**
	 * Wrapper for Dom method.
	 * @method getStyle
	 * @param {String} property The style property to retrieve
	 * @return {String} The current value of the property
	 */
	getStyle: function(property) {
		return Dom.getStyle(this.get('element'),  property);
	},

	/**
	 * Apply any queued set calls.
	 * @method fireQueue
	 */
	fireQueue: function() {
		var queue = this._queue;
		for (var i = 0, len = queue.length; i < len; ++i) {
			this[queue[i][0]].apply(this, queue[i][1]);
		}
	},

	/**
	 * Appends the HTMLElement into either the supplied parentNode.
	 * @method appendTo
	 * @param {HTMLElement | Element} parentNode The node to append to
	 * @param {HTMLElement | Element} before An optional node to insert before
	 */
	appendTo: function(parent, before) {
		parent = (parent.get) ?  parent.get('element') : Dom.get(parent);

		before = (before && before.get) ?
				before.get('element') : Dom.get(before);
		var element = this.get('element');

		var newAddition =  !Dom.inDocument(element);

		if (!element) {
			YAHOO.log('appendTo failed: element not available',
					'error', 'Element');
			return false;
		}

		if (!parent) {
			YAHOO.log('appendTo failed: parent not available',
					'error', 'Element');
			return false;
		}

		if (element.parent != parent) {
			if (before) {
				parent.insertBefore(element, before);
			} else {
				parent.appendChild(element);
			}
		}

		YAHOO.log(element + 'appended to ' + parent);

		if (!newAddition) {
			return false; // note return; no refresh if in document
		}

		// if a new addition, refresh HTMLElement any applied attributes
		var keys = this.getAttributeKeys();

		for (var key in keys) { // only refresh HTMLElement attributes
			if ( !Lang.isUndefined(element[key]) ) {
				this.refresh(key);
			}
		}
	},

	get: function(key) {
		var configs = this._configs || {};
		var el = configs.element; // avoid loop due to 'element'
		if (el && !configs[key] && !Lang.isUndefined(el.value[key]) ) {
			return el.value[key];
		}

		return AttributeProvider.prototype.get.call(this, key);
	},

	set: function(key, value, silent) {
		var el = this.get('element');
		if (!el) {
			this._queue[key] = ['set', arguments];
			return false;
		}

		// set it on the element if not a property
		if ( !this._configs[key] && !Lang.isUndefined(el[key]) ) {
			_registerHTMLAttr(this, key);
		}

		return AttributeProvider.prototype.set.apply(this, arguments);
	},

	register: function(key) { // protect html attributes
		var configs = this._configs || {};
		var element = this.get('element') || null;

		if ( element && !Lang.isUndefined(element[key]) ) {
			YAHOO.log(key + ' is reserved for ' + element,
					'error', 'Element');
			return false;
		}

		return AttributeProvider.prototype.register.apply(this, arguments);
	},

	configureAttribute: function(property, map, init) { // protect html attributes
		if (!this._configs[property] && this._configs.element &&
				!Lang.isUndefined(this._configs.element[property]) ) {
			_registerHTMLAttr(this, property, map);
			return false;
		}

		return AttributeProvider.prototype.configure.apply(this, arguments);
	},

	getAttributeKeys: function() {
		var el = this.get('element');
		var keys = AttributeProvider.prototype.getAttributeKeys.call(this);

		//add any unconfigured element keys
		for (var key in el) {
			if (!this._configs[key]) {
				keys[key] = keys[key] || el[key];
			}
		}

		return keys;
	},

	init: function(el, attr) {
		this._queue = this._queue || [];
		this._events = this._events || {};
		this._configs = this._configs || {};
		attr = attr || {};
		attr.element = attr.element || el || null;

		this.DOM_EVENTS = {
			'click': true,
			'keydown': true,
			'keypress': true,
			'keyup': true,
			'mousedown': true,
			'mousemove': true,
			'mouseout': true,
			'mouseover': true,
			'mouseup': true
		};

		var readyHandler = function() {
			this.initAttributes(attr);

			this.setAttributes(attr, true);
			this.fireQueue();
			this.fireEvent('contentReady', {
				type: 'contentReady',
				target: attr.element
			});
		};

		if ( Lang.isString(el) ) {
			_registerHTMLAttr(this, 'id', { value: el });
			YAHOO.util.Event.onAvailable(el, function() {
				attr.element = Dom.get(el);
				this.fireEvent('available', {
					type: 'available',
					target: attr.element
				});
			}, this, true);

			YAHOO.util.Event.onContentReady(el, function() {
				readyHandler.call(this);
			}, this, true);
		} else {
			readyHandler.call(this);
		}
	}
};

/**
* Sets the value of the property and fires beforeChange and change events.
* @private
* @method _registerHTMLAttr
* @param {YAHOO.util.Element} element The Element instance to
* register the config to.
* @param {String} key The name of the config to register
* @param {Object} map A key-value map of the config's params
*/
var _registerHTMLAttr = function(self, key, map) {
	var el = self.get('element');
	map = map || {};
	map.name = key;
	map.method = map.method || function(value) {
		el[key] = value;
	};
	map.value = map.value || el[key];
	self._configs[key] = new YAHOO.util.Attribute(map, self);
};

/**
* Fires when the Element's HTMLElement can be retrieved by Id.
* <p>See: <a href="#addListener">Element.addListener</a></p>
* <p><strong>Event fields:</strong><br>
* <code>&lt;String&gt; type</code> available<br>
* <code>&lt;HTMLElement&gt;
* target</code> the HTMLElement bound to this Element instance<br>
* <p><strong>Usage:</strong><br>
* <code>var handler = function(e) {var target = e.target};<br>
* myTabs.addListener('available', handler);</code></p>
* @event available
*/

/**
* Fires when the Element's HTMLElement subtree is rendered.
* <p>See: <a href="#addListener">Element.addListener</a></p>
* <p><strong>Event fields:</strong><br>
* <code>&lt;String&gt; type</code> contentReady<br>
* <code>&lt;HTMLElement&gt;
* target</code> the HTMLElement bound to this Element instance<br>
* <p><strong>Usage:</strong><br>
* <code>var handler = function(e) {var target = e.target};<br>
* myTabs.addListener('contentReady', handler);</code></p>
* @event contentReady
*/

YAHOO.augment(YAHOO.util.Element, AttributeProvider);
})();(function() {
	var Dom = YAHOO.util.Dom,
		Event = YAHOO.util.Event,
		Lang = YAHOO.util.Lang;

	/**
	 * A representation of a Tab's label and content.
	 * @namespace YAHOO.widget
	 * @class Tab
	 * @extends YAHOO.util.Element
	 * @constructor
	 * @param element {HTMLElement | String} (optional) The html element that
	 * represents the TabView. An element will be created if none provided.
	 * @param {Object} properties A key map of initial properties
	 */
	Tab = function(el, attr) {
		attr = attr || {};
		if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
			attr = el;
			el = attr.element;
		}

		if (!el && !attr.element) {
			el = _createTabElement.call(this, attr);
		}

		this.loadHandler =  {
			success: function(o) {
				this.set('content', o.responseText);
			},
			failure: function(o) {
				YAHOO.log('loading failed: ' + o.statusText,
						'error', 'Tab');
			}
		};

		Tab.superclass.constructor.call(this, el, attr);

		this.DOM_EVENTS = {}; // delegating to tabView
	};

	YAHOO.extend(Tab, YAHOO.util.Element);
	var proto = Tab.prototype;

	/**
	 * The default tag name for a Tab's inner element.
	 * @property LABEL_INNER_TAGNAME
	 * @type String
	 * @default "em"
	 */
	proto.LABEL_TAGNAME = 'em';

	/**
	 * The class name applied to active tabs.
	 * @property ACTIVE_CLASSNAME
	 * @type String
	 * @default "on"
	 */
	proto.ACTIVE_CLASSNAME = 'selected';

	/**
	 * The class name applied to disabled tabs.
	 * @property DISABLED_CLASSNAME
	 * @type String
	 * @default "disabled"
	 */
	proto.DISABLED_CLASSNAME = 'disabled';

	/**
	 * The class name applied to dynamic tabs while loading.
	 * @property LOADING_CLASSNAME
	 * @type String
	 * @default "disabled"
	 */
	proto.LOADING_CLASSNAME = 'loading';

	/**
	 * Provides a reference to the connection request object when data is
	 * loaded dynamically.
	 * @property dataConnection
	 * @type Object
	 */
	proto.dataConnection = null;

	/**
	 * Object containing success and failure callbacks for loading data.
	 * @property loadHandler
	 * @type object
	 */
	proto.loadHandler = null;

	/**
	 * Provides a readable name for the tab.
	 * @method toString
	 * @return String
	 */
	proto.toString = function() {
		var el = this.get('element');
		var id = el.id || el.tagName;
		return "Tab " + id;
	};

	/**
	 * Registers TabView specific properties.
	 * @method initAttributes
	 * @param {Object} attr Hash of initial attributes
	 */
	proto.initAttributes = function(attr) {
		attr = attr || {};
		Tab.superclass.initAttributes.call(this, attr);

		var el = this.get('element');

		/**
		 * The event that triggers the tab's activation.
		 * @config activationEvent
		 * @type String
		 */
		this.register('activationEvent', {
			value: attr.activationEvent || 'click'
		});

		/**
		 * The element that contains the tab's label.
		 * @config labelEl
		 * @type HTMLElement
		 */
		this.register('labelEl', {
			value: attr.labelEl || _getlabelEl.call(this),
			method: function(value) {
				var current = this.get('labelEl');

				if (current) {
					if (current == value) {
						return false; // already set
					}

					this.replaceChild(value, current);
				} else if (el.firstChild) { // ensure label is firstChild by default
					this.insertBefore(value, el.firstChild);
				} else {
					this.appendChild(value);
				}
			}
		});

		/**
		 * The tab's label text (or innerHTML).
		 * @config label
		 * @type String
		 */
		this.register('label', {
			value: attr.label || _getLabel.call(this),
			method: function(value) {
				var labelEl = this.get('labelEl');
				if (!labelEl) { // create if needed
					this.set('labelEl', _createlabelEl.call(this));
				}

				_setLabel.call(this, value);
			}
		});

		/**
		 * The HTMLElement that contains the tab's content.
		 * @config contentEl
		 * @type HTMLElement
		 */
		this.register('contentEl', { // TODO: apply className?
			value: attr.contentEl || document.createElement('div'),
			method: function(value) {
				var current = this.get('contentEl');

				if (current) {
					if (current == value) {
						return false; // already set
					}
					this.replaceChild(value, current);
				}
			}
		});

		/**
		 * The tab's content.
		 * @config content
		 * @type String
		 */
		this.register('content', {
			value: attr.content, // TODO: what about existing?
			method: function(value) {
				this.get('contentEl').innerHTML = value;
			}
		});

		var _dataLoaded = false;

		/**
		 * The tab's data source, used for loading content dynamically.
		 * @config dataSrc
		 * @type String
		 */
		this.register('dataSrc', {
			value: attr.dataSrc
		});

		/**
		 * Whether or not content should be reloaded for every view.
		 * @config cacheData
		 * @type Boolean
		 * @default false
		 */
		this.register('cacheData', {
			value: attr.cacheData || false,
			validator: Lang.isBoolean
		});

		/**
		 * The method to use for the data request.
		 * @config loadMethod
		 * @type String
		 * @default "GET"
		 */
		this.register('loadMethod', {
			value: attr.loadMethod || 'GET',
			validator: Lang.isString
		});

		/**
		 * Whether or not any data has been loaded from the server.
		 * @config dataLoaded
		 * @type Boolean
		 */
		this.register('dataLoaded', {
			value: false,
			validator: Lang.isBoolean,
			writeOnce: true
		});

		/**
		 * Number if milliseconds before aborting and calling failure handler.
		 * @config dataTimeout
		 * @type Number
		 * @default null
		 */
		this.register('dataTimeout', {
			value: attr.dataTimeout || null,
			validator: Lang.isNumber
		});

		/**
		 * Whether or not the tab is currently active.
		 * If a dataSrc is set for the tab, the content will be loaded from
		 * the given source.
		 * @config active
		 * @type Boolean
		 */
		this.register('active', {
			value: attr.active || this.hasClass(this.ACTIVE_CLASSNAME),
			method: function(value) {
				if (value === true) {
					this.addClass(this.ACTIVE_CLASSNAME);
					this.set('title', 'active');
				} else {
					this.removeClass(this.ACTIVE_CLASSNAME);
					this.set('title', '');
				}
			},
			validator: function(value) {
				return Lang.isBoolean(value) && !this.get('disabled') ;
			}
		});

		/**
		 * Whether or not the tab is disabled.
		 * @config disabled
		 * @type Boolean
		 */
		this.register('disabled', {
			value: attr.disabled || this.hasClass(this.DISABLED_CLASSNAME),
			method: function(value) {
				if (value === true) {
					Dom.addClass(this.get('element'), this.DISABLED_CLASSNAME);
				} else {
					Dom.removeClass(this.get('element'), this.DISABLED_CLASSNAME);
				}
			},
			validator: Lang.isBoolean
		});

		/**
		 * The href of the tab's anchor element.
		 * @config href
		 * @type String
		 * @default '#'
		 */
		this.register('href', {
			value: attr.href || '#',
			method: function(value) {
				this.getElementsByTagName('a')[0].href = value;
			},
			validator: Lang.isString
		});

		/**
		 * The Whether or not the tab's content is visible.
		 * @config contentVisible
		 * @type Boolean
		 * @default false
		 */
		this.register('contentVisible', {
			value: attr.contentVisible,
			method: function(value) {
				if (value == true) {
					this.get('contentEl').style.display = 'block';

					if ( this.get('dataSrc') ) {
					 // load dynamic content unless already loaded and caching
						if ( !this.get('dataLoaded') || !this.get('cacheData') ) {
							_dataConnect.call(this);
						}
					}
				} else {
					this.get('contentEl').style.display = 'none';
				}
			},
			validator: Lang.isBoolean
		});
	};

	var _createTabElement = function(attr) {
		var el = document.createElement('li');
		var a = document.createElement('a');

		a.href = attr.href || '#';

		el.appendChild(a);

		var label = attr.label || null;
		var labelEl = attr.labelEl || null;

		if (labelEl) { // user supplied labelEl
			if (!label) { // user supplied label
				label = _getLabel.call(this, labelEl);
			}
		} else {
			labelEl = _createlabelEl.call(this);
		}

		a.appendChild(labelEl);

		return el;
	};

	var _getlabelEl = function() {
		return this.getElementsByTagName(this.LABEL_TAGNAME)[0];
	};

	var _createlabelEl = function() {
		var el = document.createElement(this.LABEL_TAGNAME);
		return el;
	};

	var _setLabel = function(label) {
		var el = this.get('labelEl');
		el.innerHTML = label;
	};

	var _getLabel = function() {
		var label,
			el = this.get('labelEl');

			if (!el) {
				return undefined;
			}

		return el.innerHTML;
	};

	var _dataConnect = function() {
		if (!YAHOO.util.Connect) {
			YAHOO.log('YAHOO.util.Connect dependency not met',
					'error', 'Tab');
			return false;
		}

		Dom.addClass(this.get('contentEl').parentNode, this.LOADING_CLASSNAME);

		this.dataConnection = YAHOO.util.Connect.asyncRequest(
			this.get('loadMethod'),
			this.get('dataSrc'),
			{
				success: function(o) {
					this.loadHandler.success.call(this, o);
					this.set('dataLoaded', true);
					this.dataConnection = null;
					Dom.removeClass(this.get('contentEl').parentNode,
							this.LOADING_CLASSNAME);
				},
				failure: function(o) {
					this.loadHandler.failure.call(this, o);
					this.dataConnection = null;
					Dom.removeClass(this.get('contentEl').parentNode,
							this.LOADING_CLASSNAME);
				},
				scope: this,
				timeout: this.get('dataTimeout')
			}
		);
	};

	YAHOO.widget.Tab = Tab;

	/**
	 * Fires before the active state is changed.
	 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
	 * <p>If handler returns false, the change will be cancelled, and the value will not
	 * be set.</p>
	 * <p><strong>Event fields:</strong><br>
	 * <code>&lt;String&gt; type</code> beforeActiveChange<br>
	 * <code>&lt;Boolean&gt;
	 * prevValue</code> the current value<br>
	 * <code>&lt;Boolean&gt;
	 * newValue</code> the new value</p>
	 * <p><strong>Usage:</strong><br>
	 * <code>var handler = function(e) {var previous = e.prevValue};<br>
	 * myTabs.addListener('beforeActiveChange', handler);</code></p>
	 * @event beforeActiveChange
	 */

	/**
	 * Fires after the active state is changed.
	 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
	 * <p><strong>Event fields:</strong><br>
	 * <code>&lt;String&gt; type</code> activeChange<br>
	 * <code>&lt;Boolean&gt;
	 * prevValue</code> the previous value<br>
	 * <code>&lt;Boolean&gt;
	 * newValue</code> the updated value</p>
	 * <p><strong>Usage:</strong><br>
	 * <code>var handler = function(e) {var previous = e.prevValue};<br>
	 * myTabs.addListener('activeChange', handler);</code></p>
	 * @event activeChange
	 */

	/**
	 * Fires before the tab label is changed.
	 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
	 * <p>If handler returns false, the change will be cancelled, and the value will not
	 * be set.</p>
	 * <p><strong>Event fields:</strong><br>
	 * <code>&lt;String&gt; type</code> beforeLabelChange<br>
	 * <code>&lt;String&gt;
	 * prevValue</code> the current value<br>
	 * <code>&lt;String&gt;
	 * newValue</code> the new value</p>
	 * <p><strong>Usage:</strong><br>
	 * <code>var handler = function(e) {var previous = e.prevValue};<br>
	 * myTabs.addListener('beforeLabelChange', handler);</code></p>
	 * @event beforeLabelChange
	 */

	/**
	 * Fires after the tab label is changed.
	 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
	 * <p><strong>Event fields:</strong><br>
	 * <code>&lt;String&gt; type</code> labelChange<br>
	 * <code>&lt;String&gt;
	 * prevValue</code> the previous value<br>
	 * <code>&lt;String&gt;
	 * newValue</code> the updated value</p>
	 * <p><strong>Usage:</strong><br>
	 * <code>var handler = function(e) {var previous = e.prevValue};<br>
	 * myTabs.addListener('labelChange', handler);</code></p>
	 * @event labelChange
	 */

	/**
	 * Fires before the tab content is changed.
	 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
	 * <p>If handler returns false, the change will be cancelled, and the value will not
	 * be set.</p>
	 * <p><strong>Event fields:</strong><br>
	 * <code>&lt;String&gt; type</code> beforeContentChange<br>
	 * <code>&lt;String&gt;
	 * prevValue</code> the current value<br>
	 * <code>&lt;String&gt;
	 * newValue</code> the new value</p>
	 * <p><strong>Usage:</strong><br>
	 * <code>var handler = function(e) {var previous = e.prevValue};<br>
	 * myTabs.addListener('beforeContentChange', handler);</code></p>
	 * @event beforeContentChange
	 */

	/**
	 * Fires after the tab content is changed.
	 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
	 * <p><strong>Event fields:</strong><br>
	 * <code>&lt;String&gt; type</code> contentChange<br>
	 * <code>&lt;String&gt;
	 * prevValue</code> the previous value<br>
	 * <code>&lt;Boolean&gt;
	 * newValue</code> the updated value</p>
	 * <p><strong>Usage:</strong><br>
	 * <code>var handler = function(e) {var previous = e.prevValue};<br>
	 * myTabs.addListener('contentChange', handler);</code></p>
	 * @event contentChange
	 */
})();(function() {

	/**
	 * The tabview module provides a widget for managing content bound to tabs.
	 * @module tabview
	 *
	 */
	/**
	 * A widget to control tabbed views.
	 * @namespace YAHOO.widget
	 * @class TabView
	 * @extends YAHOO.util.Element
	 * @constructor
	 * @param {HTMLElement | String | Object} el(optional) The html
	 * element that represents the TabView, or the attribute object to use.
	 * An element will be created if none provided.
	 * @param {Object} attr (optional) A key map of the tabView's
	 * initial attributes.  Ignored if first arg is attributes object.
	 */
	YAHOO.widget.TabView = function(el, attr) {
		attr = attr || {};
		if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
			attr = el; // treat first arg as attr object
			el = attr.element || null;
		}

		if (!el && !attr.element) { // create if we dont have one
			el = _createTabViewElement.call(this, attr);
		}
		YAHOO.widget.TabView.superclass.constructor.call(this, el, attr);
	};

	YAHOO.extend(YAHOO.widget.TabView, YAHOO.util.Element);

	var proto = YAHOO.widget.TabView.prototype;
	var Dom = YAHOO.util.Dom;
	var Lang = YAHOO.util.Lang;
	var Event = YAHOO.util.Event;
	var Tab = YAHOO.widget.Tab;


	/**
	 * The className to add when building from scratch.
	 * @property CLASSNAME
	 * @default "navset"
	 */
	proto.CLASSNAME = 'yui-navset';

	/**
	 * The className of the HTMLElement containing the TabView's tab elements
	 * to look for when building from existing markup, or to add when building
	 * from scratch.
	 * All childNodes of the tab container are treated as Tabs when building
	 * from existing markup.
	 * @property TAB_PARENT_CLASSNAME
	 * @default "nav"
	 */
	proto.TAB_PARENT_CLASSNAME = 'yui-nav';

	/**
	 * The className of the HTMLElement containing the TabView's label elements
	 * to look for when building from existing markup, or to add when building
	 * from scratch.
	 * All childNodes of the content container are treated as content elements when
	 * building from existing markup.
	 * @property CONTENT_PARENT_CLASSNAME
	 * @default "nav-content"
	 */
	proto.CONTENT_PARENT_CLASSNAME = 'yui-content';

	proto._tabParent = null;
	proto._contentParent = null;

	/**
	 * Adds a Tab to the TabView instance.
	 * If no index is specified, the tab is added to the end of the tab list.
	 * @method addTab
	 * @param {YAHOO.widget.Tab} tab A Tab instance to add.
	 * @param {Integer} index The position to add the tab.
	 * @return void
	 */
	proto.addTab = function(tab, index) {
		var tabs = this.get('tabs');
		if (!tabs) { // not ready yet
			this._queue[this._queue.length] = ['addTab', arguments];
			return false;
		}

		index = (index === undefined) ? tabs.length : index;

		var before = this.getTab(index);

		var self = this;
		var el = this.get('element');
		var tabParent = this._tabParent;
		var contentParent = this._contentParent;

		var tabElement = tab.get('element');
		var contentEl = tab.get('contentEl');

		if ( before ) {
			tabParent.insertBefore(tabElement, before.get('element'));
		} else {
			tabParent.appendChild(tabElement);
		}

		if ( contentEl && !Dom.isAncestor(contentParent, contentEl) ) {
			contentParent.appendChild(contentEl);
		}

		if ( !tab.get('active') ) {
			tab.set('contentVisible', false, true); /* hide if not active */
		} else {
			this.set('activeTab', tab, true);

		}

		var activate = function(e) {
			YAHOO.util.Event.preventDefault(e);
			self.set('activeTab', this);
		};

		tab.addListener( tab.get('activationEvent'), activate);

		tab.addListener('activationEventChange', function(e) {
			if (e.prevValue != e.newValue) {
				tab.removeListener(e.prevValue, activate);
				tab.addListener(e.newValue, activate);
			}
		});

		tabs.splice(index, 0, tab);
	};

	/**
	 * Routes childNode events.
	 * @method DOMEventHandler
	 * @param {event} e The Dom event that is being handled.
	 * @return void
	 */
	proto.DOMEventHandler = function(e) {
		var el = this.get('element');
		var target = YAHOO.util.Event.getTarget(e);
		var tabParent = this._tabParent;

		if (Dom.isAncestor(tabParent, target) ) {
			var tabEl;
			var tab = null;
			var contentEl;
			var tabs = this.get('tabs');

			for (var i = 0, len = tabs.length; i < len; i++) {
				tabEl = tabs[i].get('element');
				contentEl = tabs[i].get('contentEl');

				if ( target == tabEl || Dom.isAncestor(tabEl, target) ) {
					tab = tabs[i];
					break; // note break
				}
			}

			if (tab) {
				tab.fireEvent(e.type, e);
			}
		}
	};

	/**
	 * Returns the Tab instance at the specified index.
	 * @method getTab
	 * @param {Integer} index The position of the Tab.
	 * @return YAHOO.widget.Tab
	 */
	proto.getTab = function(index) {
		return this.get('tabs')[index];
	};

	/**
	 * Returns the index of given tab.
	 * @method getTabIndex
	 * @param {YAHOO.widget.Tab} tab The tab whose index will be returned.
	 * @return int
	 */
	proto.getTabIndex = function(tab) {
		var index = null;
		var tabs = this.get('tabs');
		for (var i = 0, len = tabs.length; i < len; ++i) {
			if (tab == tabs[i]) {
				index = i;
				break;
			}
		}

		return index;
	};

	/**
	 * Removes the specified Tab from the TabView.
	 * @method removeTab
	 * @param {YAHOO.widget.Tab} item The Tab instance to be removed.
	 * @return void
	 */
	proto.removeTab = function(tab) {
		var tabCount = this.get('tabs').length;

		var index = this.getTabIndex(tab);
		var nextIndex = index + 1;
		if ( tab == this.get('activeTab') ) { // select next tab
			if (tabCount > 1) {
				if (index + 1 == tabCount) {
					this.set('activeIndex', index - 1);
				} else {
					this.set('activeIndex', index + 1);
				}
			}
		}

		this._tabParent.removeChild( tab.get('element') );
		this._contentParent.removeChild( tab.get('contentEl') );
		this._configs.tabs.value.splice(index, 1);

	};

	/**
	 * Provides a readable name for the TabView instance.
	 * @method toString
	 * @return String
	 */
	proto.toString = function() {
		var name = this.get('id') || this.get('tagName');
		return "TabView " + name;
	};

	/**
	 * The transiton to use when switching between tabs.
	 * @method contentTransition
	 */
	proto.contentTransition = function(newTab, oldTab) {
		newTab.set('contentVisible', true);
		oldTab.set('contentVisible', false);
	};

	/**
	 * Registers TabView specific properties.
	 * @method initAttributes
	 * @param {Object} attr Hash of initial attributes
	 */
	proto.initAttributes = function(attr) {
		YAHOO.widget.TabView.superclass.initAttributes.call(this, attr);

		if (!attr.orientation) {
			attr.orientation = 'top';
		}

		var el = this.get('element');

		/**
		 * The Tabs belonging to the TabView instance.
		 * @config tabs
		 * @type Array
		 */
		this.register('tabs', {
			value: [],
			readOnly: true
		});

		/**
		 * The container of the tabView's label elements.
		 * @property _tabParent
		 * @private
		 * @type HTMLElement
		 */
		this._tabParent =
				this.getElementsByClassName(this.TAB_PARENT_CLASSNAME,
						'ul' )[0] || _createTabParent.call(this);

		/**
		 * The container of the tabView's content elements.
		 * @property _contentParent
		 * @type HTMLElement
		 * @private
		 */
		this._contentParent =
				this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME,
						'div')[0] ||  _createContentParent.call(this);

		/**
		 * How the Tabs should be oriented relative to the TabView.
		 * @config orientation
		 * @type String
		 * @default "top"
		 */
		this.register('orientation', {
			value: attr.orientation,
			method: function(value) {
				var current = this.get('orientation');
				this.addClass('yui-navset-' + value);

				if (current != value) {
					this.removeClass('yui-navset-' + current);
				}

				switch(value) {
					case 'bottom':
					this.appendChild(this._tabParent);
					break;
				}
			}
		});

		/**
		 * The index of the tab currently active.
		 * @config activeIndex
		 * @type Int
		 */
		this.register('activeIndex', {
			value: attr.activeIndex,
			method: function(value) {
				this.set('activeTab', this.getTab(value));
			},
			validator: function(value) {
				return !this.getTab(value).get('disabled'); // cannot activate if disabled
			}
		});

		/**
		 * The tab currently active.
		 * @config activeTab
		 * @type YAHOO.widget.Tab
		 */
		this.register('activeTab', {
			value: attr.activeTab,
			method: function(tab) {
				var activeTab = this.get('activeTab');

				if (tab) {
					tab.set('active', true);
				}

				if (activeTab && activeTab != tab) {
					activeTab.set('active', false);
				}

				if (activeTab && tab != activeTab) { // no transition if only 1
					this.contentTransition(tab, activeTab);
				} else if (tab) {
					tab.set('contentVisible', true);
				}
			},
			validator: function(value) {
				return !value.get('disabled'); // cannot activate if disabled
			}
		});

		if ( this._tabParent ) {
			_initTabs.call(this);
		}

		for (var type in this.DOM_EVENTS) {
			if ( this.DOM_EVENTS.hasOwnProperty(type) ) {
				this.addListener.call(this, type, this.DOMEventHandler);
			}
		}
	};

	/**
	 * Creates Tab instances from a collection of HTMLElements.
	 * @method createTabs
	 * @private
	 * @param {Array|HTMLCollection} elements The elements to use for Tabs.
	 * @return void
	 */
	var _initTabs = function() {
		var tab,
			attr,
			contentEl;

		var el = this.get('element');
		var tabs = _getChildNodes(this._tabParent);
		var contentElements = _getChildNodes(this._contentParent);

		for (var i = 0, len = tabs.length; i < len; ++i) {
			attr = {};

			if (contentElements[i]) {
				attr.contentEl = contentElements[i];
			}

			tab = new YAHOO.widget.Tab(tabs[i], attr);
			this.addTab(tab);

			if (tab.hasClass(tab.ACTIVE_CLASSNAME) ) {
				this._configs.activeTab.value = tab; // dont invoke method
			}
		}
	};

	var _createTabViewElement = function(attr) {
		var el = document.createElement('div');

		if ( this.CLASSNAME ) {
			el.className = this.CLASSNAME;
		}

		return el;
	};

	var _createTabParent = function(attr) {
		var el = document.createElement('ul');

		if ( this.TAB_PARENT_CLASSNAME ) {
			el.className = this.TAB_PARENT_CLASSNAME;
		}

		this.get('element').appendChild(el);

		return el;
	};

	var _createContentParent = function(attr) {
		var el = document.createElement('div');

		if ( this.CONTENT_PARENT_CLASSNAME ) {
			el.className = this.CONTENT_PARENT_CLASSNAME;
		}

		this.get('element').appendChild(el);

		return el;
	};

	var _getChildNodes = function(el) {
		var nodes = [];
		var childNodes = el.childNodes;

		for (var i = 0, len = childNodes.length; i < len; ++i) {
			if (childNodes[i].nodeType == 1) {
				nodes[nodes.length] = childNodes[i];
			}
		}

		return nodes;
	};

/**
* Fires before the activeTab is changed.
* <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
* <p>If handler returns false, the change will be cancelled, and the value will not
* be set.</p>
* <p><strong>Event fields:</strong><br>
* <code>&lt;String&gt; type</code> beforeActiveTabChange<br>
* <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
* prevValue</code> the currently active tab<br>
* <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
* newValue</code> the tab to be made active</p>
* <p><strong>Usage:</strong><br>
* <code>var handler = function(e) {var previous = e.prevValue};<br>
* myTabs.addListener('beforeActiveTabChange', handler);</code></p>
* @event beforeActiveTabChange
*/

/**
* Fires after the activeTab is changed.
* <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
* <p><strong>Event fields:</strong><br>
* <code>&lt;String&gt; type</code> activeTabChange<br>
* <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
* prevValue</code> the formerly active tab<br>
* <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
* newValue</code> the new active tab</p>
* <p><strong>Usage:</strong><br>
* <code>var handler = function(e) {var previous = e.prevValue};<br>
* myTabs.addListener('activeTabChange', handler);</code></p>
* @event activeTabChange
*/

/**
* Fires before the orientation is changed.
* <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
* <p>If handler returns false, the change will be cancelled, and the value will not
* be set.</p>
* <p><strong>Event fields:</strong><br>
* <code>&lt;String&gt; type</code> beforeOrientationChange<br>
* <code>&lt;String&gt;
* prevValue</code> the current orientation<br>
* <code>&lt;String&gt;
* newValue</code> the new orientation to be applied</p>
* <p><strong>Usage:</strong><br>
* <code>var handler = function(e) {var previous = e.prevValue};<br>
* myTabs.addListener('beforeOrientationChange', handler);</code></p>
* @event beforeOrientationChange
*/

/**
* Fires after the orientation is changed.
* <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
* <p><strong>Event fields:</strong><br>
* <code>&lt;String&gt; type</code> orientationChange<br>
* <code>&lt;String&gt;
* prevValue</code> the former orientation<br>
* <code>&lt;String&gt;
* newValue</code> the new orientation</p>
* <p><strong>Usage:</strong><br>
* <code>var handler = function(e) {var previous = e.prevValue};<br>
* myTabs.addListener('orientationChange', handler);</code></p>
* @event orientationChange
*/
})();
