

// SpryDOMUtils.js - version 0.13 - Spry Pre-Release 1.7
//
// Copyright (c) 2007. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

(function() { // BeginSpryComponent

if (typeof Spry == "undefined") window.Spry = {}; if (!Spry.Utils) Spry.Utils = {};

//////////////////////////////////////////////////////////////////////
//
// Define Prototype's $() convenience function, but make sure it is
// namespaced under Spry so that we avoid collisions with other
// toolkits.
//
//////////////////////////////////////////////////////////////////////

Spry.$ = function(element)
{
	if (arguments.length > 1)
	{
		for (var i = 0, elements = [], length = arguments.length; i < length; i++)
			elements.push(Spry.$(arguments[i]));
		return elements;
	}
	if (typeof element == 'string')
		element = document.getElementById(element);
	return element;
};

//////////////////////////////////////////////////////////////////////
//
// DOM Utils
//
//////////////////////////////////////////////////////////////////////

Spry.Utils.getAttribute = function(ele, name)
{
	ele = Spry.$(ele);
	if (!ele || !name)
		return null;

	// We need to wrap getAttribute with a try/catch because IE will throw
	// an exception if you call it with a namespace prefixed attribute name
	// that doesn't exist.

	try { var value = ele.getAttribute(name); }
	catch (e) { value == undefined; }

	// XXX: Workaround for Safari 2.x and earlier:
	//
	// If value is undefined, the attribute didn't exist. Check to see if this is
	// a namespace prefixed attribute name. If it is, remove the ':' from the name
	// and try again. This allows us to support spry attributes of the form
	// "spry:region" and "spryregion".

	if (value == undefined && name.search(/:/) != -1)
	{
		try { var value = ele.getAttribute(name.replace(/:/, "")); }
		catch (e) { value == undefined; }
	}

	return value;
};

Spry.Utils.setAttribute = function(ele, name, value)
{
	ele = Spry.$(ele);
	if (!ele || !name)
		return;

	// IE doesn't allow you to set the "class" attribute. You
	// have to set the className property instead.

	if (name == "class")
		ele.className = value;
	else
	{
		// I'm probably being a bit paranoid, but given the fact that
		// getAttribute() throws exceptions when dealing with namespace
		// prefixed attributes, I'm going to wrap this setAttribute()
		// call with try/catch just in case ...

		try { ele.setAttribute(name, value); } catch(e) {}

		// XXX: Workaround for Safari 2.x and earlier:
		//
		// If this is a namespace prefixed attribute, check to make
		// sure an attribute was created. This is necessary because some
		// older versions of Safari (2.x and earlier) drop the namespace
		// prefixes. If the attribute was munged, try removing the ':'
		// character from the attribute name and setting the attribute
		// using the resulting name. The idea here is that even if we
		// remove the ':' character, Spry.Utils.getAttribute() will still
		// find the attribute.

		if (name.search(/:/) != -1 && ele.getAttribute(name) == undefined)
			ele.setAttribute(name.replace(/:/, ""), value);
	}
};

Spry.Utils.removeAttribute = function(ele, name)
{
	ele = Spry.$(ele);
	if (!ele || !name)
		return;

	try { ele.removeAttribute(name); } catch(e) {}

	// XXX: Workaround for Safari 2.x and earlier:
	//
	// If this is a namespace prefixed attribute, make sure we
	// also remove any attributes with the same name, but without
	// the ':' character.

	if (name.search(/:/) != -1)
		ele.removeAttribute(name.replace(/:/, ""));

	// XXX: Workaround for IE
	//
	// IE doesn't allow you to remove the "class" attribute.
	// It requires you to remove "className" instead, so go
	// ahead and try to remove that too.

	if (name == "class")
		ele.removeAttribute("className");
};

Spry.Utils.addClassName = function(ele, className)
{
	ele = Spry.$(ele);
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
		return;
	ele.className += (ele.className ? " " : "") + className;
};

Spry.Utils.removeClassName = function(ele, className)
{
	ele = Spry.$(ele);
	if (Spry.Utils.hasClassName(ele, className))
		ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
};

Spry.Utils.toggleClassName = function(ele, className)
{
	if (Spry.Utils.hasClassName(ele, className))
		Spry.Utils.removeClassName(ele, className);
	else
		Spry.Utils.addClassName(ele, className);
};

Spry.Utils.hasClassName = function(ele, className)
{
	ele = Spry.$(ele);
	if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)
		return false;
	return true;
};

Spry.Utils.camelizeString = function(str)
{
	var cStr = "";
	var a = str.split("-");
	for (var i = 0; i < a.length; i++)
	{
		var s = a[i];
		if (s)
			cStr = cStr ? (cStr + s.charAt(0).toUpperCase() + s.substring(1)) : s;
	}
	return cStr;
};

Spry.Utils.styleStringToObject = function(styleStr)
{
	var o = {};
	if (styleStr)
	{
		var pvA = styleStr.split(";");
		for (var i = 0; i < pvA.length; i++)
		{
			var pv = pvA[i];
			if (pv && pv.indexOf(":") != -1)
			{
				var nvA = pv.split(":");
				var n = nvA[0].replace(/^\s*|\s*$/g, "");			
				var v = nvA[1].replace(/^\s*|\s*$/g, "");
				if (n && v)
					o[Spry.Utils.camelizeString(n)] = v;
			}
		}
	}
	return o;
};

Spry.Utils.addEventListener = function(element, eventType, handler, capture)
{
	try
	{
		if (!Spry.Utils.eventListenerIsBoundToElement(element, eventType, handler, capture))
		{
			element = Spry.$(element);
			handler = Spry.Utils.bindEventListenerToElement(element, eventType, handler, capture);
			if (element.addEventListener)
				element.addEventListener(eventType, handler, capture);
			else if (element.attachEvent)
				element.attachEvent("on" + eventType, handler);
		}
	}
	catch (e) {}
};

Spry.Utils.removeEventListener = function(element, eventType, handler, capture)
{
	try
	{
			element = Spry.$(element);
			handler = Spry.Utils.unbindEventListenerFromElement(element, eventType, handler, capture);
			if (element.removeEventListener)
				element.removeEventListener(eventType, handler, capture);
			else if (element.detachEvent)
				element.detachEvent("on" + eventType, handler);
	}
	catch (e) {}
};

Spry.Utils.eventListenerHash = {};
Spry.Utils.nextEventListenerID = 1;

Spry.Utils.getHashForElementAndHandler = function(element, eventType, handler, capture)
{

	var hash = null;
	element = Spry.$(element);
	if (element)
	{
		if (typeof element.spryEventListenerID == "undefined")
			element.spryEventListenerID = "e" + (Spry.Utils.nextEventListenerID++);
		if (typeof handler.spryEventHandlerID == "undefined")
			handler.spryEventHandlerID = "h" + (Spry.Utils.nextEventListenerID++);	
		hash = element.spryEventListenerID + "-" + handler.spryEventHandlerID + "-" + eventType + (capture?"-capture":"");
	}
	return hash;
};

Spry.Utils.eventListenerIsBoundToElement = function(element, eventType, handler, capture)
{
	element = Spry.$(element);
	var hash = Spry.Utils.getHashForElementAndHandler(element, eventType, handler, capture);
	return Spry.Utils.eventListenerHash[hash] != undefined;
};

Spry.Utils.bindEventListenerToElement = function(element, eventType, handler, capture)
{
	element = Spry.$(element);
	var hash = Spry.Utils.getHashForElementAndHandler(element, eventType, handler, capture);
	if (Spry.Utils.eventListenerHash[hash])
		return Spry.Utils.eventListenerHash[hash];
	return Spry.Utils.eventListenerHash[hash] = function(e)
	{
		e = e || window.event;

		if (!e.preventDefault) e.preventDefault = function() { this.returnValue = false; };
		if (!e.stopPropagation) e.stopPropagation = function() { this.cancelBubble = true; };

		var result = handler.call(element, e);
		if (result == false)
		{
			e.preventDefault();
			e.stopPropagation();
		}
		return result;
	};
};

Spry.Utils.unbindEventListenerFromElement = function(element, eventType, handler, capture)
{
	element = Spry.$(element);
	var hash = Spry.Utils.getHashForElementAndHandler(element, eventType, handler, capture);
	if (Spry.Utils.eventListenerHash[hash])
	{
		handler = Spry.Utils.eventListenerHash[hash];
		Spry.Utils.eventListenerHash[hash] = undefined;
	}
	return handler;
};

Spry.Utils.cancelEvent = function(e)
{
	if (e.preventDefault) e.preventDefault();
	else e.returnValue = false;
	if (e.stopPropagation) e.stopPropagation();
	else e.cancelBubble = true;

	return false;
};


Spry.Utils.addLoadListener = function(handler)
{
	if (typeof window.addEventListener != 'undefined')
		window.addEventListener('load', handler, false);
	else if (typeof document.addEventListener != 'undefined')
		document.addEventListener('load', handler, false);
	else if (typeof window.attachEvent != 'undefined')
		window.attachEvent('onload', handler);
};

Spry.Utils.isDescendant = function(parent, child)
{
	if (parent && child)
	{
		child = child.parentNode;
		while (child)
		{
			if (parent == child)
				return true;
			child = child.parentNode;
		}
	}
	return false;
};

Spry.Utils.getAncestor = function(ele, selector)
{
	ele = Spry.$(ele);
	if (ele)
	{
		var s = Spry.$$.tokenizeSequence(selector ? selector : "*")[0];
		var t = s ? s[0] : null;
		if (t)
		{
			var p = ele.parentNode;
			while (p)
			{
				if (t.match(p))
					return p;
				p = p.parentNode;
			}
		}
	}
	return null;
};

//////////////////////////////////////////////////////////////////////
//
// CSS Selector Matching
//
//////////////////////////////////////////////////////////////////////

Spry.$$ = function(selectorSequence, rootNode)
{
	var matches = [];
	Spry.$$.addExtensions(matches);

	// If the first argument to $$() is an object, it
	// is assumed that all args are either a DOM element
	// or an array of DOM elements, in which case we
	// simply append all DOM elements to our special
	// matches array and return immediately.

	if (typeof arguments[0] == "object")
	{
		for (var i = 0; i < arguments.length; i++)
		{
			if (arguments[i].constructor == Array)
				matches.push.apply(matches, arguments[i]);
			else
				matches.push(arguments[i]);
		}
		return matches;
	}

	if (!rootNode)
		rootNode = document;
	else
		rootNode = Spry.$(rootNode);

	var sequences = Spry.$$.tokenizeSequence(selectorSequence);

	++Spry.$$.queryID;

	var nid = 0;
	var ns = sequences.length;
	for (var i = 0; i < ns; i++)
	{
		var m = Spry.$$.processTokens(sequences[i], rootNode);
		var nm = m.length;
		for (var j = 0; j < nm; j++)
		{
			var n = m[j];
			if (!n.spry$$ID)
			{
				n.spry$$ID = ++nid;
				matches.push(n);
			}
		}
	}

	var nm = matches.length;
	for (i = 0; i < nm; i++)
		matches[i].spry$$ID = undefined;

	return matches;
};

Spry.$$.cache = {};
Spry.$$.queryID = 0;

Spry.$$.Token = function()
{
	this.type = Spry.$$.Token.SELECTOR;
	this.name = "*";
	this.id = "";
	this.classes = [];
	this.attrs = [];

	this.pseudos = [];
};

Spry.$$.Token.Attr = function(n, v)
{
	this.name = n;
	this.value = v ? new RegExp(v) : undefined;
};

Spry.$$.Token.PseudoClass = function(pstr)
{
	this.name = pstr.replace(/\(.*/, "");
	this.arg = pstr.replace(/^[^\(\)]*\(?\s*|\)\s*$/g, "");
	this.func = Spry.$$.pseudoFuncs[this.name];
};

Spry.$$.Token.SELECTOR = 0;
Spry.$$.Token.COMBINATOR = 1;

Spry.$$.Token.prototype.match = function(ele, nameAlreadyMatches)
{
	if (this.type == Spry.$$.Token.COMBINATOR)
		return false;
	if (!nameAlreadyMatches && this.name != '*' && this.name != ele.nodeName.toLowerCase())
		return false;
	if (this.id && this.id != ele.id)
		return false;
	var classes = this.classes;
	var len = classes.length;
	for (var i = 0; i < len; i++)
	{
		if (!ele.className || !classes[i].value.test(ele.className))
			return false;
	}

	var attrs = this.attrs;
	len = attrs.length;
	for (var i = 0; i < len; i++)
	{
		var a = attrs[i];
		var an = ele.attributes.getNamedItem(a.name);
		if (!an || (!a.value && an.nodeValue == undefined) || (a.value && !a.value.test(an.nodeValue)))
			return false;
	}

	var ps = this.pseudos;
	var len = ps.length;
	for (var i = 0; i < len; i++)
	{
		var p = ps[i];
		if (p && p.func && !p.func(p.arg, ele, this))
			return false;
	}

	return true;
};

Spry.$$.Token.prototype.getNodeNameIfTypeMatches = function(ele)
{
	var nodeName = ele.nodeName.toLowerCase();
	if (this.name != '*')
	{
		if (this.name != nodeName)
			return null;
		return this.name;
	}
	return nodeName;
};

Spry.$$.escapeRegExpCharsRE = /\/|\.|\*|\+|\(|\)|\[|\]|\{|\}|\\|\|/g;

Spry.$$.tokenizeSequence = function(s)
{
	var cc = Spry.$$.cache[s];
	if (cc) return cc;

	// Attribute Selector: /(\[[^\"'~\^\$\*\|\]=]+([~\^\$\*\|]?=\s*('[^']*'|"[^"]*"|[^"'\]]+))?\s*\])/g
	// Simple Selector:    /((:[^\.#:\s,>~\+\[\]]+\(([^\(\)]+|\([^\(\)]*\))*\))|[\.#:]?[^\.#:\s,>~\+\[\]]+)/g
	// Combinator:         /(\s*[\s,>~\+]\s*)/g

	var tokenExpr = /(\[[^\"'~\^\$\*\|\]=]+([~\^\$\*\|]?=\s*('[^']*'|"[^"]*"|[^"'\]]+))?\s*\])|((:[^\.#:\s,>~\+\[\]]+\(([^\(\)]+|\([^\(\)]*\))*\))|[\.#:]?[^\.#:\s,>~\+\[\]]+)|(\s*[\s,>~\+]\s*)/g;

	var tkn = new Spry.$$.Token;
	var sequence = [];
	sequence.push(tkn);
	var tokenSequences = [];
	tokenSequences.push(sequence);

	s = s.replace(/^\s*|\s*$/, "");

	var expMatch = tokenExpr.exec(s);
	while (expMatch)
	{
		var tstr = expMatch[0];
		var c = tstr.charAt(0);
		switch (c)
		{
			case '.':
				tkn.classes.push(new Spry.$$.Token.Attr("class", "\\b" + tstr.substr(1) + "\\b"));
				break;
			case '#':
				tkn.id = tstr.substr(1);
				break;
			case ':':
				tkn.pseudos.push(new Spry.$$.Token.PseudoClass(tstr));
				break;
			case '[':
				var attrComps = tstr.match(/\[([^\"'~\^\$\*\|\]=]+)(([~\^\$\*\|]?=)\s*('[^']*'|"[^"]*"|[^"'\]]+))?\s*\]/);
				var name = attrComps[1];				
				var matchType = attrComps[3];
				var val = attrComps[4];
				if (val)
				{
					val = val.replace(/^['"]|['"]$/g, "");
					val = val.replace(Spry.$$.escapeRegExpCharsRE, '\\$&');
				}

				var matchStr = undefined;

				switch(matchType)
				{
					case "=":
						matchStr = "^" + val + "$";
						break;
					case "^=":
						matchStr = "^" + val;
						break;
					case "$=":
						matchStr = val + "$";
						break;
					case "~=":
					case "|=":
						matchStr = "\\b" + val + "\\b";
						break;
					case "*=":
						matchStr = val;
						break;
				}

				tkn.attrs.push(new Spry.$$.Token.Attr(name, matchStr));
				break;
			default:
				var combiMatch = tstr.match(/^\s*([\s,~>\+])\s*$/);
				if (combiMatch)
				{
					if (combiMatch[1] == ',')
					{
						sequence = new Array;
						tokenSequences.push(sequence);
						tkn = new Spry.$$.Token;
						sequence.push(tkn);
					}
					else
					{
						tkn = new Spry.$$.Token;
						tkn.type = Spry.$$.Token.COMBINATOR;
						tkn.name = combiMatch[1];
						sequence.push(tkn);
						tkn = new Spry.$$.Token();
						sequence.push(tkn);
					}
				}
				else
					tkn.name = tstr.toLowerCase();
				break;
		}
		expMatch = tokenExpr.exec(s);
	}

	Spry.$$.cache[s] = tokenSequences;

	return tokenSequences;
};

Spry.$$.combinatorFuncs = {
	// Element Descendant

	" ": function(nodes, token)
	{
		var uid = ++Spry.$$.uniqueID;
		var results = [];
		var nn = nodes.length;
		for (var i = 0; i < nn; i++)
		{
			var n = nodes[i];
			if (uid != n.spry$$uid)
			{
				// n.spry$$uid = uid;
				var ea = nodes[i].getElementsByTagName(token.name);
				var ne = ea.length;
				for (var j = 0; j < ne; j++)
				{
					var e = ea[j];

					// If the token matches, add it to our results. We have
					// to make sure e is an element because IE6 returns the DOCTYPE
					// tag as a comment when '*' is used in the call to getElementsByTagName().

					if (e.nodeType == 1 /* Node.ELEMENT_NODE */ && token.match(e, true))
						results.push(e);
					e.spry$$uid = uid;
				}
			}
		}
		return results;
	},

	// Element Child

	">": function(nodes, token)
	{
		var results = [];
		var nn = nodes.length;
		for (var i = 0; i < nn; i++)
		{
			var n = nodes[i].firstChild;
			while (n)
			{
				if (n.nodeType == 1 /* Node.ELEMENT_NODE */ && token.match(n))
					results.push(n);
				n = n.nextSibling;
			}
		}
		return results;
	},

	// Element Immediately Preceded By

	"+": function(nodes, token)
	{
		var results = [];
		var nn = nodes.length;
		for (var i = 0; i < nn; i++)
		{
			var n = nodes[i].nextSibling;
			while (n && n.nodeType != 1 /* Node.ELEMENT_NODE */)
				n = n.nextSibling;
			if (n && token.match(n))
				results.push(n);
		}
		return results;
	},

	// Element Preceded By

	"~": function(nodes, token)
	{
		var uid = ++Spry.$$.uniqueID;
		var results = [];
		var nn = nodes.length;
		for (var i = 0; i < nn; i++)
		{
			var n = nodes[i].nextSibling;
			while (n)
			{
				if (n.nodeType == 1 /* Node.ELEMENT_NODE */)
				{
					if (uid == n.spry$$uid)
						break;

					if (token.match(n))
					{
						results.push(n);
						n.spry$$uid = uid;
					}
				}
				n = n.nextSibling;
			}
		}
		return results;
	}
};

Spry.$$.uniqueID = 0;

Spry.$$.pseudoFuncs = {
	":first-child": function(arg, node, token)
	{
		var n = node.previousSibling;
		while (n)
		{
			if (n.nodeType == 1) return false; // Node.ELEMENT_NODE
			n = n.previousSibling;
		}

		return true;
	},

	":last-child": function(arg, node, token)
	{
		var n = node.nextSibling;
		while (n)
		{
			if (n.nodeType == 1) // Node.ELEMENT_NODE
				return false;
			n = n.nextSibling;
		}
		return true;
	},

	":empty": function(arg, node, token)
	{
		var n = node.firstChild;
		while (n)
		{
			switch(n.nodeType)
			{
				case 1: // Node.ELEMENT_NODE
				case 3: // Node.TEXT_NODE
				case 4: // Node.CDATA_NODE
				case 5: // Node.ENTITY_REFERENCE_NODE
					return false;
			}
			n = n.nextSibling;
		}
		return true;
	},

	":nth-child": function(arg, node, token)
	{
		return Spry.$$.nthChild(arg, node, token);
	},

	":nth-last-child": function(arg, node, token)
	{
		return Spry.$$.nthChild(arg, node, token, true);
	},

	":nth-of-type": function(arg, node, token)
	{
		return Spry.$$.nthChild(arg, node, token, false, true);
	},
	
	":nth-last-of-type": function(arg, node, token)
	{
		return Spry.$$.nthChild(arg, node, token, true, true);
	},
	
	":first-of-type": function(arg, node, token)
	{
		var nodeName = token.getNodeNameIfTypeMatches(node);
		if (!nodeName) return false;

		var n = node.previousSibling;
		while (n)
		{
			if (n.nodeType == 1 && nodeName == n.nodeName.toLowerCase()) return false; // Node.ELEMENT_NODE
			n = n.previousSibling;
		}

		return true;
	},

	":last-of-type": function(arg, node, token)
	{
		var nodeName = token.getNodeNameIfTypeMatches(node);
		if (!nodeName) return false;

		var n = node.nextSibling;
		while (n)
		{
			if (n.nodeType == 1 && nodeName == n.nodeName.toLowerCase()) // Node.ELEMENT_NODE
				return false;
			n = n.nextSibling;
		}
		return true;
	},

	":only-child": function(arg, node, token)
	{
		var f = Spry.$$.pseudoFuncs;
		return f[":first-child"](arg, node, token) && f[":last-child"](arg, node, token);
	},

	":only-of-type": function(arg, node, token)
	{
		var f = Spry.$$.pseudoFuncs;
		return f[":first-of-type"](arg, node, token) && f[":last-of-type"](arg, node, token);
	},

	":not": function(arg, node, token)
	{
		var s = Spry.$$.tokenizeSequence(arg)[0];
		var t = s ? s[0] : null;
		return !t || !t.match(node);
	},

	":enabled": function(arg, node, token)
	{
		return !node.disabled;
	},

	":disabled": function(arg, node, token)
	{
		return node.disabled;
	},

	":checked": function(arg, node, token)
	{
		return node.checked;
	},

	":root": function(arg, node, token)
	{
		return node.parentNode && node.ownerDocument && node.parentNode == node.ownerDocument;
	}
};

Spry.$$.nthRegExp = /((-|[0-9]+)?n)?([+-]?[0-9]*)/;

Spry.$$.nthCache = {
	  "even": { a: 2, b: 0, mode: 1, invalid: false }
	, "odd":  { a: 2, b: 1, mode: 1, invalid: false }
	, "2n":   { a: 2, b: 0, mode: 1, invalid: false }
	, "2n+1": { a: 2, b: 1, mode: 1, invalid: false }
};

Spry.$$.parseNthChildString = function(str)
{
	var o = Spry.$$.nthCache[str];
	if (!o)
	{
		var m = str.match(Spry.$$.nthRegExp);
		var n = m[1];
		var a = m[2];
		var b = m[3];

		if (!a)
		{
			// An 'a' value was not specified. Was there an 'n' present?
			// If so, we treat it as an increment of 1, otherwise we're
			// in no-repeat mode.

			a = n ? 1 : 0;
		}
		else if (a == "-")
		{
			// The string is using the "-n" short-hand which is
			// short for -1.

			a = -1;
		}
		else
		{
			// An integer repeat value for 'a' was specified. Convert
			// it into number.

			a = parseInt(a, 10);
		}

		// If a 'b' value was specified, turn it into a number.
		// If no 'b' value was specified, default to zero.

		b = b ? parseInt(b, 10) : 0;

		// Figure out the mode:
		//
		// -1 - repeat backwards
		//  0 - no repeat
		//  1 - repeat forwards

		var mode = (a == 0) ? 0 : ((a > 0) ? 1 : -1);
		var invalid = false;

		// Fix up 'a' and 'b' for proper repeating.

		if (a > 0 && b < 0)
		{
			b = b % a;
			b = ((b=(b%a)) < 0) ? a + b : b;
		}
		else if (a < 0)
		{
			if (b < 0)
				invalid = true;
			else
				a = Math.abs(a);
		}

		o = new Object;
		o.a = a;
		o.b = b;
		o.mode = mode;
		o.invalid = invalid;

		Spry.$$.nthCache[str] = o;
	}

	return o;
};

Spry.$$.nthChild = function(arg, node, token, fromLastSib, matchNodeName)
{
	if (matchNodeName)
	{
		var nodeName = token.getNodeNameIfTypeMatches(node);
		if (!nodeName) return false;
	}

	var o = Spry.$$.parseNthChildString(arg);

	if (o.invalid)
		return false;

	var qidProp = "spry$$ncQueryID";
	var posProp = "spry$$ncPos";
	var countProp = "spry$$ncCount";
	if (matchNodeName)
	{
		qidProp += nodeName;
		posProp += nodeName;
		countProp += nodeName;
	}

	var parent = node.parentNode;
	if (parent[qidProp] != Spry.$$.queryID)
	{
		var pos = 0;
		parent[qidProp] = Spry.$$.queryID;
		var c = parent.firstChild;
		while (c)
		{
			if (c.nodeType == 1 && (!matchNodeName || nodeName == c.nodeName.toLowerCase()))
				c[posProp] = ++pos;
			c = c.nextSibling;
		}
		parent[countProp] = pos;
	}

	pos = node[posProp];
	if (fromLastSib)
		pos = parent[countProp] - pos + 1;

/*
	var sib = fromLastSib ? "nextSibling" : "previousSibling";

	var pos = 1;
	var n = node[sib];
	while (n)
	{
		if (n.nodeType == 1 && (!matchNodeName || nodeName == n.nodeName.toLowerCase()))
		{
			if (n == node) break;
			++pos;
		}
		n = n[sib];
	}
*/

	if (o.mode == 0) // Exact match
		return pos == o.b;
	if (o.mode > 0) // Forward Repeat
		return (pos < o.b) ? false : (!((pos - o.b) % o.a));
	return (pos > o.b) ? false : (!((o.b - pos) % o.a)); // Backward Repeat
};

Spry.$$.processTokens = function(tokens, root)
{
	var numTokens = tokens.length;
	var nodeSet = [ root ];
	var combiFunc = null;

	for (var i = 0; i < numTokens && nodeSet.length > 0; i++)
	{
		var t = tokens[i];
		if (t.type == Spry.$$.Token.SELECTOR)
		{
			if (combiFunc)
			{
				nodeSet = combiFunc(nodeSet, t);
				combiFunc = null;
			}
			else
				nodeSet = Spry.$$.getMatchingElements(nodeSet, t);
		}
		else // Spry.$$.Token.COMBINATOR
			combiFunc = Spry.$$.combinatorFuncs[t.name];
	}
	return nodeSet;
};

Spry.$$.getMatchingElements = function(nodes, token)
{
	var results = [];
	if (token.id)
	{
		n = nodes[0];
		if (n && n.ownerDocument)
		{
			var e = n.ownerDocument.getElementById(token.id);
			if (e)
			{
				// XXX: We need to make sure that the element
				//      we found is actually underneath the root
				//      we were given!

				if (token.match(e))
					results.push(e);
			}
			return results;
		}
	}

	var nn = nodes.length;
	for (var i = 0; i < nn; i++)
	{
		var n = nodes[i];
		// if (token.match(n)) results.push(n);
		
		var ea = n.getElementsByTagName(token.name);
		var ne = ea.length;
		for (var j = 0; j < ne; j++)
		{
			var e = ea[j];

			// If the token matches, add it to our results. We have
			// to make sure e is an element because IE6 returns the DOCTYPE
			// tag as a comment when '*' is used in the call to getElementsByTagName().

			if (e.nodeType == 1 /* Node.ELEMENT_NODE */ && token.match(e, true))
				results.push(e);
		}
	}
	return results;
};

/*
Spry.$$.dumpSequences = function(sequences)
{
	Spry.Debug.trace("<hr />Number of Sequences: " + sequences.length);
	for (var i = 0; i < sequences.length; i++)
	{
		var str = "";
		var s = sequences[i];
		Spry.Debug.trace("<hr />Sequence " + i + " -- Tokens: " + s.length);
		for (var j = 0; j < s.length; j++)
		{
			var t = s[j];
			if (t.type == Spry.$$.Token.SELECTOR)
			{
				str += "  SELECTOR:\n    Name: " + t.name + "\n    ID: " + t.id + "\n    Attrs:\n";
				for (var k = 0; k < t.classes.length; k++)
					str += "      " + t.classes[k].name + ": " + t.classes[k].value + "\n";
				for (var k = 0; k < t.attrs.length; k++)
					str += "      " + t.attrs[k].name + ": " + t.attrs[k].value + "\n";
				str += "    Pseudos:\n";
				for (var k = 0; k < t.pseudos.length; k++)
					str += "      " + t.pseudos[k].name + (t.pseudos[k].arg ? "(" + t.pseudos[k].arg + ")" : "") + "\n";
			}
			else
			{
				str += "  COMBINATOR:\n    Name: '" + t.name + "'\n"; 
			}
		}
		Spry.Debug.trace("<pre>" + Spry.Utils.encodeEntities(str) + "</pre>");
	}
};
*/

Spry.$$.addExtensions = function(a)
{
	for (var f in Spry.$$.Results)
		a[f] = Spry.$$.Results[f];
};

Spry.$$.Results = {};

Spry.$$.Results.forEach = function(func)
{
	var n = this.length;
	for (var i = 0; i < n; i++)
		func(this[i]);
	return this;
};

Spry.$$.Results.setAttribute = function(name, value)
{
	return this.forEach(function(n) { Spry.Utils.setAttribute(n, name, value); });
};

Spry.$$.Results.removeAttribute = function(name)
{
	return this.forEach(function(n) { Spry.Utils.removeAttribute(n, name); });
};

Spry.$$.Results.addClassName = function(className)
{
	return this.forEach(function(n) { Spry.Utils.addClassName(n, className); });
};

Spry.$$.Results.removeClassName = function(className)
{
	return this.forEach(function(n) { Spry.Utils.removeClassName(n, className); });
};

Spry.$$.Results.toggleClassName = function(className)
{
	return this.forEach(function(n) { Spry.Utils.toggleClassName(n, className); });
};

Spry.$$.Results.addEventListener = function(eventType, handler, capture, bindHandler)
{
	return this.forEach(function(n) { Spry.Utils.addEventListener(n, eventType, handler, capture, bindHandler); });
};

Spry.$$.Results.removeEventListener = function(eventType, handler, capture)
{
	return this.forEach(function(n) { Spry.Utils.removeEventListener(n, eventType, handler, capture); });
};

Spry.$$.Results.setStyle = function(style)
{
	if (style)
	{
		style = Spry.Utils.styleStringToObject(style);
		this.forEach(function(n)
		{
			for (var p in style)
				try { n.style[p] = style[p]; } catch (e) {}
		});
	}
	return this;
};

Spry.$$.Results.setProperty = function(prop, value)
{
	if (prop)
	{
		if (typeof prop == "string")
		{
			var p = {};
			p[prop] = value;
			prop = p;
		}

		this.forEach(function(n)
		{
			for (var p in prop)
				try { n[p] = prop[p]; } catch (e) {}
		});
	}
	return this;
};

})(); // EndSpryComponent

// SpryDOMEffects.js - version 0.6 - Spry Pre-Release 1.7
//
// Copyright (c) 2007. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

(function() { // BeginSpryComponent
	
if (typeof Spry == "undefined" || !Spry.Utils || !Spry.$$)
{
	alert("SpryDOMEffects.js%20requires%20SpryDOMUtils.html");
	return;
}

if (!Spry.Effect) Spry.Effect = {};

Spry.Effect.Animator = function(opts)
{
	Spry.Effect.Animator.Notifier.call(this);

	this.animatorID = Spry.Effect.Animator.nextID++;
	this.dropFrames = true;
	this.fps = 60; // frames per-second
	this.duration = 500; // msecs
	this.timer = 0;
	this.startTime = 0; // Used only when dropFrames is true.
	this.currentFrame = 0;
	this.easeFunc = Spry.Effect.Animator.defaultEaseFunc;
	this.stopped = false;

	Spry.Effect.Animator.copyProps(this, opts);

	this.interval = 1000 / this.fps;
	this.numFrames = (this.duration / 1000) * this.fps;

	if (this.onComplete)
	{
		var self = this;
		this.addObserver({ onAnimationComplete: function(){ self.onComplete(); } });
	}
};

Spry.Effect.Animator.nextID = 1;

Spry.Effect.Animator.copyProps = function(dst, src)
{
	if (src)
	{
		for (prop in src)
			dst[prop] = src[prop];
	}
	return dst;
};

Spry.Effect.Animator.getElement = function(element)
{
	if (arguments.length > 1)
	{
		for (var i = 0, elements = [], length = arguments.length; i < length; i++)
			elements.push(Spry.Effect.Animator.getElement(arguments[i]));
		return elements;
	}
	if (typeof element == 'string')
		element = document.getElementById(element);
	return element;
};

Spry.Effect.Animator.defaultEaseFunc = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); };

Spry.Effect.Animator.Notifier = function()
{
	this.observers = [];
	this.suppressNotifications = 0;
};

Spry.Effect.Animator.Notifier.prototype.addObserver = function(observer)
{
	if (!observer)
		return;

	// Make sure the observer isn't already on the list.

	var len = this.observers.length;
	for (var i = 0; i < len; i++)
	{
		if (this.observers[i] == observer)
			return;
	}
	this.observers[len] = observer;
};

Spry.Effect.Animator.Notifier.prototype.removeObserver = function(observer)
{
	if (!observer)
		return;

	for (var i = 0; i < this.observers.length; i++)
	{
		if (this.observers[i] == observer)
		{
			this.observers.splice(i, 1);
			break;
		}
	}
};

Spry.Effect.Animator.Notifier.prototype.notifyObservers = function(methodName, data)
{
	if (!methodName)
		return;

	if (!this.suppressNotifications)
	{
		var len = this.observers.length;
		for (var i = 0; i < len; i++)
		{
			var obs = this.observers[i];
			if (obs)
			{
				if (typeof obs == "function")
					obs(methodName, this, data);
				else if (obs[methodName])
					obs[methodName](this, data);
			}
		}
	}
};

Spry.Effect.Animator.Notifier.prototype.enableNotifications = function()
{
	if (--this.suppressNotifications < 0)
	{
		this.suppressNotifications = 0;
		Spry.Debug.reportError("Unbalanced enableNotifications() call!\n");
	}
};

Spry.Effect.Animator.Notifier.prototype.disableNotifications = function()
{
	++this.suppressNotifications;
};

Spry.Effect.Animator.prototype = new Spry.Effect.Animator.Notifier;
Spry.Effect.Animator.prototype.constructor = Spry.Effect.Animator;

Spry.Effect.Animator.prototype.start = function()
{
	this.stopped = false;
	this.currentFrame = 0;
	this.startTime = (new Date()).getTime();

	this.notifyObservers("onAnimationStart");

	var self = this;
	this.timer = setTimeout(function(){ self.onStepAnimation(); }, this.interval);
};

Spry.Effect.Animator.prototype.stop = function()
{
	if (this.timer)
		clearTimeout(this.timer);
	this.timer = 0;
	this.stopped = true;

	this.notifyObservers("onAnimationStopped");
};

Spry.Effect.Animator.prototype.onStepAnimation = function()
{
	var obj = {};

	if (this.dropFrames)
	{
		obj.duration = this.duration;
		obj.elapsed = ((new Date).getTime()) - this.startTime;
		if (obj.elapsed > obj.duration)
			obj.elapsed = obj.duration;
	}
	else
	{
		obj.duration = this.numFrames;
		obj.elapsed = ++this.currentFrame;
	}

	obj.easingConst = this.easeFunc(obj.elapsed, 0, 1, obj.duration)

	this.notifyObservers("onPreDraw", obj);
	this.draw(obj.elapsed, obj.duration, obj.easingConst);
	this.notifyObservers("onPostDraw", obj);

	if (!this.stopped)
	{
		if (obj.elapsed < obj.duration)
		{
			var self = this;
			this.timer = setTimeout(function(){ self.onStepAnimation(); }, this.interval);
		}
		else
		{
			this.stop();
			this.notifyObservers("onAnimationComplete");
		}
	}
};

Spry.Effect.Animator.prototype.draw = function(elapsed, duration, easingConst)
{
	// The default draw method does nothing. It is assumed that
	// derived classes will provide their own implementation of this
	// method.

	debug.log("elapsed: " + elapsed + " -- duration: " + duration + " -- easingConst: " + easingConst);
};


///////////////////////////////////////////////////////////////////////////////

Spry.Effect.CSSAnimator = function(elements, styleStr, opts)
{
	this.animationSets = [];

	Spry.Effect.Animator.call(this, opts);

	this.add(elements, styleStr);
};

Spry.Effect.CSSAnimator.prototype = new Spry.Effect.Animator();
Spry.Effect.CSSAnimator.prototype.constructor = Spry.Effect.CSSAnimator;

Spry.Effect.CSSAnimator.prototype.add = function(elements, styleStr)
{
	// The first argument for the CSSAnimator can be
	// the id of an element, an element node, or an array of
	// elements and/or ids.

	elements = Spry.$$(elements);

	if (elements.length < 1)
		return;

	var animSet = { elements: elements, cssProps: []};

	this.animationSets.push(animSet);

	// Convert the styleStr into an object.

	var toObj = Spry.Utils.styleStringToObject(styleStr);
	for (var p in toObj)
	{
		var obj = new Object;
		var v = toObj[p];
		obj.value = new Number(v.replace(/[^-\d\.]+/g, ""));
		obj.units = v.replace(/[-\d+\.]/g, "");
		toObj[p] = obj;
	}

	for (var i = 0; i < elements.length; i++)
	{
		var obj = animSet.cssProps[i] = new Object;
		for (var p in toObj)
		{
			var pFuncs = Spry.Effect.CSSAnimator.stylePropFuncs[p];
			if (!pFuncs)
				pFuncs = Spry.Effect.CSSAnimator.stylePropFuncs["default"];

			obj[p] = new Object;
			obj[p].from = new Number(pFuncs.get(elements[i], p).replace(/[^-\d\.]+/g, ""));
			obj[p].to = toObj[p].value;
			obj[p].distance = obj[p].to - obj[p].from;
			obj[p].units = toObj[p].units;
		}
	}
};

Spry.Effect.CSSAnimator.prototype.start = function()
{
	for (var s = 0; s < this.animationSets.length; s++)
	{
		var animSet = this.animationSets[s];
		var elements = animSet.elements;
		var cssProps = animSet.cssProps;

		for (var i = 0; i < elements.length; i++)
		{
			var ele = elements[i];
	
			var eleProps = ele.spryCSSAnimatorProps;
			if (!eleProps)
				eleProps = ele.spryCSSAnimatorProps = new Object;
	
			var obj = cssProps[i];
			for (var p in obj)
				eleProps[p] = this.animatorID;
		}
	}

	return Spry.Effect.Animator.prototype.start.call(this);
};

Spry.Effect.CSSAnimator.prototype.stop = function()
{
	for (var s = 0; s < this.animationSets.length; s++)
	{
		var animSet = this.animationSets[s];
		var elements = animSet.elements;
		var cssProps = animSet.cssProps;

		for (var i = 0; i < elements.length; i++)
		{
			var ele = elements[i];
			var obj = cssProps[i];
	
			var eleProps = ele.spryCSSAnimatorProps;
			for (var p in obj)
			{
				if (eleProps[p] == this.animatorID)
					delete eleProps[p];
			}
		}
	}

	return Spry.Effect.Animator.prototype.stop.call(this);
};

Spry.Effect.CSSAnimator.prototype.draw = function(elapsed, duration, easingConst)
{
	for (var s = 0; s < this.animationSets.length; s++)
	{
		var animSet = this.animationSets[s];
		var elements = animSet.elements;
		var cssProps = animSet.cssProps;

		for (var i = 0; i < elements.length; i++)
		{
			var ele = elements[i];
			var eleProps = ele.spryCSSAnimatorProps;
			var obj = cssProps[i];
			for (var p in obj)
			{
				if (eleProps[p] == this.animatorID)
				{
					var pFuncs = Spry.Effect.CSSAnimator.stylePropFuncs[p];
					if (!pFuncs)
						pFuncs = Spry.Effect.CSSAnimator.stylePropFuncs["default"];
	
					if (elapsed > duration)
						pFuncs.set(ele, p, obj[p].to + obj[p].units);
					else
						pFuncs.set(ele, p, obj[p].from + (obj[p].distance * easingConst) + obj[p].units);
				}
			}
		}
	}
};

Spry.Effect.CSSAnimator.stylePropFuncs = {};

Spry.Effect.CSSAnimator.stylePropFuncs["default"] = {
	get: function(ele, prop)
	{
		return ele.style[prop];
	},

	set: function(ele, prop, val)
	{
		ele.style[prop] = val;
	}
};

Spry.Effect.CSSAnimator.stylePropFuncs["opacity"] = {
	get: function(ele, prop)
	{
		var val = 1;
		
		if (ele.style.opacity)
			val = ele.style.opacity;
		else if (ele.style.filter)
		{
			var strVal = ele.style.filter.replace(/.*alpha\(opacity=(\d+)\).*/, "$1");
			if (strVal)
				val = parseInt(strVal) / 100;
		}
		return val + "";
	},

	set: function(ele, prop, val)
	{
		ele.style.opacity = "" + val;
		ele.style.filter = "alpha(opacity=" + (val * 100) + ")";
	}
};

///////////////////////////////////////////////////////////////////////////////

Spry.$$.Results.defaultEaseFunc = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); };

Spry.$$.Results.animatePropertyTo = function(propName, to, options)
{
	var opts = { interval: 10, duration: 1000, onComplete: null, transition: Spry.$$.Results.defaultEaseFunc };
	Spry.Effect.Animator.copyProps(opts, options);

	var objs = [];
	for (var i = 0; i < this.length; i++)
	{
		var obj = objs[i] = new Object;
		obj.ele = this[i];
		obj.from = obj.ele[propName];
		obj.distance = to - obj.from;
	}

	var startTime = (new Date).getTime();

	var animateFunc = function()
	{
		var elapsedTime = ((new Date).getTime()) - startTime;

		if (elapsedTime > opts.duration)
		{
			for (var i = 0; i < objs.length; i++)
				objs[i].ele[propName] = to;
			if (opts.onComplete)
				opts.onComplete();
		}
		else
		{
			for (var i = 0; i < objs.length; i++)
			{
				var obj = objs[i];
				obj.ele[propName] = opts.transition(elapsedTime, obj.from, obj.distance, opts.duration);
			}
			setTimeout(animateFunc, opts.interval);
		}
	};

	setTimeout(animateFunc, opts.interval);
	return this;
};

Spry.$$.Results.animateStyleTo = function(styleStr, options)
{
	var a = new Spry.Effect.CSSAnimator(this, styleStr, options);
	a.start();
	return this;
};

})(); // EndSpryComponent
// SpryWidget.js - version 0.16 - Spry Pre-Release 1.7
//
// Copyright (c) 2009. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

(function() { // BeginSpryComponent
	
if (typeof Spry == "undefined" || !Spry.Utils || !Spry.$$)
{
	alert("SpryWidget.js requires SpryDOMUtils.js");
	return;
}

if (!Spry.Widget) Spry.Widget = {};

Spry.Widget.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
{
	if (obj && optionsObj)
	{
		for (var optionName in optionsObj)
		{
			var v = optionsObj[optionName];
			if (!ignoreUndefinedProps || v != undefined)
				obj[optionName] = v;
		}
	}
	return obj;
};

Spry.Widget.onLoadDidFire = false;
Spry.Widget.onLoadQueue = [];

Spry.Widget.addCallbackToOnLoadQueue = function(callbackFunc, context)
{
	if (callbackFunc)
	{
		if (context)
		{
			var cf = callbackFunc;
			callbackFunc = function() { cf.call(context); };
		}

		Spry.Widget.onLoadQueue.push(callbackFunc);
	}
};

Spry.Widget.triggerCallbackAfterOnLoad = function(callbackFunc, context)
{
	if (Spry.Widget.onLoadDidFire)
		callbackFunc.call(context);
	else
		Spry.Widget.addCallbackToOnLoadQueue(callbackFunc, context);
		
};

Spry.Widget.processOnLoadQueue = function()
{
	Spry.Widget.onLoadDidFire = true;
	var q = Spry.Widget.onLoadQueue;
	while (q.length)
		(q.shift())();
};

Spry.Utils.addLoadListener(Spry.Widget.processOnLoadQueue);

Spry.Widget.Base = function()
{
	Spry.Widget.Base.Notifier.call(this);
};

Spry.Widget.Base.Notifier = function()
{
	this.observers = [];
	this.suppressNotifications = 0;
};

Spry.Widget.Base.Notifier.prototype.addObserver = function(observer)
{
	if (!observer)
		return;

	// Make sure the observer isn't already on the list.

	var len = this.observers.length;
	for (var i = 0; i < len; i++)
	{
		if (this.observers[i] == observer)
			return;
	}
	this.observers[len] = observer;
};

Spry.Widget.Base.Notifier.prototype.removeObserver = function(observer)
{
	if (!observer)
		return;

	for (var i = 0; i < this.observers.length; i++)
	{
		if (this.observers[i] == observer)
		{
			this.observers.splice(i, 1);
			break;
		}
	}
};

Spry.Widget.Base.Notifier.prototype.notifyObservers = function(methodName, data)
{
	if (!methodName)
		return;

	if (!this.suppressNotifications)
	{
		var len = this.observers.length;
		for (var i = 0; i < len; i++)
		{
			var obs = this.observers[i];
			if (obs)
			{
				if (typeof obs == "function")
					obs(methodName, this, data);
				else if (obs[methodName])
					obs[methodName](this, data);
			}
		}
	}
};

Spry.Widget.Base.Notifier.prototype.enableNotifications = function()
{
	if (--this.suppressNotifications < 0)
	{
		this.suppressNotifications = 0;
		Spry.Debug.reportError("Unbalanced enableNotifications() call!\n");
	}
};

Spry.Widget.Base.Notifier.prototype.disableNotifications = function()
{
	++this.suppressNotifications;
};

Spry.Widget.Base.prototype = new Spry.Widget.Base.Notifier();
Spry.Widget.Base.prototype.constructor = Spry.Widget.Base;

Spry.Widget.Base.getElement = function(ele)
{
	return Spry.$(ele);
};

Spry.Widget.Base.getElements = function(elements)
{
	var eType = typeof elements;
	if (eType == "string")
		return Spry.$$(elements);
	else if (eType == "object")
	{
		if (elements.constructor == Array)
		{
			var result = [];
			for (var i = 0; i < elements.length; i++)
				result = result.concat(Spry.Widget.Base.getElements(elements[i]));
			return result;
		}
		else
			return [elements];
	}

	return [];
};

Spry.Widget.Base.getElementsByClassName = function(root, className)
{
	var results = [];

	if (typeof root.getElementsByClassName != "undefined")
	{
		// Browser has a native getElementsByClassName(), so use it.

		var nodeList = root.getElementsByClassName(className);
		for (var i = 0; i < nodeList.length; i++)
			results.push(nodeList.item(i));
	}
	else
	{
		// Browser has no native getElementsByClassName() implementation
		// so do a manual search.

		var re = new RegExp("\\b" + className + "\\b");
		var nodeList = root.getElementsByTagName("*");
		for (var i = 0; i < nodeList.length; i++)
		{
			var ele = nodeList.item(i);
			if (ele.className.search(re) != -1)
				results.push(ele);
		}
	}

	return results;
};

Spry.Widget.Base.prototype.getElementChildren = function(element)
{
	var children = [];
	if (element)
	{
		var child = element.firstChild;
		while (child)
		{
			if (child.nodeType == 1 /* Node.ELEMENT_NODE */)
				children.push(child);
			child = child.nextSibling;
		}
	}
	return children;
};

Spry.Widget.Base.prototype.groupContentByDelimeter = function(delimeterElements)
{
	var results = new Array();

	var numDelims = delimeterElements.length;
	for (var i = 0; i < numDelims; i++)
	{
		var delim = delimeterElements[i];
		var group = new Array();
		group.push(delim);

		var nextDelim = delimeterElements[i+1];
		var sib = delim.nextSibling;
		while (sib && sib != nextDelim)
		{
			group.push(sib);
			sib = sib.nextSibling;
		}
		
		results.push(group);
	}

	return results;
};

Spry.Widget.Base.prototype.createElement = function(elementName, className, parent, child)
{
	var ele = document.createElement(elementName);
	if (className) ele.className = className;
	if (parent) parent.appendChild(ele);
	if (child) ele.appendChild(child);
	return ele;
};

Spry.Widget.Base.prototype.sliceLeftClassStr =   "Left";
Spry.Widget.Base.prototype.sliceRightClassStr =  "Right";
Spry.Widget.Base.prototype.sliceCenterClassStr = "Center";
Spry.Widget.Base.prototype.sliceTopClassStr =    "Top";
Spry.Widget.Base.prototype.sliceBottomClassStr = "Bottom";

Spry.Widget.Base.prototype.sliceFuncs = {};

Spry.Widget.Base.prototype.sliceFuncs["2slice"] = function(root, eleName, baseClassName)
{
	var a = root ? root : document.createElement(eleName);
	var b = document.createElement(eleName);

	this.appendChildNodes(b, this.extractChildNodes(a)); // Transfer any children into the new content container.

	a.appendChild(b);

	this.addClassName(a, baseClassName + this.sliceLeftClassStr);
	b.className = baseClassName + this.sliceRightClassStr;

	a.contentContainer = b;

	return a;
};

Spry.Widget.Base.prototype.sliceFuncs["3slice"] = function(root, eleName, baseClassName)
{
	var a = root ? root : document.createElement(eleName);
	var b = document.createElement(eleName);
	var c = document.createElement(eleName);

	this.appendChildNodes(c, this.extractChildNodes(a)); // Transfer any children into the new content container.

	a.appendChild(b);
	b.appendChild(c);

	this.addClassName(a, baseClassName + this.sliceLeftClassStr);
	b.className = baseClassName + this.sliceRightClassStr;
	c.className = baseClassName + this.sliceCenterClassStr;

	a.contentContainer = c;

	return a;
};

Spry.Widget.Base.prototype.sliceFuncs["3sliceStacked"] = function(root, eleName, baseClassName)
{
	root = root ? root : document.createElement(eleName);

	var l = document.createElement(eleName);
	var m = document.createElement(eleName);
	var r = document.createElement(eleName);

	this.appendChildNodes(m, this.extractChildNodes(root)); // Transfer any children into the new content container.

	root.appendChild(l);
	root.appendChild(m);
	root.appendChild(r);

	this.addClassName(root, baseClassName);
	l.className = baseClassName + this.sliceLeftClassStr;
	m.className = baseClassName + this.sliceCenterClassStr;
	r.className = baseClassName + this.sliceRightClassStr;

	root.contentContainer = m;

	return root;
};

Spry.Widget.Base.prototype.sliceFuncs["9slice"] = function(root, eleName, baseClassName)
{
	if (!root)
		root = document.createElement(eleName);
	this.addClassName(root, baseClassName);

	var t = this.create3SliceStructure(null, eleName, baseClassName + this.sliceTopClassStr);
	var m = this.create3SliceStructure(null, eleName, baseClassName);
	var b = this.create3SliceStructure(null, eleName, baseClassName + this.sliceBottomClassStr);

	this.appendChildNodes(m.contentContainer, this.extractChildNodes(root)); // Transfer any children into the new content container.

	root.appendChild(t);
	root.appendChild(m);
	root.appendChild(b);

	var contentContainer = m.contentContainer;
	root.contentContainer = contentContainer;
	contentContainer.rootContainer = root;

	return root;
};

// XXX: REMOVE THESE AFTER WIDGETS HAVE BEEN CLEANED UP!
Spry.Widget.Base.prototype.create3SliceStructure = Spry.Widget.Base.prototype.sliceFuncs["3slice"];
Spry.Widget.Base.prototype.create9SliceStructure = Spry.Widget.Base.prototype.sliceFuncs["9slice"];
// XXX

Spry.Widget.Base.prototype.createOptionalSlicedStructure = function(root, eleName, className, sliceMap, childEleName)
{
	// root         - null or the dom element that will serve as the root of the sliced structure.
	//                If null, this function will create the root container using the element name specified.
	// eleName      - The tag to use when creating the sliced structure.
	// className    - The class names placed on each element within the sliced structure will be derived from this name.
	//				  If a space delimited list is passed in, all of the names are assigned to the root element, but children 
	//				  derive their classnames from just the first class in the list.
	// sliceMap     - null or a dictionary of class name keys whose values are either "9slice", "3slice", or "none".
	//                If null, the widget's sliceMap property is used.
	// childEleName - If specified, the eleName arg will only be used for the first element created within the structure. All
	//                other elements will be created with the specified childEleName.

	if (!sliceMap)
		sliceMap = this.sliceMap ? this.sliceMap : {};

	if (!childEleName)
		childEleName = eleName;

	var sliceType = sliceMap[className];
	sliceType = sliceType ? sliceType : "none";

	if (!root)
		root = document.createElement(eleName);
	this.addClassName(root, className);

	var baseClass = (className || "").split(/\s+/)[0];
	var sliceFunc = this.sliceFuncs[sliceType];
	if (sliceFunc)
		root = sliceFunc.call(this, root, childEleName, baseClass);
	else
		root.contentContainer = root;

	return root;
};

Spry.Widget.Base.prototype.extractChildNodes = function(ele)
{
	var children = [];
	while (ele.firstChild)
	{
		var c = ele.firstChild;
		children.push(c);
		ele.removeChild(c);
	}
	return children;
};

Spry.Widget.Base.prototype.appendChildNodes = function(ele, nodes)
{
	for (var i = 0; i < nodes.length; i++)
		ele.appendChild(nodes[i]);
};

Spry.Widget.Base.prototype.setOptions = Spry.Widget.setOptions;
Spry.Widget.Base.prototype.getOnLoadDidFire = function() { return Spry.Widget.onLoadDidFire; };
Spry.Widget.Base.prototype.addCallbackToOnLoadQueue = Spry.Widget.addCallbackToOnLoadQueue;
Spry.Widget.Base.prototype.triggerCallbackAfterOnLoad = Spry.Widget.triggerCallbackAfterOnLoad;

Spry.Widget.Base.prototype.getElement = Spry.Widget.Base.getElement;
Spry.Widget.Base.prototype.getElements = Spry.Widget.Base.getElements;
Spry.Widget.Base.prototype.addClassName = Spry.Utils.addClassName;
Spry.Widget.Base.prototype.hasClassName = Spry.Utils.hasClassName;
Spry.Widget.Base.prototype.removeClassName = Spry.Utils.removeClassName;
Spry.Widget.Base.prototype.addEventListener = Spry.Utils.addEventListener;
Spry.Widget.Base.prototype.removeEventListener = Spry.Utils.removeEventListener;

Spry.Widget.Base.prototype.indexOf = function(a, v)
{
	// IE6 doesn't support indexOf on Arrays so we need to check
	// for built-in support first. If not found manually do the
	// search.
	if (a)
	{
		if (a.indexOf)
			return a.indexOf(v);
		for (var i = 0; i < a.length; i++)
			if (a[i] == v)
				return i;
	}
	return -1;
};

Spry.Widget.Base.prototype.initializePlugIns = function(defaultPlugIns, widgetOpts)
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreInitializePlugIns", evt);
	if (!evt.performDefaultAction)
		return;

	// Both defaultPlugIns and widgetOpts are optional so make sure
	// we have always have something to work with.

	var opts = widgetOpts ? widgetOpts : {};
	var useDefaults = (typeof opts.useDefaultPlugIns == "undefined") ? true : opts.useDefaultPlugIns;

	var dp = (useDefaults && defaultPlugIns) ? defaultPlugIns : [];
	var np = opts.plugIns ? opts.plugIns : [];

	// Build a list of unique plugins from the default and user-specified sets.

	var plugIns = [];
	var plist = dp.concat(np);
	for (var i = 0; i < plist.length; i++)
	{
		var p = plist[i];
		if (this.indexOf(plugIns, p) < 0)
			plugIns.push(p);
	}

	// Sort the resulting set of plugins based on priority.

	plugIns = plugIns.sort(function(a, b)
	{
		var ap = (typeof a.priority == "undefined") ? 50 : a.priority;
		var bp = (typeof b.priority == "undefined") ? 50 : b.priority;
		return ap - bp;
	});

	// Store the sorted list of plugins on the widget.

	this.plugIns = plugIns;

	// Instantiate each plugin.

	for (var i = 0; plugIns && i < plugIns.length; i++)
	{
		if (plugIns[i].initialize)
			plugIns[i].initialize(this);
	}

	this.notifyObservers("onPostInitializePlugIns", evt);
};

Spry.Widget.Base.prototype.getClientPosition = function(ele)
{
	var pos = new Object;
	pos.x = ele.offsetLeft;
	pos.y = ele.offsetTop;
	var parent = ele.offsetParent;
	while (parent)
	{
		pos.x += parent.offsetLeft;
		pos.y += parent.offsetTop;
		parent = parent.offsetParent;
	}
	return pos;
};

Spry.Widget.Base.prototype.getStyleProp = function(element, prop)
{
	var value;
	var camelized = Spry.Utils.camelizeString(prop);
	try
	{
		if (element.style)
			value = element.style[camelized];

		if (!value)
		{
			if (document.defaultView && document.defaultView.getComputedStyle)
			{
				var css = document.defaultView.getComputedStyle(element, null);
				value = css ? css.getPropertyValue(prop) : null;
			}
			else if (element.currentStyle) 
			{
					value = element.currentStyle[camelized];
			}
		}
	}
	catch (e) {}

	return value == 'auto' ? null : value;
};

Spry.Widget.Base.prototype.makePositioned = function(element)
{
	var pos = this.getStyleProp(element, 'position');
	if (!pos || pos == 'static')
	{
		element.style.position = 'relative';

		// Opera returns the offset relative to the positioning context, when an
		// element is position relative but top and left have not been defined
		if (window.opera)
		{
			element.style.top = 0;
			element.style.left = 0;
		}
	}
};

Spry.Widget.Base.prototype.clearIEAlphaFilter = function(ele)
{
	var filter = ele.style.filter;

	// IE uses an alpha() filter for opacity. The filter style
	// property can contain multiple commands, so the idea here
	// is to just strip out the alpha(filter) and append a new
	// one, leaving any other filters untouched.

	if (filter)
	{
		filter = filter.replace(/alpha\([^\)]*\)/, "");
		filter = filter.replace(/^\s+|\s+$/, "");
		ele.style.filter = filter;
	}
	else
		filter = "";

	return filter;
};

Spry.Widget.Base.prototype.setOpacity = function(ele, opacity)
{
	ele.style.opacity = "" + opacity;

	var filter = this.clearIEAlphaFilter(ele);
	if (filter)
		filter += " ";

	ele.style.filter = filter + "alpha(opacity=" + (opacity*100) + ")";
};

Spry.Widget.Event = function(widget, opts)
{
	this.widget = widget;
	Spry.Widget.setOptions(this, opts);
	this.performDefaultAction = true;
};

Spry.Widget.Event.prototype.preventDefault = function() { this.performDefaultAction = false; };

////////////////////////////////////////////////////////

Spry.Widget.Button = function(ele, opts)
{
	Spry.Widget.Base.call(this);

	this.element = Spry.$$(ele)[0];

	// Initialize the button object with the global defaults.

	this.setOptions(this, Spry.Widget.Button.config);
	
	// Override the defaults with any options passed into the constructor.

	this.setOptions(this, opts);

	var self = this;

	this.addEventListener(this.element, "mousedown", function(e) { return self.handleMouseDown(e); }, false);
	this.addEventListener(this.element, "mouseover", function(e) { return self.handleMouseOver(e); }, false);
	this.addEventListener(this.element, "mouseout", function(e) { return self.handleMouseOut(e); }, false);

	// XXX: IE doesn't allow the setting of tabindex dynamically. This means we can't
	// rely on adding the tabindex attribute if it is missing to enable keyboard navigation
	// by default.

	// Find the first element within the tab container that has a tabindex or the first
	// anchor tag.
	this.focusElement = this.getFocusElement(this.element);
	if (this.focusElement)
	{
		this.addEventListener(this.focusElement, "focus", function(e) { return self.handleFocus(e); }, false);
		this.addEventListener(this.focusElement, "blur", function(e) { return self.handleBlur(e); }, false);
		this.addEventListener(this.focusElement, "keydown", function(e) { return self.handleKeyDown(e); }, false);
	}

	// We need to eat the onclick event so that buttons made
	// from links don't follow the link.
	
	this.addEventListener(this.element, "click", function(e) { return false; }, false);

	this.mouseUpCallback = function(evt) { return self.handleMouseUp(evt); };
};

Spry.Widget.Button.config = {
	disabled:             false,
	mouseOutCancelsClick: true,
	onclick:              null,
	downClass:            "ButtonDown",
	hoverClass:           "ButtonHover",
	disabledClass:        "ButtonDisabled",
	focusedClass:         "ButtonFocused"
};


Spry.Widget.Button.prototype = new Spry.Widget.Base();
Spry.Widget.Button.prototype.constructor = Spry.Widget.Button;

Spry.Widget.Button.prototype.handleMouseDown = function(evt)
{
	if (this.disabled)
		return false;

	this.addClassName(this.element, this.downClass);
	this.addEventListener(document, "mouseup", this.mouseUpCallback, true);

	this.notifyObservers("onButtonDown", { event: evt });
};

Spry.Widget.Button.prototype.handleMouseUp = function(evt)
{
	if (this.disabled)
		return false;

	this.removeClassName(this.element, this.downClass);
	this.removeEventListener(document, "mouseup", this.mouseUpCallback, true);

	if (this.onclick)
		this.onclick(evt);

	this.notifyObservers("onButtonUp");
	this.notifyObservers("onButtonClick");
};

Spry.Widget.Button.prototype.handleMouseOver = function(evt)
{
	if (this.disabled)
		return false;

	this.addClassName(this.element, this.hoverClass);
	this.notifyObservers("onButtonEnter");
};

Spry.Widget.Button.prototype.handleMouseOut = function(evt)
{
	if (this.disabled)
		return false;

	var ele = this.element;

	this.removeClassName(ele, this.hoverClass);

	if (this.mouseOutCancelsClick)
	{
		this.removeClassName(ele, this.downClass);
		this.removeEventListener(document, "mouseup", this.mouseUpCallback, true);
	}
	
	this.notifyObservers("onButtonExit");
};

Spry.Widget.Button.prototype.handleFocus = function(evt)
{
	if (this.disabled)
		return false;

	this.addClassName(this.element, this.focusedClass);
	this.notifyObservers("onButtonFocused");
};

Spry.Widget.Button.prototype.handleBlur = function(evt)
{
	if (this.disabled)
		return false;

	this.removeClassName(this.element, this.focusedClass);
	this.notifyObservers("onButtonBlur");
};

Spry.Widget.Button.prototype.handleKeyDown = function(evt)
{
	if (this.disabled)
		return false;
	this.notifyObservers("onButtonKeyDown", {event: evt, element: this.element});
};

Spry.Widget.Button.prototype.getFocusElement = function(element) {
	var focusElement = null;
	var indexEle = null;
	var anchorEle = null;

	this.preorderTraversal(element, function(node) {
		if (node.nodeType == 1 /* NODE.ELEMENT_NODE */)
		{
			var tabIndexAttr = element.attributes.getNamedItem("tabindex");
			if (tabIndexAttr)
			{
				indexEle = node;
				return true;
			}
			if (!anchorEle && node.nodeName.toLowerCase() == "a")
				anchorEle = node;
		}
		return false;
	});

	if (indexEle)
		focusElement = indexEle;
	else if (anchorEle)
		focusElement = anchorEle;
	return focusElement;
};

Spry.Widget.Button.prototype.preorderTraversal = function(root, func)
{
	var stopTraversal = false;
	if (root)
	{
		stopTraversal = func(root);
		if (root.hasChildNodes())
		{
			var child = root.firstChild;
			while (!stopTraversal && child)
			{
				stopTraversal = this.preorderTraversal(child, func);
				try { child = child.nextSibling; } catch (e) { child = null; }
			}
		}
	}
	return stopTraversal;
};

Spry.Widget.Button.prototype.disable = function()
{
	this.disabled = true;
	this.removeClassName(this.element, this.downClass);
	this.removeClassName(this.element, this.hoverClass);
	this.addClassName(this.element, this.disabledClass);
	this.removeEventListener(document, "mouseup", this.mouseUpCallback, true);
};

Spry.Widget.Button.prototype.enable = function()
{
	this.disabled = false;
	this.removeClassName(this.element, this.disabledClass);
};

Spry.Widget.Button.prototype.focus = function()
{
	if (this.disabled)
		return false;

	if (this.focusElement)
		this.focusElement.focus();
};


})(); // EndSpryComponent


// SpryPanelSet.js - version 0.4 - Spry Pre-Release 1.7
//
// Copyright (c) 2010. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

(function() { // BeginSpryComponent

if (typeof Spry == "undefined" || !Spry.Widget || !Spry.Widget.Base)
{
	alert("SpryPanelSet.js requires SpryWidget.js!");
	return;
}

Spry.Widget.PanelSet = function(elements, opts)
{
	Spry.Widget.Base.call(this);

	this.elements = elements ? Spry.$$(elements) : [];
	this.currentPanel = null;

	// Slide Show Mode properties.

	this.displayTimerID = 0;

	// Initialize the panel set object with the global defaults.

	this.setOptions(this, Spry.Widget.PanelSet.config);
	
	// Override the defaults with any options passed into the constructor.

	this.setOptions(this, opts);

	if (typeof (this.defaultPanel) == "number")
	{
		if (this.defaultPanel < 0)
			this.defaultPanel = 0;
		else
		{
			var count = this.getPanelCount();
			if (this.defaultPanel >= count)
				this.defaultPanel = (count > 1) ? (count - 1) : 0;
		}

	}

	this.initialize();
};

Spry.Widget.PanelSet.prototype = new Spry.Widget.Base();
Spry.Widget.PanelSet.prototype.constructor = Spry.Widget.PanelSet;

Spry.Widget.PanelSet.config = {
	defaultPanel:    0,
	autoPlay:       false,
	displayInterval: 8000, // msecs

	visibleClass:    "PanelVisible",
	hiddenClass:     "PanelHidden"
}

Spry.Widget.PanelSet.prototype.initialize = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreInitialize", evt);
	if (!evt.performDefaultAction)
		return;

	this.defaultPanel = this.indexToElement(this.defaultPanel);
	var panels = this.getPanels();

	for (var i = 0; i < panels.length; i++)
	{
		var ele = panels[i];
		var addClass = this.hiddenClass;
		var removeClass = this.visibleClass;

		if (ele == this.defaultPanel)
		{
			addClass = this.visibleClass;
			removeClass = this.hiddenClass;
			this.currentPanel = this.defaultPanel;
		}

		Spry.Utils.addClassName(ele, addClass);
		Spry.Utils.removeClassName(ele, removeClass);
	}

	if (this.autoPlay)
		this.play();

	this.notifyObservers("onPostInitialize", evt);
};

Spry.Widget.PanelSet.prototype.getPanels = function()
{
	return this.elements.slice(0);
};

Spry.Widget.PanelSet.prototype.getPanelCount = function()
{
	return this.getPanels().length;
};

Spry.Widget.PanelSet.prototype.getCurrentPanel = function()
{
	return this.currentPanel;
};

Spry.Widget.PanelSet.prototype.getCurrentPanelIndex = function()
{
	return this.getPanelIndex(this.getCurrentPanel());
};

Spry.Widget.PanelSet.prototype.getPanelIndex = function(panel)
{
	var panels = this.getPanels();
	for (var i = 0; i < panels.length; i++)
	{
		if (panel == panels[i])
			return i;
	}
	return -1;
};

Spry.Widget.PanelSet.prototype.getPanel = function(panelIndex)
{
	return this.getPanels()[panelIndex];
};

Spry.Widget.PanelSet.prototype.indexToElement = function(eleOrIndex)
{
	if (typeof eleOrIndex == "number")
		return this.getPanels()[eleOrIndex];
	return eleOrIndex ? Spry.$$(eleOrIndex)[0] : eleOrIndex;
};

Spry.Widget.PanelSet.prototype.elementToIndex = function(eleOrIndex)
{
	var panels = this.getPanels();

	if (typeof eleOrIndex == "number")
		return panels[eleOrIndex];

	if (typeof eleOrIndex == "string")
		eleOrIndex = Spry.$$(eleOrIndex)[0];

	return !eleOrIndex ? -1 : panels.indexOf(eleOrIndex);
};

Spry.Widget.PanelSet.prototype.createEvent = function(target, opts)
{
	var eopts = {
		target: target,
		targetIndex: this.getPanelIndex(target)
	};
	return new Spry.Widget.Event(this, this.setOptions(eopts, opts));
};

Spry.Widget.PanelSet.prototype.showPanel = function(eleOrIndex)
{
	var ele = this.indexToElement(eleOrIndex);
	if (ele && ele != this.currentPanel)
	{
		var evt = this.createEvent(ele, { currentPanel: this.currentPanel });
		this.notifyObservers("onPreShowPanel", evt);

		if (evt.performDefaultAction)
		{
			if (this.currentPanel)
				this.hidePanel(this.currentPanel);
	
			this.currentPanel = ele;
	
			Spry.Utils.addClassName(ele, this.visibleClass);
			Spry.Utils.removeClassName(ele, this.hiddenClass);

			this.notifyObservers("onPostShowPanel", evt);
		}
	}
};

Spry.Widget.PanelSet.prototype.hidePanel = function(eleOrIndex)
{
	var evt = this.createEvent(this.currentPanel);
	this.notifyObservers("onPreHidePanel", evt);

	if (evt.performDefaultAction)
	{
		var ele = this.currentPanel;

		Spry.Utils.addClassName(ele, this.hiddenClass);
		Spry.Utils.removeClassName(ele, this.visibleClass);

		this.currentPanel = null;

		this.notifyObservers("onPostHidePanel", evt);
	}
};

Spry.Widget.PanelSet.prototype.showPreviousPanel = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreShowPreviousPanel", evt);
	if (!evt.performDefaultAction)
		return;

	var curIndex = this.getCurrentPanelIndex();
	this.showPanel(((curIndex < 1) ? this.getPanelCount() : curIndex) - 1);

	this.notifyObservers("onPostShowPreviousPanel", evt);
};

Spry.Widget.PanelSet.prototype.showNextPanel = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreShowNextPanel", evt);
	if (!evt.performDefaultAction)
		return;

	this.showPanel((this.getCurrentPanelIndex()+1) % this.getPanelCount());

	this.notifyObservers("onPostShowNextPanel", evt);
};

Spry.Widget.PanelSet.prototype.showFirstPanel = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreShowFirstPanel", evt);
	if (!evt.performDefaultAction)
		return;

	this.showPanel(0);

	this.notifyObservers("onPostShowFirstPanel", evt);
};

Spry.Widget.PanelSet.prototype.showLastPanel = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreShowLastPanel", evt);
	if (!evt.performDefaultAction)
		return;

	var count = this.getPanelCount();
	this.showPanel(count > 0 ? count - 1 : 0);

	this.notifyObservers("onPostShowLastPanel", evt);
};


Spry.Widget.PanelSet.prototype.startTimer = function()
{
	this.stopTimer();
	var self = this;
	this.displayTimerID = setTimeout(function() { self.showNextPanel(); self.startTimer(); }, this.displayInterval);
};

Spry.Widget.PanelSet.prototype.stopTimer = function()
{
	if (this.displayTimerID)
		clearTimeout(this.displayTimerID);
	this.displayTimerID = 0;
};

Spry.Widget.PanelSet.prototype.isPlaying = function()
{
	return this.displayTimerID != 0;
};

Spry.Widget.PanelSet.prototype.play = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreStartSlideShowMode", evt);
	if (!evt.performDefaultAction)
		return;

	this.startTimer();

	this.notifyObservers("onPostStartSlideShowMode", evt);
};

Spry.Widget.PanelSet.prototype.stop = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreStopSlideShowMode", evt);
	if (!evt.performDefaultAction)
		return;

	this.stopTimer();

	this.notifyObservers("onPostStopSlideShowMode", evt);
};

})(); // EndSpryComponent

