/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.0
*/
(function () {

	YAHOO.util.Config = function (owner) {

		if (owner) {
			this.init(owner);
		}


	};


	var Lang = YAHOO.lang,
		CustomEvent = YAHOO.util.CustomEvent,
		Config = YAHOO.util.Config;


	Config.CONFIG_CHANGED_EVENT = "configChanged";
	
	Config.BOOLEAN_TYPE = "boolean";
	
	Config.prototype = {
	 
		owner: null,
		queueInProgress: false,
		config: null,
		initialConfig: null,
		eventQueue: null,
		configChangedEvent: null,
		init: function (owner) {
	
			this.owner = owner;
	
			this.configChangedEvent = 
			this.createEvent(Config.CONFIG_CHANGED_EVENT);
	
			this.configChangedEvent.signature = CustomEvent.LIST;
			this.queueInProgress = false;
			this.config = {};
			this.initialConfig = {};
			this.eventQueue = [];
		
		},
		
		checkBoolean: function (val) {
			return (typeof val == Config.BOOLEAN_TYPE);
		},
		
		checkNumber: function (val) {
			return (!isNaN(val));
		},
		
		fireEvent: function ( key, value ) {
			var property = this.config[key];
		
			if (property && property.event) {
				property.event.fire(value);
			} 
		},
		
		addProperty: function ( key, propertyObject ) {
			key = key.toLowerCase();
		
			this.config[key] = propertyObject;
		
			propertyObject.event = this.createEvent(key, { scope: this.owner });
			propertyObject.event.signature = CustomEvent.LIST;
			
			
			propertyObject.key = key;
		
			if (propertyObject.handler) {
				propertyObject.event.subscribe(propertyObject.handler, 
					this.owner);
			}
		
			this.setProperty(key, propertyObject.value, true);
			
			if (! propertyObject.suppressEvent) {
				this.queueProperty(key, propertyObject.value);
			}
			
		},
		
		getConfig: function () {
		
			var cfg = {},
				prop,
				property;
				
			for (prop in this.config) {
				property = this.config[prop];
				if (property && property.event) {
					cfg[prop] = property.value;
				}
			}
			
			return cfg;
		},
		
		getProperty: function (key) {
			var property = this.config[key.toLowerCase()];
			if (property && property.event) {
				return property.value;
			} else {
				return undefined;
			}
		},
		
		resetProperty: function (key) {
	
			key = key.toLowerCase();
		
			var property = this.config[key];
	
			if (property && property.event) {
	
				if (this.initialConfig[key] && 
					!Lang.isUndefined(this.initialConfig[key])) {
	
					this.setProperty(key, this.initialConfig[key]);

					return true;
	
				}
	
			} else {
	
				return false;
			}
	
		},
		
		setProperty: function (key, value, silent) {
		
			var property;
		
			key = key.toLowerCase();
		
			if (this.queueInProgress && ! silent) {
				// Currently running through a queue... 
				this.queueProperty(key,value);
				return true;
	
			} else {
				property = this.config[key];
				if (property && property.event) {
					if (property.validator && !property.validator(value)) {
						return false;
					} else {
						property.value = value;
						if (! silent) {
							this.fireEvent(key, value);
							this.configChangedEvent.fire([key, value]);
						}
						return true;
					}
				} else {
					return false;
				}
			}
		},
		
		queueProperty: function (key, value) {
		
			key = key.toLowerCase();
		
			var property = this.config[key],
				foundDuplicate = false,
				iLen,
				queueItem,
				queueItemKey,
				queueItemValue,
				sLen,
				supercedesCheck,
				qLen,
				queueItemCheck,
				queueItemCheckKey,
				queueItemCheckValue,
				i,
				s,
				q;
								
			if (property && property.event) {
	
				if (!Lang.isUndefined(value) && property.validator && 
					!property.validator(value)) { // validator
					return false;
				} else {
		
					if (!Lang.isUndefined(value)) {
						property.value = value;
					} else {
						value = property.value;
					}
		
					foundDuplicate = false;
					iLen = this.eventQueue.length;
		
					for (i = 0; i < iLen; i++) {
						queueItem = this.eventQueue[i];
		
						if (queueItem) {
							queueItemKey = queueItem[0];
							queueItemValue = queueItem[1];

							if (queueItemKey == key) {
	
								/*
									found a dupe... push to end of queue, null 
									current item, and break
								*/
	
								this.eventQueue[i] = null;
	
								this.eventQueue.push(
									[key, (!Lang.isUndefined(value) ? 
									value : queueItemValue)]);
	
								foundDuplicate = true;
								break;
							}
						}
					}
					
					// this is a refire, or a new property in the queue
	
					if (! foundDuplicate && !Lang.isUndefined(value)) { 
						this.eventQueue.push([key, value]);
					}
				}
		
				if (property.supercedes) {

					sLen = property.supercedes.length;

					for (s = 0; s < sLen; s++) {

						supercedesCheck = property.supercedes[s];
						qLen = this.eventQueue.length;

						for (q = 0; q < qLen; q++) {
							queueItemCheck = this.eventQueue[q];

							if (queueItemCheck) {
								queueItemCheckKey = queueItemCheck[0];
								queueItemCheckValue = queueItemCheck[1];

								if (queueItemCheckKey == 
									supercedesCheck.toLowerCase() ) {

									this.eventQueue.push([queueItemCheckKey, 
										queueItemCheckValue]);

									this.eventQueue[q] = null;
									break;

								}
							}
						}
					}
				}


				return true;
			} else {
				return false;
			}
		},
		
		refireEvent: function (key) {
	
			key = key.toLowerCase();
		
			var property = this.config[key];
	
			if (property && property.event && 
	
				!Lang.isUndefined(property.value)) {
	
				if (this.queueInProgress) {
	
					this.queueProperty(key);
	
				} else {
	
					this.fireEvent(key, property.value);
	
				}
	
			}
		},
		
		applyConfig: function (userConfig, init) {
		
			var sKey,
				oConfig;

			if (init) {
				oConfig = {};
				for (sKey in userConfig) {
					if (Lang.hasOwnProperty(userConfig, sKey)) {
						oConfig[sKey.toLowerCase()] = userConfig[sKey];
					}
				}
				this.initialConfig = oConfig;
			}

			for (sKey in userConfig) {
				if (Lang.hasOwnProperty(userConfig, sKey)) {
					this.queueProperty(sKey, userConfig[sKey]);
				}
			}
		},
		
		refresh: function () {
		
			var prop;
		
			for (prop in this.config) {
				this.refireEvent(prop);
			}
		},
		
		fireQueue: function () {
		
			var i, 
				queueItem,
				key,
				value,
				property;
		
			this.queueInProgress = true;
			for (i = 0;i < this.eventQueue.length; i++) {
				queueItem = this.eventQueue[i];
				if (queueItem) {
		
					key = queueItem[0];
					value = queueItem[1];
					property = this.config[key];
		
					property.value = value;
		
					this.fireEvent(key,value);
				}
			}
			
			this.queueInProgress = false;
			this.eventQueue = [];
		},
		
		subscribeToConfigEvent: function (key, handler, obj, override) {
	
			var property = this.config[key.toLowerCase()];
	
			if (property && property.event) {
				if (!Config.alreadySubscribed(property.event, handler, obj)) {
					property.event.subscribe(handler, obj, override);
				}
				return true;
			} else {
				return false;
			}
	
		},
		
		unsubscribeFromConfigEvent: function (key, handler, obj) {
			var property = this.config[key.toLowerCase()];
			if (property && property.event) {
				return property.event.unsubscribe(handler, obj);
			} else {
				return false;
			}
		},
		
		toString: function () {
			var output = "Config";
			if (this.owner) {
				output += " [" + this.owner.toString() + "]";
			}
			return output;
		},
		
		outputEventQueue: function () {

			var output = "",
				queueItem,
				q,
				nQueue = this.eventQueue.length;
			  
			for (q = 0; q < nQueue; q++) {
				queueItem = this.eventQueue[q];
				if (queueItem) {
					output += queueItem[0] + "=" + queueItem[1] + ", ";
				}
			}
			return output;
		},

		destroy: function () {

			var oConfig = this.config,
				sProperty,
				oProperty;


			for (sProperty in oConfig) {
			
				if (Lang.hasOwnProperty(oConfig, sProperty)) {

					oProperty = oConfig[sProperty];

					oProperty.event.unsubscribeAll();
					oProperty.event = null;

				}
			
			}
			
			this.configChangedEvent.unsubscribeAll();
			
			this.configChangedEvent = null;
			this.owner = null;
			this.config = null;
			this.initialConfig = null;
			this.eventQueue = null;
		
		}

	};
	
	
	
	Config.alreadySubscribed = function (evt, fn, obj) {
	
		var nSubscribers = evt.subscribers.length,
			subsc,
			i;

		if (nSubscribers > 0) {
			i = nSubscribers - 1;
			do {
				subsc = evt.subscribers[i];
				if (subsc && subsc.obj == obj && subsc.fn == fn) {
					return true;
				}
			}
			while (i--);
		}

		return false;

	};

	YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);

}());