// SpryFadingPanels.js - version 0.5 - Spry Pre-Release 1.7
//
// Copyright (c) 2010. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

(function() { // BeginSpryComponent

if (typeof Spry == "undefined" || !Spry.Widget || !Spry.Widget.PanelSet)
{
	alert("SpryFadingPanels.js requires SpryPanelSet.js!");
	return;
}

Spry.Widget.FadingPanels = function(elements, opts)
{
	// Override any of the global defaults with options passed into
	// the constructor.

	var mergedOpts = this.setOptions(this.setOptions({}, Spry.Widget.FadingPanels.config), opts);

	Spry.Widget.PanelSet.call(this, Spry.$$(elements), mergedOpts);
};

Spry.Widget.FadingPanels.prototype = new Spry.Widget.PanelSet();
Spry.Widget.FadingPanels.prototype.constructor = Spry.Widget.FadingPanels;

Spry.Widget.FadingPanels.config = {
	defaultPanel:    0,
	minOpacity:      0,
	maxOpacity:      1,
	minDuration:     600, // msecs
	maxDuration:     800, // msecs
	stoppedMinDuration:     200, // msecs
	stoppedMaxDuration:     200, // msecs

	visibleClass:    "FadingPanelVisible",
	hiddenClass:     "FadingPanelHidden",

	autoPlay:       false,
	displayInterval: 9000, // msecs
	parallelTransition:true
};

Spry.Widget.FadingPanels.prototype.initialize = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPreInitialize", evt);
	if (!evt.performDefaultAction)
		return;

	this.disableNotifications();

	Spry.Widget.PanelSet.prototype.initialize.call(this);

	var panels = this.getPanels();
	var cpanel = this.currentPanel;

	for (var i = 0; i < panels.length; i++)
	{
		var p = panels[i];
		this.setOpacity(p, (p == cpanel) ? this.maxOpacity : this.minOpacity);
	}

	this.enableNotifications();

	this.notifyObservers("onPostInitialize", evt);
};

Spry.Widget.FadingPanels.prototype.showPanel = function(eleOrIndex)
{
	var ele = this.indexToElement(eleOrIndex);
	if (ele && ele != this.currentPanel)
	{
		var evt = this.createEvent(ele, { currentPanel: this.currentPanel });
		this.notifyObservers("onPreShowPanel", evt);
		if (!evt.performDefaultAction)
			return;

		if (this.showEffect && !this.parallelTransition) {
			this.showEffect.stop();
		}

		if (this.hideEffect && !this.parallelTransition) {
			this.hideEffect.stop();
		}

		var currentPanel = this.currentPanel;
		this.currentPanel = ele;

		var self = this;
		var showPanelComplete = function() {
			self.currentPanel = ele;
			self.addClassName(ele, self.visibleClass);
			self.removeClassName(ele, self.hiddenClass);

			self.notifyObservers("onPreShowPanelEffect", evt);
			self.showEffect = new Spry.Effect.CSSAnimator(ele, "opacity: " + self.maxOpacity, { duration: self.isPlaying()?self.maxDuration:self.stoppedMaxDuration });
			self.showEffect.addObserver({
				onAnimationComplete: function() {
					self.showEffect = null;
					self.notifyObservers("onPostShowPanelEffect", evt);
				}
			});
			self.showEffect.start();

			self.notifyObservers("onPostShowPanel", evt);
		};

		if (currentPanel)
			this.hidePanel(currentPanel, showPanelComplete);
		else
			showPanelComplete();

	}
};

Spry.Widget.FadingPanels.prototype.hidePanel = function(eleOrIndex, callback)
{
	var ele = this.indexToElement(eleOrIndex);
	if (ele) {
		var evt = this.createEvent(ele);
		this.notifyObservers("onPreHidePanel", evt);
		if (!evt.performDefaultAction)
			return;

		this.currentPanel = null;

		var self = this;
		var hidePanelComplete = function() {
			self.addClassName(ele, self.hiddenClass);
			self.removeClassName(ele, self.visibleClass);
			self.notifyObservers("onPostHidePanel", evt);

			if(callback) {
				callback();
			}
		};

		this.notifyObservers("onPreHidePanelEffect", evt);
		this.hideEffect = new Spry.Effect.CSSAnimator(ele, "opacity: " + this.minOpacity, { duration: this.isPlaying()?this.minDuration:this.stoppedMinDuration });
		this.hideEffect.addObserver({
			onAnimationComplete: function() {
				self.hideEffect = null;
				self.notifyObservers("onPostHidePanelEffect", evt);
				if (!self.parallelTransition) {
					hidePanelComplete();
				}
			}
		})
		this.hideEffect.start();

		if (this.parallelTransition) {
			hidePanelComplete();
		}
	}
};

})(); // EndSpryComponent