(function () {

	YAHOO.widget.Module = function (el, userConfig) {
		if (el) {
			this.init(el, userConfig);
		} else {
		}
	};

	var Dom = YAHOO.util.Dom,
		Config = YAHOO.util.Config,
		Event = YAHOO.util.Event,
		CustomEvent = YAHOO.util.CustomEvent,
		Module = YAHOO.widget.Module,

		m_oModuleTemplate,
		m_oHeaderTemplate,
		m_oBodyTemplate,
		m_oFooterTemplate,

		EVENT_TYPES = {
		
			"BEFORE_INIT": "beforeInit",
			"INIT": "init",
			"APPEND": "append",
			"BEFORE_RENDER": "beforeRender",
			"RENDER": "render",
			"CHANGE_HEADER": "changeHeader",
			"CHANGE_BODY": "changeBody",
			"CHANGE_FOOTER": "changeFooter",
			"CHANGE_CONTENT": "changeContent",
			"DESTORY": "destroy",
			"BEFORE_SHOW": "beforeShow",
			"SHOW": "show",
			"BEFORE_HIDE": "beforeHide",
			"HIDE": "hide"
		
		},
			
		DEFAULT_CONFIG = {
		
			"VISIBLE": { 
				key: "visible", 
				value: true, 
				validator: YAHOO.lang.isBoolean 
			},
		
			"EFFECT": { 
				key: "effect", 
				suppressEvent: true, 
				supercedes: ["visible"] 
			},

			"MONITOR_RESIZE": { 
				key: "monitorresize", 
				value: true  
			},

			"APPEND_TO_DOCUMENT_BODY": { 
				key: "appendtodocumentbody", 
				value: false
			}
		};
	
	Module.IMG_ROOT = null;
	Module.IMG_ROOT_SSL = null;
	Module.CSS_MODULE = "yui-module";
	Module.CSS_HEADER = "hd";
	Module.CSS_BODY = "bd";
	Module.CSS_FOOTER = "ft";
	Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
	Module.textResizeEvent = new CustomEvent("textResize");

	function createModuleTemplate() {

		if (!m_oModuleTemplate) {
			m_oModuleTemplate = document.createElement("div");
			
			m_oModuleTemplate.innerHTML = ("<div class=\"" + 
				Module.CSS_HEADER + "\"></div>" + "<div class=\"" + 
				Module.CSS_BODY + "\"></div><div class=\"" + 
				Module.CSS_FOOTER + "\"></div>");

			m_oHeaderTemplate = m_oModuleTemplate.firstChild;
			m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
			m_oFooterTemplate = m_oBodyTemplate.nextSibling;
		}

		return m_oModuleTemplate;
	}

	function createHeader() {
		if (!m_oHeaderTemplate) {
			createModuleTemplate();
		}
		return (m_oHeaderTemplate.cloneNode(false));
	}

	function createBody() {
		if (!m_oBodyTemplate) {
			createModuleTemplate();
		}
		return (m_oBodyTemplate.cloneNode(false));
	}

	function createFooter() {
		if (!m_oFooterTemplate) {
			createModuleTemplate();
		}
		return (m_oFooterTemplate.cloneNode(false));
	}

	Module.prototype = {

		constructor: Module,
		element: null,
		header: null,
		body: null,

		footer: null,

		id: null,

		imageRoot: Module.IMG_ROOT,

		initEvents: function () {

			var SIGNATURE = CustomEvent.LIST;

			this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
			this.beforeInitEvent.signature = SIGNATURE;

			this.initEvent = this.createEvent(EVENT_TYPES.INIT);
			this.initEvent.signature = SIGNATURE;

			this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
			this.appendEvent.signature = SIGNATURE;

			this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
			this.beforeRenderEvent.signature = SIGNATURE;
		
			this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
			this.renderEvent.signature = SIGNATURE;
		
			this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
			this.changeHeaderEvent.signature = SIGNATURE;
			
			this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
			this.changeBodyEvent.signature = SIGNATURE;
			
			this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
			this.changeFooterEvent.signature = SIGNATURE;
		
			this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
			this.changeContentEvent.signature = SIGNATURE;

			this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
			this.destroyEvent.signature = SIGNATURE;

			this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
			this.beforeShowEvent.signature = SIGNATURE;

			this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
			this.showEvent.signature = SIGNATURE;

			this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
			this.beforeHideEvent.signature = SIGNATURE;

			this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
			this.hideEvent.signature = SIGNATURE;
		}, 

		platform: function () {
			var ua = navigator.userAgent.toLowerCase();

			if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
				return "windows";
			} else if (ua.indexOf("macintosh") != -1) {
				return "mac";
			} else {
				return false;
			}
		}(),
		
		browser: function () {
			var ua = navigator.userAgent.toLowerCase();
			if (ua.indexOf('opera') != -1) { 
				return 'opera';
			} else if (ua.indexOf('msie 7') != -1) {
				return 'ie7';
			} else if (ua.indexOf('msie') != -1) {
				return 'ie';
			} else if (ua.indexOf('safari') != -1) { 
				return 'safari';
			} else if (ua.indexOf('gecko') != -1) {
				return 'gecko';
			} else {
				return false;
			}
		}(),
		
		isSecure: function () {
			if (window.location.href.toLowerCase().indexOf("https") === 0) {
				return true;
			} else {
				return false;
			}
		}(),
		
		initDefaultConfig: function () {
			// Add properties //
			this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
				handler: this.configVisible, 
				value: DEFAULT_CONFIG.VISIBLE.value, 
				validator: DEFAULT_CONFIG.VISIBLE.validator
			});

			this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
				suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent, 
				supercedes: DEFAULT_CONFIG.EFFECT.supercedes
			});

			this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
				handler: this.configMonitorResize,
				value: DEFAULT_CONFIG.MONITOR_RESIZE.value
			});

			this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
				value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
			});
		},

		init: function (el, userConfig) {

			var elId, child;

			this.initEvents();
			this.beforeInitEvent.fire(Module);

			this.cfg = new Config(this);

			if (this.isSecure) {
				this.imageRoot = Module.IMG_ROOT_SSL;
			}

			if (typeof el == "string") {
				elId = el;
				el = document.getElementById(el);
				if (! el) {
					el = (createModuleTemplate()).cloneNode(false);
					el.id = elId;
				}
			}

			this.element = el;

			if (el.id) {
				this.id = el.id;
			}

			child = this.element.firstChild;

			if (child) {
				var fndHd = false, fndBd = false, fndFt = false;
				do {
					// We're looking for elements
					if (1 == child.nodeType) {
						if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
							this.header = child;
							fndHd = true;
						} else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
							this.body = child;
							fndBd = true;
						} else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
							this.footer = child;
							fndFt = true;
						}
					}
				} while ((child = child.nextSibling));
			}

			this.initDefaultConfig();

			Dom.addClass(this.element, Module.CSS_MODULE);

			if (userConfig) {
				this.cfg.applyConfig(userConfig, true);
			}

			if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
				this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
			}

			this.initEvent.fire(Module);
		},

		initResizeMonitor: function () {

			var isGeckoWin = (YAHOO.env.ua.gecko && this.platform == "windows");
			if (isGeckoWin) {
				// Help prevent spinning loading icon which 
				// started with FireFox 2.0.0.8/Win
				var self = this;
				setTimeout(function(){self._initResizeMonitor();}, 0);
			} else {
				this._initResizeMonitor();
			}
		},

		_initResizeMonitor : function() {

			var oDoc, 
				oIFrame, 
				sHTML;

			function fireTextResize() {
				Module.textResizeEvent.fire();
			}

			if (!YAHOO.env.ua.opera) {
				oIFrame = Dom.get("_yuiResizeMonitor");

				var supportsCWResize = this._supportsCWResize();

				if (!oIFrame) {
					oIFrame = document.createElement("iframe");

					if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && YAHOO.env.ua.ie) {
						oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
					}

					if (!supportsCWResize) {
						// Can't monitor on contentWindow, so fire from inside iframe
						sHTML = ["<html><head><script ",
								 "type=\"text/javascript\">",
								 "window.onresize=function(){window.parent.",
								 "YAHOO.widget.Module.textResizeEvent.",
								 "fire();};<",
								 "\/script></head>",
								 "<body></body></html>"].join('');

						oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
					}

					oIFrame.id = "_yuiResizeMonitor";
					oIFrame.style.position = "absolute";
					oIFrame.style.visibility = "hidden";

					var db = document.body,
						fc = db.firstChild;
					if (fc) {
						db.insertBefore(oIFrame, fc);
					} else {
						db.appendChild(oIFrame);
					}

					oIFrame.style.width = "10em";
					oIFrame.style.height = "10em";
					oIFrame.style.top = (-1 * oIFrame.offsetHeight) + "px";
					oIFrame.style.left = (-1 * oIFrame.offsetWidth) + "px";
					oIFrame.style.borderWidth = "0";
					oIFrame.style.visibility = "visible";

					/*
					   Don't open/close the document for Gecko like we used to, since it
					   leads to duplicate cookies. (See SourceForge bug #1721755)
					*/
					if (YAHOO.env.ua.webkit) {
						oDoc = oIFrame.contentWindow.document;
						oDoc.open();
						oDoc.close();
					}
				}

				if (oIFrame && oIFrame.contentWindow) {
					Module.textResizeEvent.subscribe(this.onDomResize, this, true);

					if (!Module.textResizeInitialized) {
						if (supportsCWResize) {
							if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
								/*
									 This will fail in IE if document.domain has 
									 changed, so we must change the listener to 
									 use the oIFrame element instead
								*/
								Event.on(oIFrame, "resize", fireTextResize);
							}
						}
						Module.textResizeInitialized = true;
					}
					this.resizeMonitor = oIFrame;
				}
			}
		},

		_supportsCWResize : function() {
			var bSupported = true;
			if (YAHOO.env.ua.gecko && YAHOO.env.ua.gecko <= 1.8) {
				bSupported = false;
			}
			return bSupported;
		},

		onDomResize: function (e, obj) {

			var nLeft = -1 * this.resizeMonitor.offsetWidth,
				nTop = -1 * this.resizeMonitor.offsetHeight;
		
			this.resizeMonitor.style.top = nTop + "px";
			this.resizeMonitor.style.left =  nLeft + "px";

		},

		setHeader: function (headerContent) {
			var oHeader = this.header || (this.header = createHeader());

			if (headerContent.tagName) {
				oHeader.innerHTML = "";
				oHeader.appendChild(headerContent);
			} else {
				oHeader.innerHTML = headerContent;
			}

			this.changeHeaderEvent.fire(headerContent);
			this.changeContentEvent.fire();

		},

		appendToHeader: function (element) {
			var oHeader = this.header || (this.header = createHeader());
		
			oHeader.appendChild(element);

			this.changeHeaderEvent.fire(element);
			this.changeContentEvent.fire();

		},

		setBody: function (bodyContent) {
			var oBody = this.body || (this.body = createBody());

			if (bodyContent.tagName) {
				oBody.innerHTML = "";
				oBody.appendChild(bodyContent);
			} else {
				oBody.innerHTML = bodyContent;
			}

			this.changeBodyEvent.fire(bodyContent);
			this.changeContentEvent.fire();
		},

		appendToBody: function (element) {
			var oBody = this.body || (this.body = createBody());
		
			oBody.appendChild(element);

			this.changeBodyEvent.fire(element);
			this.changeContentEvent.fire();

		},
		
		setFooter: function (footerContent) {

			var oFooter = this.footer || (this.footer = createFooter());

			if (footerContent.tagName) {
				oFooter.innerHTML = "";
				oFooter.appendChild(footerContent);
			} else {
				oFooter.innerHTML = footerContent;
			}

			this.changeFooterEvent.fire(footerContent);
			this.changeContentEvent.fire();

		},
		
		appendToFooter: function (element) {

			var oFooter = this.footer || (this.footer = createFooter());
		
			oFooter.appendChild(element);

			this.changeFooterEvent.fire(element);
			this.changeContentEvent.fire();

		},
		
		render: function (appendToNode, moduleElement) {

			var me = this,
				firstChild;

			function appendTo(parentNode) {
				if (typeof parentNode == "string") {
					parentNode = document.getElementById(parentNode);
				}

				if (parentNode) {
					me._addToParent(parentNode, me.element);
					me.appendEvent.fire();
				}
			}

			this.beforeRenderEvent.fire();

			if (! moduleElement) {
				moduleElement = this.element;
			}

			if (appendToNode) {
				appendTo(appendToNode);
			} else { 
				// No node was passed in. If the element is not already in the Dom, this fails
				if (! Dom.inDocument(this.element)) {
					return false;
				}
			}

			// Need to get everything into the DOM if it isn't already
			if (this.header && ! Dom.inDocument(this.header)) {
				// There is a header, but it's not in the DOM yet. Need to add it.
				firstChild = moduleElement.firstChild;
				if (firstChild) {
					moduleElement.insertBefore(this.header, firstChild);
				} else {
					moduleElement.appendChild(this.header);
				}
			}

			if (this.body && ! Dom.inDocument(this.body)) {
				// There is a body, but it's not in the DOM yet. Need to add it.		
				if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
					moduleElement.insertBefore(this.body, this.footer);
				} else {
					moduleElement.appendChild(this.body);
				}
			}

			if (this.footer && ! Dom.inDocument(this.footer)) {
				// There is a footer, but it's not in the DOM yet. Need to add it.
				moduleElement.appendChild(this.footer);
			}

			this.renderEvent.fire();
			return true;
		},

		destroy: function () {

			var parent,
				e;

			if (this.element) {
				Event.purgeElement(this.element, true);
				parent = this.element.parentNode;
			}

			if (parent) {
				parent.removeChild(this.element);
			}
		
			this.element = null;
			this.header = null;
			this.body = null;
			this.footer = null;

			Module.textResizeEvent.unsubscribe(this.onDomResize, this);

			this.cfg.destroy();
			this.cfg = null;

			this.destroyEvent.fire();
		
			for (e in this) {
				if (e instanceof CustomEvent) {
					e.unsubscribeAll();
				}
			}

		},
		
		show: function () {
			this.cfg.setProperty("visible", true);
		},
		
		hide: function () {
			this.cfg.setProperty("visible", false);
		},
		
		configVisible: function (type, args, obj) {
			var visible = args[0];
			if (visible) {
				this.beforeShowEvent.fire();
				Dom.setStyle(this.element, "display", "block");
				this.showEvent.fire();
			} else {
				this.beforeHideEvent.fire();
				Dom.setStyle(this.element, "display", "none");
				this.hideEvent.fire();
			}
		},
		
		configMonitorResize: function (type, args, obj) {
			var monitor = args[0];
			if (monitor) {
				this.initResizeMonitor();
			} else {
				Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
				this.resizeMonitor = null;
			}
		},

		_addToParent: function(parentNode, element) {
			if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
				parentNode.insertBefore(element, parentNode.firstChild);
			} else {
				parentNode.appendChild(element);
			}
		},

		/**
		* Returns a String representation of the Object.
		* @method toString
		* @return {String} The string representation of the Module
		*/
		toString: function () {
			return "Module " + this.id;
		}
	};

	YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);

}());