// SpryPanelSelector.js - version 0.6 - Spry Pre-Release 1.7
//
// Copyright (c) 2009. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

(function() { // BeginSpryComponent

if (typeof Spry == "undefined" || !Spry.Widget || !Spry.Widget.Base)
{
	alert("SpryPanelSelector.js requires SpryWidget.js!");
	return;
}

Spry.Widget.PanelSelector = function(elements, panel, opts)
{
	Spry.Widget.Base.call(this);

	this.buttons = Spry.$$(elements);
	this.panel = panel;
	this.disablePanelCallbacks = 0;
	this.currentButton = null;

	// Initialize the accordion object with the global defaults.

	this.setOptions(this, Spry.Widget.PanelSelector.config);
	
	// Override the defaults with any options passed into the constructor.

	this.setOptions(this, opts);

	if (typeof (this.defaultButton) == "number")
	{
		if (this.defaultButton < 0)
			this.defaultButton = 0;
		else
		{
			var count = this.getButtonCount();
			if (this.defaultButton >= count)
				this.defaultButton = (count > 1) ? (count - 1) : 0;
		}

	}
	this.attachBehaviors();
};

Spry.Widget.PanelSelector.config = {
	event:                    "click",
	defaultButton:            0,
	selectionStopsSlideShow:  true,
	useHrefs:                 false,
	selectedClass:            "PanelSelectorButtonSelected",
	unselectedClass:          "PanelSelectorButtonUnselected",
	downClass:                "PanelSelectorButtonDown",
	disabledClass:            "PanelSelectorButtonDisabled",
	hoverClass:               "PanelSelectorButtonHover",
	focusedClass:             "PanelSelectorButtonFocused"
};

Spry.Widget.PanelSelector.prototype = new Spry.Widget.Base();
Spry.Widget.PanelSelector.prototype.constructor = Spry.Widget.PanelSelector;

Spry.Widget.PanelSelector.prototype.getPanelIDFromHREF = function(ele)
{
	if (ele)
	{
		var href = ele.getAttribute("href");
		if (href != undefined && href.search(/^#\w/) != -1)
			return href.replace(/.*#/, "#");
	}
	return null;
};

Spry.Widget.PanelSelector.prototype.getButtonCount = function()
{
	return this.buttons.length;
};


Spry.Widget.PanelSelector.prototype.getCurrentButton = function()
{
	return this.currentButton;
};

Spry.Widget.PanelSelector.prototype.getCurrentButtonIndex = function()
{
	return this.elementToIndex(this.getCurrentButton());
};


Spry.Widget.PanelSelector.prototype.elementToIndex = function(ele)
{
	var ea = this.buttons;
	var n = ea.length;
	for (var i = 0; i < n; i++)
		if (ea[i] == ele) return i;
	return -1;
};

Spry.Widget.PanelSelector.prototype.indexToElement = function(eleOrIndex)
{
	return (typeof eleOrIndex == "number") ? this.buttons[eleOrIndex] : eleOrIndex;
};


Spry.Widget.PanelSelector.prototype.enableButton = function(eleOrIndex)
{
	var ele = this.indexToElement(eleOrIndex);
	if (ele && ele.psButton)
		ele.psButton.enable();
};


Spry.Widget.PanelSelector.prototype.disableButton = function(eleOrIndex)
{
	var ele = this.indexToElement(eleOrIndex);
	if (ele && ele.psButton)
		ele.psButton.disable();
};

Spry.Widget.PanelSelector.prototype.focusButton = function(eleOrIndex)
{
	var ele = this.indexToElement(eleOrIndex);
	if (ele && ele.psButton)
		ele.psButton.focus();
};

Spry.Widget.PanelSelector.prototype.selectButton = function(eleOrIndex, suppressPanelSync)
{
	++this.disablePanelCallbacks;

	var buttons = this.buttons;
	var ele = this.indexToElement(eleOrIndex);

	for (var i = 0; i < buttons.length; i++)
	{
		var e = buttons[i];
		this.removeClassName(e, (e == ele) ? this.unselectedClass : this.selectedClass);
		this.addClassName(e, (e == ele) ? this.selectedClass : this.unselectedClass);
	}

	this.currentButton = ele;

	if (!suppressPanelSync && this.panel)
	{
		var href = this.useHrefs ? this.getPanelIDFromHREF(ele) : null;
		this.panel.showPanel(href ? href : this.elementToIndex(ele));
	}

	--this.disablePanelCallbacks;
};

Spry.Widget.PanelSelector.prototype.selectPreviousButton = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPrePanelSelectorSelectPreviousButton", evt);
	if (!evt.performDefaultAction)
		return;

	var curIndex = this.getCurrentButtonIndex();
	this.handleActivate(((curIndex < 1) ? this.getButtonCount() : curIndex) - 1);

	this.notifyObservers("onPostPanelSelectorSelectPreviousButton", evt);
};

Spry.Widget.PanelSelector.prototype.selectNextButton = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPrePanelSelectorSelectNextButton", evt);
	if (!evt.performDefaultAction)
		return;

	this.handleActivate((this.getCurrentButtonIndex()+1) % this.getButtonCount());

	this.notifyObservers("onPostPanelSelectorSelectNextButton", evt);
};

Spry.Widget.PanelSelector.prototype.selectFirstButton = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPrePanelSelectorSelectFirstButton", evt);
	if (!evt.performDefaultAction)
		return;

	this.handleActivate(0);

	this.notifyObservers("onPostPanelSelectorSelectFirstButton", evt);
};

Spry.Widget.PanelSelector.prototype.selectLastButton = function()
{
	var evt = new Spry.Widget.Event(this);
	this.notifyObservers("onPrePanelSelectorSelectLastButton", evt);
	if (!evt.performDefaultAction)
		return;

	var count = this.getButtonCount();
	this.handleActivate(count > 0 ? count - 1 : 0);

	this.notifyObservers("onPostPanelSelectorSelectLastButton", evt);
};

Spry.Widget.PanelSelector.prototype.handleActivate = function(ele)
{
	if (typeof ele == "string")
		ele = document.getElementById(ele);

	var evt = new Spry.Widget.Event(this, { target: ele, targetIndex: this.elementToIndex(ele) });
	this.notifyObservers("onPrePanelSelectorClick", evt);
	if (!evt.performDefaultAction)
		return;

	if (this.selectionStopsSlideShow && this.panel)
		this.panel.stop();

	this.selectButton(ele);

	this.notifyObservers("onPostPanelSelectorClick", evt);
};

Spry.Widget.PanelSelector.prototype.handlePanelChange = function(data)
{
	if (this.disablePanelCallbacks)
		return;

	var panelEle = data.target;
	var panelIndex = data.targetIndex;

	if (!this.panel)
		return;

	var panelID = panelEle.id;
	var btns = this.buttons;
	var btn = btns[panelIndex];

	if (panelID)
	{
		// Search for the button to activate based on
		// the panel's id.
		
		for (var i = 0; !btn && i < btns.length; i++)
		{
			var b = btns[i];
			var id = this.getPanelIDFromHREF(b);
			if (id == panelID)
			{
				btn = b;
				break;
			}
		}
	}

	if (btn)
		this.selectButton(btn, true);
};

Spry.Widget.PanelSelector.prototype.attachButtonBehaviors = function(ele)
{
	var self = this;

	var activateFunc = function(e) { self.handleActivate(ele); return false; };

	ele.psButton = new Spry.Widget.Button(ele, {
		onclick:       activateFunc,
		downClass:     this.downClass,
		hoverClass:    this.hoverClass,
		disabledClass: this.disabledClass,
		focusedClass:  this.focusedClass
	});

	if (this.event != "click")
		this.addEventListener(ele, this.event, activateFunc, false);
};

Spry.Widget.PanelSelector.prototype.attachBehaviors = function()
{
	var self = this;
	var buttons = this.buttons;

	for (var i = 0; i < buttons.length; i++)
		this.attachButtonBehaviors(buttons[i]);

	if (this.panel)
		this.panel.addObserver({ onPostShowPanel: function(n, data){ self.handlePanelChange(data); }});

	this.selectButton(this.defaultButton);
};

})(); // EndSpryComponent
// SprySlidingPanels.js - version 0.5 - Spry Pre-Release 1.6.1
//
// Copyright (c) 2006. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

var Spry;
if (!Spry) Spry = {};
if (!Spry.Widget) Spry.Widget = {};

Spry.Widget.SlidingPanels = function(element, opts)
{
	this.element = this.getElement(element);
	this.enableAnimation = true;
	this.currentPanel = null;
	this.enableKeyboardNavigation = true;
	this.hasFocus = false;
	this.previousPanelKeyCode = Spry.Widget.SlidingPanels.KEY_LEFT;
	this.nextPanelKeyCode = Spry.Widget.SlidingPanels.KEY_RIGHT;

	this.currentPanelClass = "SlidingPanelsCurrentPanel";
	this.focusedClass = "SlidingPanelsFocused";
	this.animatingClass = "SlidingPanelsAnimating";

	Spry.Widget.SlidingPanels.setOptions(this, opts);

	if (this.element)
		this.element.style.overflow = "hidden";

	// Developers can specify the default panel as an index,
	// id or an actual element node. Make sure to normalize
	// it into an element node because that is what we expect
	// internally.

	if (this.defaultPanel)
	{
		if (typeof this.defaultPanel == "number")
			this.currentPanel = this.getContentPanels()[this.defaultPanel];
		else
			this.currentPanel = this.getElement(this.defaultPanel);
	}

	// If we still don't have a current panel, use the first one!

	if (!this.currentPanel)
		this.currentPanel = this.getContentPanels()[0];

	// Since we rely on the positioning information of the
	// panels, we need to wait for the onload event to fire before
	// we can attempt to show the initial panel. Once the onload
	// fires, we know that all CSS files have loaded. This is
	// especially important for Safari.

	if (Spry.Widget.SlidingPanels.onloadDidFire)
		this.attachBehaviors();
	else
		Spry.Widget.SlidingPanels.loadQueue.push(this);
};