(function () {

	YAHOO.widget.Overlay = function (el, userConfig) {
		YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
	};

	var Lang = YAHOO.lang,
		CustomEvent = YAHOO.util.CustomEvent,
		Module = YAHOO.widget.Module,
		Event = YAHOO.util.Event,
		Dom = YAHOO.util.Dom,
		Config = YAHOO.util.Config,
		Overlay = YAHOO.widget.Overlay,

		m_oIFrameTemplate,

		EVENT_TYPES = {
			"BEFORE_MOVE": "beforeMove",
			"MOVE": "move"
		},

		DEFAULT_CONFIG = {

			"X": { 
				key: "x", 
				validator: Lang.isNumber, 
				suppressEvent: true, 
				supercedes: ["iframe"]
			},

			"Y": { 
				key: "y", 
				validator: Lang.isNumber, 
				suppressEvent: true, 
				supercedes: ["iframe"]
			},

			"XY": { 
				key: "xy", 
				suppressEvent: true, 
				supercedes: ["iframe"] 
			},

			"CONTEXT": { 
				key: "context", 
				suppressEvent: true, 
				supercedes: ["iframe"] 
			},

			"FIXED_CENTER": { 
				key: "fixedcenter", 
				value: false, 
				validator: Lang.isBoolean, 
				supercedes: ["iframe", "visible"] 
			},

			"WIDTH": { 
				key: "width", 
				suppressEvent: true, 
				supercedes: ["context", "fixedcenter", "iframe"] 
			}, 

			"HEIGHT": { 
				key: "height", 
				suppressEvent: true, 
				supercedes: ["context", "fixedcenter", "iframe"] 
			},

			"ZINDEX": { 
				key: "zindex", 
				value: null 
			},

			"CONSTRAIN_TO_VIEWPORT": { 
				key: "constraintoviewport", 
				value: false, 
				validator: Lang.isBoolean, 
				supercedes: ["iframe", "x", "y", "xy"]
			}, 

			"IFRAME": { 
				key: "iframe", 
				value: (YAHOO.env.ua.ie == 6 ? true : false), 
				validator: Lang.isBoolean, 
				supercedes: ["zindex"] 
			}
		};

	Overlay.IFRAME_SRC = "javascript:false;";

	Overlay.IFRAME_OFFSET = 3;

	Overlay.VIEWPORT_OFFSET = 10;

	Overlay.TOP_LEFT = "tl";

	Overlay.TOP_RIGHT = "tr";

	Overlay.BOTTOM_LEFT = "bl";

	Overlay.BOTTOM_RIGHT = "br";

	Overlay.CSS_OVERLAY = "yui-overlay";

	Overlay.windowScrollEvent = new CustomEvent("windowScroll");

	Overlay.windowResizeEvent = new CustomEvent("windowResize");

	Overlay.windowScrollHandler = function (e) {

		if (YAHOO.env.ua.ie) {

			if (! window.scrollEnd) {
				window.scrollEnd = -1;
			}

			clearTimeout(window.scrollEnd);
	
			window.scrollEnd = setTimeout(function () { 
				Overlay.windowScrollEvent.fire(); 
			}, 1);
	
		} else {
			Overlay.windowScrollEvent.fire();
		}
	};

	Overlay.windowResizeHandler = function (e) {

		if (YAHOO.env.ua.ie) {
			if (! window.resizeEnd) {
				window.resizeEnd = -1;
			}

			clearTimeout(window.resizeEnd);

			window.resizeEnd = setTimeout(function () {
				Overlay.windowResizeEvent.fire(); 
			}, 100);
		} else {
			Overlay.windowResizeEvent.fire();
		}
	};

	Overlay._initialized = null;

	if (Overlay._initialized === null) {
		Event.on(window, "scroll", Overlay.windowScrollHandler);
		Event.on(window, "resize", Overlay.windowResizeHandler);
	
		Overlay._initialized = true;
	}

	YAHOO.extend(Overlay, Module, {

		init: function (el, userConfig) {
	
	
			Overlay.superclass.init.call(this, el/*, userConfig*/);  

			this.beforeInitEvent.fire(Overlay);
			
			Dom.addClass(this.element, Overlay.CSS_OVERLAY);
			
			if (userConfig) {
				this.cfg.applyConfig(userConfig, true);
			}

			if (this.platform == "mac" && YAHOO.env.ua.gecko) {

				if (! Config.alreadySubscribed(this.showEvent,
					this.showMacGeckoScrollbars, this)) {

					this.showEvent.subscribe(this.showMacGeckoScrollbars, 
						this, true);

				}

				if (! Config.alreadySubscribed(this.hideEvent, 
					this.hideMacGeckoScrollbars, this)) {

					this.hideEvent.subscribe(this.hideMacGeckoScrollbars, 
						this, true);

				}
			}

			this.initEvent.fire(Overlay);
		},
		
		initEvents: function () {
	
			Overlay.superclass.initEvents.call(this);
			
			var SIGNATURE = CustomEvent.LIST;
			
			this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
			this.beforeMoveEvent.signature = SIGNATURE;
			
			this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
			this.moveEvent.signature = SIGNATURE;
		
		},
		
		initDefaultConfig: function () {
	
			Overlay.superclass.initDefaultConfig.call(this);
			
			
			// Add overlay config properties //
			
			this.cfg.addProperty(DEFAULT_CONFIG.X.key, { 
	
				handler: this.configX, 
				validator: DEFAULT_CONFIG.X.validator, 
				suppressEvent: DEFAULT_CONFIG.X.suppressEvent, 
				supercedes: DEFAULT_CONFIG.X.supercedes
	
			});

			this.cfg.addProperty(DEFAULT_CONFIG.Y.key, {

				handler: this.configY, 
				validator: DEFAULT_CONFIG.Y.validator, 
				suppressEvent: DEFAULT_CONFIG.Y.suppressEvent, 
				supercedes: DEFAULT_CONFIG.Y.supercedes

			});
	
			this.cfg.addProperty(DEFAULT_CONFIG.XY.key, {
			
				handler: this.configXY, 
				suppressEvent: DEFAULT_CONFIG.XY.suppressEvent, 
				supercedes: DEFAULT_CONFIG.XY.supercedes
			
			});
	
			this.cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
			
				handler: this.configContext, 
				suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent, 
				supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
			
			});

			this.cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
			
				handler: this.configFixedCenter,
				value: DEFAULT_CONFIG.FIXED_CENTER.value, 
				validator: DEFAULT_CONFIG.FIXED_CENTER.validator, 
				supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
			
			});
	
			this.cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {

				handler: this.configWidth, 
				suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent, 
				supercedes: DEFAULT_CONFIG.WIDTH.supercedes

			});

			this.cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {

				handler: this.configHeight, 
				suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent, 
				supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
			
			});
			
			this.cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {

				handler: this.configzIndex,
				value: DEFAULT_CONFIG.ZINDEX.value

			});

			this.cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {

				handler: this.configConstrainToViewport, 
				value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, 
				validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, 
				supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes

			});

			this.cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {

				handler: this.configIframe, 
				value: DEFAULT_CONFIG.IFRAME.value, 
				validator: DEFAULT_CONFIG.IFRAME.validator, 
				supercedes: DEFAULT_CONFIG.IFRAME.supercedes

			});
		},

		moveTo: function (x, y) {
			this.cfg.setProperty("xy", [x, y]);
		},

		hideMacGeckoScrollbars: function () {
	
			Dom.removeClass(this.element, "show-scrollbars");
			Dom.addClass(this.element, "hide-scrollbars");
	
		},

		showMacGeckoScrollbars: function () {
	
			Dom.removeClass(this.element, "hide-scrollbars");
			Dom.addClass(this.element, "show-scrollbars");
	
		},

		// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
		configVisible: function (type, args, obj) {

			var visible = args[0],
				currentVis = Dom.getStyle(this.element, "visibility"),
				effect = this.cfg.getProperty("effect"),
				effectInstances = [],
				isMacGecko = (this.platform == "mac" && YAHOO.env.ua.gecko),
				alreadySubscribed = Config.alreadySubscribed,
				eff, ei, e, i, j, k, h,
				nEffects,
				nEffectInstances;

			if (currentVis == "inherit") {
				e = this.element.parentNode;

				while (e.nodeType != 9 && e.nodeType != 11) {
					currentVis = Dom.getStyle(e, "visibility");

					if (currentVis != "inherit") { 
						break; 
					}

					e = e.parentNode;
				}

				if (currentVis == "inherit") {
					currentVis = "visible";
				}
			}

			if (effect) {
				if (effect instanceof Array) {
					nEffects = effect.length;

					for (i = 0; i < nEffects; i++) {
						eff = effect[i];
						effectInstances[effectInstances.length] = 
							eff.effect(this, eff.duration);

					}
				} else {
					effectInstances[effectInstances.length] = 
						effect.effect(this, effect.duration);
				}
			}


			if (visible) { // Show
				if (isMacGecko) {
					this.showMacGeckoScrollbars();
				}

				if (effect) { // Animate in
					if (visible) { // Animate in if not showing
						if (currentVis != "visible" || currentVis === "") {
							this.beforeShowEvent.fire();
							nEffectInstances = effectInstances.length;

							for (j = 0; j < nEffectInstances; j++) {
								ei = effectInstances[j];
								if (j === 0 && !alreadySubscribed(
										ei.animateInCompleteEvent, 
										this.showEvent.fire, this.showEvent)) {

									/*
										 Delegate showEvent until end 
										 of animateInComplete
									*/

									ei.animateInCompleteEvent.subscribe(
									 this.showEvent.fire, this.showEvent, true);
								}
								ei.animateIn();
							}
						}
					}
				} else { // Show
					if (currentVis != "visible" || currentVis === "") {
						this.beforeShowEvent.fire();

						Dom.setStyle(this.element, "visibility", "visible");

						this.cfg.refireEvent("iframe");
						this.showEvent.fire();
					}
				}
			} else { // Hide

				if (isMacGecko) {
					this.hideMacGeckoScrollbars();
				}
					
				if (effect) { // Animate out if showing
					if (currentVis == "visible") {
						this.beforeHideEvent.fire();

						nEffectInstances = effectInstances.length;
						for (k = 0; k < nEffectInstances; k++) {
							h = effectInstances[k];
	
							if (k === 0 && !alreadySubscribed(
								h.animateOutCompleteEvent, this.hideEvent.fire, 
								this.hideEvent)) {
	
								/*
									 Delegate hideEvent until end 
									 of animateOutComplete
								*/
	
								h.animateOutCompleteEvent.subscribe(
									this.hideEvent.fire, this.hideEvent, true);
	
							}
							h.animateOut();
						}

					} else if (currentVis === "") {
						Dom.setStyle(this.element, "visibility", "hidden");
					}

				} else { // Simple hide

					if (currentVis == "visible" || currentVis === "") {
						this.beforeHideEvent.fire();
						Dom.setStyle(this.element, "visibility", "hidden");
						this.hideEvent.fire();
					}
				}
			}
		},

		doCenterOnDOMEvent: function () {
			if (this.cfg.getProperty("visible")) {
				this.center();
			}
		},

		configFixedCenter: function (type, args, obj) {

			var val = args[0],
				alreadySubscribed = Config.alreadySubscribed,
				windowResizeEvent = Overlay.windowResizeEvent,
				windowScrollEvent = Overlay.windowScrollEvent;

			if (val) {
				this.center();

				if (!alreadySubscribed(this.beforeShowEvent, this.center, this)) {
					this.beforeShowEvent.subscribe(this.center);
				}

				if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
					windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
				}

				if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
					windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
				}

			} else {
				this.beforeShowEvent.unsubscribe(this.center);

				windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
				windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
			}
		},
		
		configHeight: function (type, args, obj) {

			var height = args[0],
				el = this.element;

			Dom.setStyle(el, "height", height);
			this.cfg.refireEvent("iframe");
		},

		configWidth: function (type, args, obj) {

			var width = args[0],
				el = this.element;
	
			Dom.setStyle(el, "width", width);
			this.cfg.refireEvent("iframe");
		},
		
		configzIndex: function (type, args, obj) {

			var zIndex = args[0],
				el = this.element;

			if (! zIndex) {
				zIndex = Dom.getStyle(el, "zIndex");
				if (! zIndex || isNaN(zIndex)) {
					zIndex = 0;
				}
			}

			if (this.iframe || this.cfg.getProperty("iframe") === true) {
				if (zIndex <= 0) {
					zIndex = 1;
				}
			}

			Dom.setStyle(el, "zIndex", zIndex);
			this.cfg.setProperty("zIndex", zIndex, true);

			if (this.iframe) {
				this.stackIframe();
			}
		},

		configXY: function (type, args, obj) {

			var pos = args[0],
				x = pos[0],
				y = pos[1];

			this.cfg.setProperty("x", x);
			this.cfg.setProperty("y", y);

			this.beforeMoveEvent.fire([x, y]);

			x = this.cfg.getProperty("x");
			y = this.cfg.getProperty("y");


			this.cfg.refireEvent("iframe");
			this.moveEvent.fire([x, y]);
		},

		configX: function (type, args, obj) {

			var x = args[0],
				y = this.cfg.getProperty("y");

			this.cfg.setProperty("x", x, true);
			this.cfg.setProperty("y", y, true);

			this.beforeMoveEvent.fire([x, y]);

			x = this.cfg.getProperty("x");
			y = this.cfg.getProperty("y");
			
			Dom.setX(this.element, x, true);

			this.cfg.setProperty("xy", [x, y], true);

			this.cfg.refireEvent("iframe");
			this.moveEvent.fire([x, y]);
		},

		configY: function (type, args, obj) {

			var x = this.cfg.getProperty("x"),
				y = args[0];

			this.cfg.setProperty("x", x, true);
			this.cfg.setProperty("y", y, true);

			this.beforeMoveEvent.fire([x, y]);

			x = this.cfg.getProperty("x");
			y = this.cfg.getProperty("y");

			Dom.setY(this.element, y, true);

			this.cfg.setProperty("xy", [x, y], true);

			this.cfg.refireEvent("iframe");
			this.moveEvent.fire([x, y]);
		},
		
		showIframe: function () {

			var oIFrame = this.iframe,
				oParentNode;

			if (oIFrame) {
				oParentNode = this.element.parentNode;

				if (oParentNode != oIFrame.parentNode) {
					this._addToParent(oParentNode, oIFrame);
				}
				oIFrame.style.display = "block";
			}
		},

		hideIframe: function () {
			if (this.iframe) {
				this.iframe.style.display = "none";
			}
		},

		syncIframe: function () {

			var oIFrame = this.iframe,
				oElement = this.element,
				nOffset = Overlay.IFRAME_OFFSET,
				nDimensionOffset = (nOffset * 2),
				aXY;

			if (oIFrame) {
				// Size <iframe>
				oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
				oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");

				// Position <iframe>
				aXY = this.cfg.getProperty("xy");

				if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
					this.syncPosition();
					aXY = this.cfg.getProperty("xy");
				}
				Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
			}
		},

		stackIframe: function () {
			if (this.iframe) {
				var overlayZ = Dom.getStyle(this.element, "zIndex");
				if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
					Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
				}
			}
		},

		configIframe: function (type, args, obj) {

			var bIFrame = args[0];

			function createIFrame() {

				var oIFrame = this.iframe,
					oElement = this.element,
					oParent;

				if (!oIFrame) {
					if (!m_oIFrameTemplate) {
						m_oIFrameTemplate = document.createElement("iframe");

						if (this.isSecure) {
							m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
						}



						if (YAHOO.env.ua.ie) {
							m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
							m_oIFrameTemplate.frameBorder = 0;
						}
						else {
							m_oIFrameTemplate.style.opacity = "0";
						}

						m_oIFrameTemplate.style.position = "absolute";
						m_oIFrameTemplate.style.border = "none";
						m_oIFrameTemplate.style.margin = "0";
						m_oIFrameTemplate.style.padding = "0";
						m_oIFrameTemplate.style.display = "none";
					}

					oIFrame = m_oIFrameTemplate.cloneNode(false);
					oParent = oElement.parentNode;

					var parentNode = oParent || document.body;

					this._addToParent(parentNode, oIFrame);
					this.iframe = oIFrame;
				}

				this.showIframe();

				this.syncIframe();
				this.stackIframe();

				// Add event listeners to update the <iframe> when necessary
				if (!this._hasIframeEventListeners) {
					this.showEvent.subscribe(this.showIframe);
					this.hideEvent.subscribe(this.hideIframe);
					this.changeContentEvent.subscribe(this.syncIframe);

					this._hasIframeEventListeners = true;
				}
			}

			function onBeforeShow() {
				createIFrame.call(this);
				this.beforeShowEvent.unsubscribe(onBeforeShow);
				this._iframeDeferred = false;
			}

			if (bIFrame) { // <iframe> shim is enabled

				if (this.cfg.getProperty("visible")) {
					createIFrame.call(this);
				} else {
					if (!this._iframeDeferred) {
						this.beforeShowEvent.subscribe(onBeforeShow);
						this._iframeDeferred = true;
					}
				}

			} else {	// <iframe> shim is disabled
				this.hideIframe();

				if (this._hasIframeEventListeners) {
					this.showEvent.unsubscribe(this.showIframe);
					this.hideEvent.unsubscribe(this.hideIframe);
					this.changeContentEvent.unsubscribe(this.syncIframe);

					this._hasIframeEventListeners = false;
				}
			}
		},

		_primeXYFromDOM : function() {
			if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
				// Set CFG XY based on DOM XY
				this.syncPosition();
				// Account for XY being set silently in syncPosition (no moveTo fired/called)
				this.cfg.refireEvent("xy");
				this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
			}
		},

		configConstrainToViewport: function (type, args, obj) {
			var val = args[0];

			if (val) {
				if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
					this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
				}
				if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
					this.beforeShowEvent.subscribe(this._primeXYFromDOM);
				}
			} else {
				this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
				this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
			}
		},

		configContext: function (type, args, obj) {
	
			var contextArgs = args[0],
				contextEl,
				elementMagnetCorner,
				contextMagnetCorner;

			if (contextArgs) {
				contextEl = contextArgs[0];
				elementMagnetCorner = contextArgs[1];
				contextMagnetCorner = contextArgs[2];
				
				if (contextEl) {
					if (typeof contextEl == "string") {
						this.cfg.setProperty("context", 
							[document.getElementById(contextEl), 
								elementMagnetCorner, contextMagnetCorner], 
								true);
					}
					
					if (elementMagnetCorner && contextMagnetCorner) {
						this.align(elementMagnetCorner, contextMagnetCorner);
					}
				}
			}
		},

		// END BUILT-IN PROPERTY EVENT HANDLERS //
		align: function (elementAlign, contextAlign) {

			var contextArgs = this.cfg.getProperty("context"),
				me = this,
				context,
				element,
				contextRegion;

			function doAlign(v, h) {
	
				switch (elementAlign) {
	
				case Overlay.TOP_LEFT:
					me.moveTo(h, v);
					break;
	
				case Overlay.TOP_RIGHT:
					me.moveTo((h - element.offsetWidth), v);
					break;
	
				case Overlay.BOTTOM_LEFT:
					me.moveTo(h, (v - element.offsetHeight));
					break;
	
				case Overlay.BOTTOM_RIGHT:
					me.moveTo((h - element.offsetWidth), 
						(v - element.offsetHeight));
					break;
				}
			}
	
	
			if (contextArgs) {
			
				context = contextArgs[0];
				element = this.element;
				me = this;
				
				if (! elementAlign) {
					elementAlign = contextArgs[1];
				}
				
				if (! contextAlign) {
					contextAlign = contextArgs[2];
				}
				
				if (element && context) {
					contextRegion = Dom.getRegion(context);

					switch (contextAlign) {
	
					case Overlay.TOP_LEFT:
						doAlign(contextRegion.top, contextRegion.left);
						break;
	
					case Overlay.TOP_RIGHT:
						doAlign(contextRegion.top, contextRegion.right);
						break;
	
					case Overlay.BOTTOM_LEFT:
						doAlign(contextRegion.bottom, contextRegion.left);
						break;
	
					case Overlay.BOTTOM_RIGHT:
						doAlign(contextRegion.bottom, contextRegion.right);
						break;
					}
	
				}
	
			}
			
		},

		enforceConstraints: function (type, args, obj) {
			var pos = args[0];
			var cXY = this.getConstrainedXY(pos[0], pos[1]);
			this.cfg.setProperty("x", cXY[0], true);
			this.cfg.setProperty("y", cXY[1], true);
			this.cfg.setProperty("xy", cXY, true);
		},

		getConstrainedXY: function(x, y) {

			var nViewportOffset = Overlay.VIEWPORT_OFFSET,
				viewPortWidth = Dom.getViewportWidth(),
				viewPortHeight = Dom.getViewportHeight(),
				offsetHeight = this.element.offsetHeight,
				offsetWidth = this.element.offsetWidth,
				scrollX = Dom.getDocumentScrollLeft(),
				scrollY = Dom.getDocumentScrollTop();

			var xNew = x;
			var yNew = y;

			if (offsetWidth + nViewportOffset < viewPortWidth) {

				var leftConstraint = scrollX + nViewportOffset;
				var rightConstraint = scrollX + viewPortWidth - offsetWidth - nViewportOffset;

				if (x < leftConstraint) {
					xNew = leftConstraint;
				} else if (x > rightConstraint) {
					xNew = rightConstraint;
				}
			} else {
				xNew = nViewportOffset + scrollX;
			}

			if (offsetHeight + nViewportOffset < viewPortHeight) {

				var topConstraint = scrollY + nViewportOffset;
				var bottomConstraint = scrollY + viewPortHeight - offsetHeight - nViewportOffset;

				if (y < topConstraint) {
					yNew  = topConstraint;
				} else if (y  > bottomConstraint) {
					yNew  = bottomConstraint;
				}
			} else {
				yNew = nViewportOffset + scrollY;
			}

			return [xNew, yNew];
		},

		center: function () {

			var nViewportOffset = Overlay.VIEWPORT_OFFSET,
				elementWidth = this.element.offsetWidth,
				elementHeight = this.element.offsetHeight,
				viewPortWidth = Dom.getViewportWidth(),
				viewPortHeight = Dom.getViewportHeight(),
				x,
				y;

			if (elementWidth < viewPortWidth) {
				x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
			} else {
				x = nViewportOffset + Dom.getDocumentScrollLeft();
			}

			if (elementHeight < viewPortHeight) {
				y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
			} else {
				y = nViewportOffset + Dom.getDocumentScrollTop();
			}

			this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
			this.cfg.refireEvent("iframe");
		},

		syncPosition: function () {

			var pos = Dom.getXY(this.element);

			this.cfg.setProperty("x", pos[0], true);
			this.cfg.setProperty("y", pos[1], true);
			this.cfg.setProperty("xy", pos, true);

		},

		onDomResize: function (e, obj) {

			var me = this;

			Overlay.superclass.onDomResize.call(this, e, obj);

			setTimeout(function () {
				me.syncPosition();
				me.cfg.refireEvent("iframe");
				me.cfg.refireEvent("context");
			}, 0);
	
		},

		bringToTop: function () {

			var aOverlays = [],
				oElement = this.element;

			function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {

				var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
					sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),

					nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
					nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);

				if (nZIndex1 > nZIndex2) {
					return -1;
				} else if (nZIndex1 < nZIndex2) {
					return 1;
				} else {
					return 0;
				}
			}

			function isOverlayElement(p_oElement) {

				var oOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
					Panel = YAHOO.widget.Panel;

				if (oOverlay && !Dom.isAncestor(oElement, oOverlay)) {
					if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
						aOverlays[aOverlays.length] = p_oElement.parentNode;
					} else {
						aOverlays[aOverlays.length] = p_oElement;
					}
				}
			}

			Dom.getElementsBy(isOverlayElement, "DIV", document.body);

			aOverlays.sort(compareZIndexDesc);

			var oTopOverlay = aOverlays[0],
				nTopZIndex;

			if (oTopOverlay) {
				nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");

				if (!isNaN(nTopZIndex)) {
					var bRequiresBump = false;

					if (oTopOverlay != oElement) {
						bRequiresBump = true;
					} else if (aOverlays.length > 1) {
						var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
						// Don't rely on DOM order to stack if 2 overlays are at the same zindex.
						if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
							bRequiresBump = true;
						}
					}
					if (bRequiresBump) {
						this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
					}
				}
			}
		},

		destroy: function () {

			if (this.iframe) {
				this.iframe.parentNode.removeChild(this.iframe);
			}

			this.iframe = null;
		
			Overlay.windowResizeEvent.unsubscribe(
				this.doCenterOnDOMEvent, this);
	
			Overlay.windowScrollEvent.unsubscribe(
				this.doCenterOnDOMEvent, this);
		
			Overlay.superclass.destroy.call(this);
		},
		
		toString: function () {
			return "Overlay " + this.id;
		}

	});
}());