Spry.Widget.SlidingPanels.prototype.onFocus = function(e)
{
	this.hasFocus = true;
	this.addClassName(this.element, this.focusedClass);
	return false;
};

Spry.Widget.SlidingPanels.prototype.onBlur = function(e)
{
	this.hasFocus = false;
	this.removeClassName(this.element, this.focusedClass);
	return false;
};

Spry.Widget.SlidingPanels.KEY_LEFT = 37;
Spry.Widget.SlidingPanels.KEY_UP = 38;
Spry.Widget.SlidingPanels.KEY_RIGHT = 39;
Spry.Widget.SlidingPanels.KEY_DOWN = 40;

Spry.Widget.SlidingPanels.prototype.onKeyDown = function(e)
{
	var key = e.keyCode;
	if (!this.hasFocus || (key != this.previousPanelKeyCode && key != this.nextPanelKeyCode))
		return true;

	if (key == this.nextPanelKeyCode)
		this.showNextPanel();
	else /* if (key == this.previousPanelKeyCode) */
		this.showPreviousPanel();

	if (e.preventDefault) e.preventDefault();
	else e.returnValue = false;
	if (e.stopPropagation) e.stopPropagation();
	else e.cancelBubble = true;

	return false;
};

Spry.Widget.SlidingPanels.prototype.attachBehaviors = function()
{
     var ele = this.element;
     if (!ele)
          return;
 
     if (this.enableKeyboardNavigation)
     {
          var focusEle = null;
          var tabIndexAttr = ele.attributes.getNamedItem("tabindex");
          if (tabIndexAttr || ele.nodeName.toLowerCase() == "a")
               focusEle = ele;
     
          if (focusEle)
          {
               var self = this;
               Spry.Widget.SlidingPanels.addEventListener(focusEle, "focus", function(e) { return self.onFocus(e || window.event); }, false);
               Spry.Widget.SlidingPanels.addEventListener(focusEle, "blur", function(e) { return self.onBlur(e || window.event); }, false);
               Spry.Widget.SlidingPanels.addEventListener(focusEle, "keydown", function(e) { return self.onKeyDown(e || window.event); }, false);
          }
     }
 
     if (this.currentPanel)
     {
          // Temporarily turn off animation when showing the
          // initial panel.
 
          var ea = this.enableAnimation;
          this.enableAnimation = false;
          this.showPanel(this.currentPanel);
          this.enableAnimation = ea;
     }
     
     if (this.automatic){
          this.start();
     }
};