(function () {
	
	YAHOO.widget.OverlayManager = function (userConfig) {
		this.init(userConfig);
	};

	var Overlay = YAHOO.widget.Overlay,
		Event = YAHOO.util.Event,
		Dom = YAHOO.util.Dom,
		Config = YAHOO.util.Config,
		CustomEvent = YAHOO.util.CustomEvent,
		OverlayManager = YAHOO.widget.OverlayManager;
	
	OverlayManager.CSS_FOCUSED = "focused";
	
	OverlayManager.prototype = {
	
		constructor: OverlayManager,
		
		overlays: null,
		
		initDefaultConfig: function () {
		
			this.cfg.addProperty("overlays", { suppressEvent: true } );
		
			this.cfg.addProperty("focusevent", { value: "mousedown" } );

		},

		init: function (userConfig) {

			this.cfg = new Config(this);

			this.initDefaultConfig();

			if (userConfig) {
				this.cfg.applyConfig(userConfig, true);
			}
			this.cfg.fireQueue();

			var activeOverlay = null;

			this.getActive = function () {
				return activeOverlay;
			};

			this.focus = function (overlay) {
				var o = this.find(overlay);
				if (o) {
					if (activeOverlay != o) {
						if (activeOverlay) {
							activeOverlay.blur();
						}
						this.bringToTop(o);

						activeOverlay = o;

						Dom.addClass(activeOverlay.element, 
							OverlayManager.CSS_FOCUSED);

						o.focusEvent.fire();
					}
				}
			};
		
			this.remove = function (overlay) {
				var o = this.find(overlay), 
						originalZ;
				if (o) {
					if (activeOverlay == o) {
						activeOverlay = null;
					}

					var bDestroyed = (o.element === null && o.cfg === null) ? true : false;

					if (!bDestroyed) {
						// Set it's zindex so that it's sorted to the end.
						originalZ = Dom.getStyle(o.element, "zIndex");
						o.cfg.setProperty("zIndex", -1000, true);
					}

					this.overlays.sort(this.compareZIndexDesc);
					this.overlays = this.overlays.slice(0, (this.overlays.length - 1));

					o.hideEvent.unsubscribe(o.blur);
					o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);

					if (!bDestroyed) {
						Event.removeListener(o.element, 
									this.cfg.getProperty("focusevent"), 
									this._onOverlayElementFocus);

						o.cfg.setProperty("zIndex", originalZ, true);
						o.cfg.setProperty("manager", null);
					}

					o.focusEvent.unsubscribeAll();
					o.blurEvent.unsubscribeAll();

					o.focusEvent = null;
					o.blurEvent = null;

					o.focus = null;
					o.blur = null;
				}
			};

			this.blurAll = function () {
	
				var nOverlays = this.overlays.length,
					i;

				if (nOverlays > 0) {
					i = nOverlays - 1;

					do {
						this.overlays[i].blur();
					}
					while(i--);
				}
			};
		
			this._onOverlayBlur = function (p_sType, p_aArgs) {
				activeOverlay = null;
			};
		
			var overlays = this.cfg.getProperty("overlays");
		
			if (! this.overlays) {
				this.overlays = [];
			}
		
			if (overlays) {
				this.register(overlays);
				this.overlays.sort(this.compareZIndexDesc);
			}
		},
		
		
		_onOverlayElementFocus: function (p_oEvent) {
		
			var oTarget = Event.getTarget(p_oEvent),
				oClose = this.close;
			
			if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
				this.blur();
			} else {
				this.focus();
			}
		},
		
		
		_onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
			this.remove(p_oOverlay);
		},
		
		register: function (overlay) {
		
			var mgr = this,
				zIndex,
				regcount,
				i,
				nOverlays;
		
			if (overlay instanceof Overlay) {

				overlay.cfg.addProperty("manager", { value: this } );

				overlay.focusEvent = overlay.createEvent("focus");
				overlay.focusEvent.signature = CustomEvent.LIST;

				overlay.blurEvent = overlay.createEvent("blur");
				overlay.blurEvent.signature = CustomEvent.LIST;
		
				overlay.focus = function () {
					mgr.focus(this);
				};
		
				overlay.blur = function () {
					if (mgr.getActive() == this) {
						Dom.removeClass(this.element, OverlayManager.CSS_FOCUSED);
						this.blurEvent.fire();
					}
				};
		
				overlay.blurEvent.subscribe(mgr._onOverlayBlur);
				overlay.hideEvent.subscribe(overlay.blur);
				
				overlay.destroyEvent.subscribe(this._onOverlayDestroy, overlay, this);
		
				Event.on(overlay.element, this.cfg.getProperty("focusevent"), 
							this._onOverlayElementFocus, null, overlay);
		
				zIndex = Dom.getStyle(overlay.element, "zIndex");

				if (!isNaN(zIndex)) {
					overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
				} else {
					overlay.cfg.setProperty("zIndex", 0);
				}

				this.overlays.push(overlay);
				this.bringToTop(overlay);

				return true;

			} else if (overlay instanceof Array) {

				regcount = 0;
				nOverlays = overlay.length;

				for (i = 0; i < nOverlays; i++) {
					if (this.register(overlay[i])) {
						regcount++;
					}
				}

				if (regcount > 0) {
					return true;
				}
			} else {
				return false;
			}
		},

		bringToTop: function (p_oOverlay) {

			var oOverlay = this.find(p_oOverlay),
				nTopZIndex,
				oTopOverlay,
				aOverlays;

			if (oOverlay) {

				aOverlays = this.overlays;
				aOverlays.sort(this.compareZIndexDesc);

				oTopOverlay = aOverlays[0];

				if (oTopOverlay) {
					nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");

					if (!isNaN(nTopZIndex)) {

						var bRequiresBump = false;

						if (oTopOverlay !== oOverlay) {
							bRequiresBump = true;
						} else if (aOverlays.length > 1) {
							var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
							// Don't rely on DOM order to stack if 2 overlays are at the same zindex.
							if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
								bRequiresBump = true;
							}
						}

						if (bRequiresBump) {
							oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
						}
					}
					aOverlays.sort(this.compareZIndexDesc);
				}
			}
		},

		find: function (overlay) {

			var aOverlays = this.overlays,
				nOverlays = aOverlays.length,
				i;

			if (nOverlays > 0) {
				i = nOverlays - 1;

				if (overlay instanceof Overlay) {
					do {
						if (aOverlays[i] == overlay) {
							return aOverlays[i];
						}
					}
					while(i--);

				} else if (typeof overlay == "string") {
					do {
						if (aOverlays[i].id == overlay) {
							return aOverlays[i];
						}
					}
					while(i--);
				}
				return null;
			}
		},
		
		compareZIndexDesc: function (o1, o2) {

			var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
				zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.

			if (zIndex1 === null && zIndex2 === null) {
				return 0;
			} else if (zIndex1 === null){
				return 1;
			} else if (zIndex2 === null) {
				return -1;
			} else if (zIndex1 > zIndex2) {
				return -1;
			} else if (zIndex1 < zIndex2) {
				return 1;
			} else {
				return 0;
			}
		},
		
		showAll: function () {
		
			var aOverlays = this.overlays,
				nOverlays = aOverlays.length,
				i;

			if (nOverlays > 0) {
				i = nOverlays - 1;
				do {
					aOverlays[i].show();
				}
				while(i--);
			}
		},

		hideAll: function () {
		
			var aOverlays = this.overlays,
				nOverlays = aOverlays.length,
				i;

			if (nOverlays > 0) {
				i = nOverlays - 1;
				do {
					aOverlays[i].hide();
				}
				while(i--);
			}
		},

		toString: function () {
			return "OverlayManager";
		}
	};

}());