Spry.Widget.SlidingPanels.prototype.getElement = function(ele)
{
	if (ele && typeof ele == "string")
		return document.getElementById(ele);
	return ele;
};

Spry.Widget.SlidingPanels.prototype.addClassName = function(ele, className)
{
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
		return;
	ele.className += (ele.className ? " " : "") + className;
};

Spry.Widget.SlidingPanels.prototype.removeClassName = function(ele, className)
{
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1))
		return;
	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
};

Spry.Widget.SlidingPanels.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
{
	if (!optionsObj)
		return;
	for (var optionName in optionsObj)
	{
		if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
			continue;
		obj[optionName] = optionsObj[optionName];
	}
};

Spry.Widget.SlidingPanels.prototype.getElementChildren = function(element)
{
	var children = [];
	var child = element.firstChild;
	while (child)
	{
		if (child.nodeType == 1 /* Node.ELEMENT_NODE */)
			children.push(child);
		child = child.nextSibling;
	}
	return children;
};

Spry.Widget.SlidingPanels.prototype.getCurrentPanel = function()
{
	return this.currentPanel;
};

Spry.Widget.SlidingPanels.prototype.getContentGroup = function()
{
	return this.getElementChildren(this.element)[0];
};

Spry.Widget.SlidingPanels.prototype.getContentPanels = function()
{
	return this.getElementChildren(this.getContentGroup());
};

Spry.Widget.SlidingPanels.prototype.getContentPanelsCount = function()
{
	return this.getContentPanels().length;
};

Spry.Widget.SlidingPanels.onloadDidFire = false;
Spry.Widget.SlidingPanels.loadQueue = [];

Spry.Widget.SlidingPanels.addLoadListener = function(handler)
{
	if (typeof window.addEventListener != 'undefined')
		window.addEventListener('load', handler, false);
	else if (typeof document.addEventListener != 'undefined')
		document.addEventListener('load', handler, false);
	else if (typeof window.attachEvent != 'undefined')
		window.attachEvent('onload', handler);
};

Spry.Widget.SlidingPanels.processLoadQueue = function(handler)
{
	Spry.Widget.SlidingPanels.onloadDidFire = true;
	var q = Spry.Widget.SlidingPanels.loadQueue;
	var qlen = q.length;
	for (var i = 0; i < qlen; i++)
		q[i].attachBehaviors();
};

Spry.Widget.SlidingPanels.addLoadListener(Spry.Widget.SlidingPanels.processLoadQueue);

Spry.Widget.SlidingPanels.addEventListener = function(element, eventType, handler, capture)
{
	try
	{
		if (element.addEventListener)
			element.addEventListener(eventType, handler, capture);
		else if (element.attachEvent)
			element.attachEvent("on" + eventType, handler);
	}
	catch (e) {}
};