(function () {

	YAHOO.widget.ContainerEffect = 
	
		function (overlay, attrIn, attrOut, targetElement, animClass) {
	
		if (!animClass) {
			animClass = YAHOO.util.Anim;
		}
		
		this.overlay = overlay;
	
		this.attrIn = attrIn;
	
		this.attrOut = attrOut;
	
		this.targetElement = targetElement || overlay.element;
	
		this.animClass = animClass;
	
	};


	var Dom = YAHOO.util.Dom,
		CustomEvent = YAHOO.util.CustomEvent,
		Easing = YAHOO.util.Easing,
		ContainerEffect = YAHOO.widget.ContainerEffect;


	ContainerEffect.FADE = function (overlay, dur) {

		var fin = {
			attributes: {opacity:{from:0, to:1}},
			duration: dur,
			method: Easing.easeIn
		};

		var fout = {
			attributes: {opacity:{to:0}},
			duration: dur,
			method: Easing.easeOut
		};

		var fade = new ContainerEffect(overlay, fin, fout, overlay.element);

		fade.handleUnderlayStart = function() {
			var underlay = this.overlay.underlay;
			if (underlay && YAHOO.env.ua.ie) {
				var hasFilters = (underlay.filters && underlay.filters.length > 0);
				if(hasFilters) {
					Dom.addClass(overlay.element, "yui-effect-fade");
				}
			}
		};

		fade.handleUnderlayComplete = function() {
			var underlay = this.overlay.underlay;
			if (underlay && YAHOO.env.ua.ie) {
				Dom.removeClass(overlay.element, "yui-effect-fade");
			}
		};

		fade.handleStartAnimateIn = function (type,args,obj) {
			Dom.addClass(obj.overlay.element, "hide-select");

			if (!obj.overlay.underlay) {
				obj.overlay.cfg.refireEvent("underlay");
			}

			obj.handleUnderlayStart();

			Dom.setStyle(obj.overlay.element, "visibility", "visible");
			Dom.setStyle(obj.overlay.element, "opacity", 0);
		};

		fade.handleCompleteAnimateIn = function (type,args,obj) {
			Dom.removeClass(obj.overlay.element, "hide-select");

			if (obj.overlay.element.style.filter) {
				obj.overlay.element.style.filter = null;
			}

			obj.handleUnderlayComplete();

			obj.overlay.cfg.refireEvent("iframe");
			obj.animateInCompleteEvent.fire();
		};

		fade.handleStartAnimateOut = function (type, args, obj) {
			Dom.addClass(obj.overlay.element, "hide-select");
			obj.handleUnderlayStart();
		};

		fade.handleCompleteAnimateOut =  function (type, args, obj) {
			Dom.removeClass(obj.overlay.element, "hide-select");
			if (obj.overlay.element.style.filter) {
				obj.overlay.element.style.filter = null;
			}
			Dom.setStyle(obj.overlay.element, "visibility", "hidden");
			Dom.setStyle(obj.overlay.element, "opacity", 1);

			obj.handleUnderlayComplete();

			obj.overlay.cfg.refireEvent("iframe");
			obj.animateOutCompleteEvent.fire();
		};

		fade.init();
		return fade;
	};
	
	
	ContainerEffect.SLIDE = function (overlay, dur) {
	
		var x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
	
			y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
	
			clientWidth = Dom.getClientWidth(),
	
			offsetWidth = overlay.element.offsetWidth,
	
			slide = new ContainerEffect(overlay, 
			
			{ attributes: { points: { to: [x, y] } },
				duration: dur,
				method: Easing.easeIn },
	
			{ attributes: { points: { to: [(clientWidth + 25), y] } },
				duration: dur,
				method: Easing.easeOut },
	
			overlay.element, YAHOO.util.Motion);
		
		
		slide.handleStartAnimateIn = function (type,args,obj) {
			obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
			obj.overlay.element.style.top  = y + "px";
		};
		
		slide.handleTweenAnimateIn = function (type, args, obj) {
		
			var pos = Dom.getXY(obj.overlay.element),
				currentX = pos[0],
				currentY = pos[1];
		
			if (Dom.getStyle(obj.overlay.element, "visibility") == 
				"hidden" && currentX < x) {

				Dom.setStyle(obj.overlay.element, "visibility", "visible");

			}
		
			obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
			obj.overlay.cfg.refireEvent("iframe");
		};
		
		slide.handleCompleteAnimateIn = function (type, args, obj) {
			obj.overlay.cfg.setProperty("xy", [x, y], true);
			obj.startX = x;
			obj.startY = y;
			obj.overlay.cfg.refireEvent("iframe");
			obj.animateInCompleteEvent.fire();
		};
		
		slide.handleStartAnimateOut = function (type, args, obj) {
	
			var vw = Dom.getViewportWidth(),
				pos = Dom.getXY(obj.overlay.element),
				yso = pos[1];
	
			obj.animOut.attributes.points.to = [(vw + 25), yso];
		};
		
		slide.handleTweenAnimateOut = function (type, args, obj) {
	
			var pos = Dom.getXY(obj.overlay.element),
				xto = pos[0],
				yto = pos[1];
		
			obj.overlay.cfg.setProperty("xy", [xto, yto], true);
			obj.overlay.cfg.refireEvent("iframe");
		};
		
		slide.handleCompleteAnimateOut = function (type, args, obj) {
			Dom.setStyle(obj.overlay.element, "visibility", "hidden");
		
			obj.overlay.cfg.setProperty("xy", [x, y]);
			obj.animateOutCompleteEvent.fire();
		};
		
		slide.init();
		return slide;
	};
	
	ContainerEffect.prototype = {
	
		/**
		* Initializes the animation classes and events.
		* @method init
		*/
		init: function () {

			this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
			this.beforeAnimateInEvent.signature = CustomEvent.LIST;
			
			this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
			this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
		
			this.animateInCompleteEvent = this.createEvent("animateInComplete");
			this.animateInCompleteEvent.signature = CustomEvent.LIST;
		
			this.animateOutCompleteEvent = 
				this.createEvent("animateOutComplete");
			this.animateOutCompleteEvent.signature = CustomEvent.LIST;
		
			this.animIn = new this.animClass(this.targetElement, 
				this.attrIn.attributes, this.attrIn.duration, 
				this.attrIn.method);

			this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
			this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);

			this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn, 
				this);
		
			this.animOut = new this.animClass(this.targetElement, 
				this.attrOut.attributes, this.attrOut.duration, 
				this.attrOut.method);

			this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
			this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
			this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, 
				this);

		},
		
		animateIn: function () {
			this.beforeAnimateInEvent.fire();
			this.animIn.animate();
		},
		
		animateOut: function () {
			this.beforeAnimateOutEvent.fire();
			this.animOut.animate();
		},
		
		handleStartAnimateIn: function (type, args, obj) { },
	
		handleTweenAnimateIn: function (type, args, obj) { },
	
		handleCompleteAnimateIn: function (type, args, obj) { },
		
		handleStartAnimateOut: function (type, args, obj) { },
	
		handleTweenAnimateOut: function (type, args, obj) { },
	
		handleCompleteAnimateOut: function (type, args, obj) { },
		
		toString: function () {
			var output = "ContainerEffect";
			if (this.overlay) {
				output += " [" + this.overlay.toString() + "]";
			}
			return output;
		}
	
	};

	YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);

})();

YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.5.0", build: "897"});