Spry.Widget.SlidingPanels.prototype.getContentPanelIndex = function(ele)
{
	if (ele)
	{
		ele = this.getElement(ele);
		var panels = this.getContentPanels();
		var numPanels = panels.length;
		for (var i = 0; i < numPanels; i++)
		{
			if (panels[i] == ele)
				return i;
		}
	}
	return -1;
};

Spry.Widget.SlidingPanels.prototype.showPanel = function(elementOrIndex)
{
	var pIndex = -1;
	
	if (typeof elementOrIndex == "number")
		pIndex = elementOrIndex;
	else // Must be the element for the content panel.
		pIndex = this.getContentPanelIndex(elementOrIndex);

	var numPanels = this.getContentPanelsCount();
	if (numPanels > 0)
		pIndex = (pIndex >= numPanels) ? numPanels - 1 : pIndex;
	else
		pIndex = 0;

	var panel = this.getContentPanels()[pIndex];
	var contentGroup = this.getContentGroup();

	if (panel && contentGroup)
	{
		if (this.currentPanel)
			this.removeClassName(this.currentPanel, this.currentPanelClass);
		this.currentPanel = panel;

		var nx = -panel.offsetLeft;
		var ny = -panel.offsetTop;

		if (this.enableAnimation)
		{
			if (this.animator)
				this.animator.stop();
			var cx = contentGroup.offsetLeft;
			var cy = contentGroup.offsetTop;
			if (cx != nx || cy != ny)
			{
				var self = this;
				this.addClassName(this.element, this.animatingClass);
				this.animator = new Spry.Widget.SlidingPanels.PanelAnimator(contentGroup, cx, cy, nx, ny, { duration: this.duration, fps: this.fps, transition: this.transition, finish: function()
				{
					self.removeClassName(self.element, self.animatingClass);
					self.addClassName(panel, self.currentPanelClass);
				} });
				this.animator.start();
			}
		}
		else
		{
			contentGroup.style.left = nx + "px";
			contentGroup.style.top = ny + "px";
			this.addClassName(panel, this.currentPanelClass);
		}
	}

	return panel;
};

Spry.Widget.SlidingPanels.prototype.showFirstPanel = function()
{
	return this.showPanel(0);
};

Spry.Widget.SlidingPanels.prototype.showLastPanel = function()
{
	return this.showPanel(this.getContentPanels().length - 1);
};

Spry.Widget.SlidingPanels.prototype.showPreviousPanel = function()
{
	return this.showPanel(this.getContentPanelIndex(this.currentPanel) - 1);
};

Spry.Widget.SlidingPanels.prototype.showNextPanel = function()
{
	return this.showPanel(this.getContentPanelIndex(this.currentPanel) + 1);
};

Spry.Widget.SlidingPanels.PanelAnimator = function(ele, curX, curY, dstX, dstY, opts)
{
	this.element = ele;

	this.curX = curX;
	this.curY = curY;
	this.dstX = dstX;
	this.dstY = dstY;
	this.fps = 60;
	this.duration = 500;
	this.transition = Spry.Widget.SlidingPanels.PanelAnimator.defaultTransition;
	this.startTime = 0;
	this.timerID = 0;
	this.finish = null;

	var self = this;
	this.intervalFunc = function() { self.step(); };
	
	Spry.Widget.SlidingPanels.setOptions(this, opts, true);

	this.interval = 1000/this.fps;
};

Spry.Widget.SlidingPanels.PanelAnimator.defaultTransition = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); };

Spry.Widget.SlidingPanels.PanelAnimator.prototype.start = function()
{
	this.stop();
	this.startTime = (new Date()).getTime();
	this.timerID = setTimeout(this.intervalFunc, this.interval);
};

Spry.Widget.SlidingPanels.PanelAnimator.prototype.stop = function()
{
	if (this.timerID)
		clearTimeout(this.timerID);
	this.timerID = 0;
};

Spry.Widget.SlidingPanels.PanelAnimator.prototype.step = function()
{
	var elapsedTime = (new Date()).getTime() - this.startTime;
	var done = elapsedTime >= this.duration;
	var x, y;

	if (done)
	{
		x = this.curX = this.dstX;
		y = this.curY = this.dstY;
	}
	else
	{
		x = this.transition(elapsedTime, this.curX, this.dstX - this.curX, this.duration);
		y = this.transition(elapsedTime, this.curY, this.dstY - this.curY, this.duration);
	}

	this.element.style.left = x + "px";
	this.element.style.top = y + "px";

	if (!done)
		this.timerID = setTimeout(this.intervalFunc, this.interval);
	else if (this.finish)
		this.finish();
};

// These are all new methods
Spry.Widget.SlidingPanels.prototype.start = function(){
     var self = this; // reference to this, so we can use it inside our function
     this.automaticStarted = setInterval(function(){
               var panels = self.getContentPanels(),
                    panelcount = panels.length,
                    current = self.getCurrentPanel(),
                    newpanel;
               
               // locate the current panel index, and check if we need to increase or decrease the panel
               for(var i = 0; i < panelcount; i++){
                    if(panels[i] == current){
                         
                         self.direction == 1 ? (i++) : (i--);
                         
                         self.showPanel( self.direction == 1 ? (i >= panels.length ? 0 : i) : (i < 0 ? panels.length -1 : i));     
                                   
                         break; // stop looping, we already found and are displaying our new panel
                    }
               }
     }, this.each || 3000);
};
 
Spry.Widget.SlidingPanels.prototype.stop = function(){
     if(this.automaticStarted && typeof this.automaticStarted == 'number'){
          clearInterval(this.automaticStarted);
          this.automaticStarted = null;
     }
};
 
Spry.Widget.SlidingPanels.prototype.setDirection = function(direction){
     this.direction = direction;
}
