// SpryDOMUtils.js - version 0.6 - Spry Pre-Release 1.6.1

//

// 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.



var Spry; if (!Spry) 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.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

		ele.setAttribute(name, value);

};



Spry.Utils.removeAttribute = function(ele, name)

{

	ele = Spry.$(ele);

	if (!ele || !name)

		return;



	try

	{

		ele.removeAttribute(name);



		// 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.

		//

		// XXX: We should add a check for IE here instead of doing

		// it for every browser.



		if (name == "class")

			ele.removeAttribute("className");

	} catch(e) {}

};



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)

	{

		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.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.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)

{

	if (!rootNode)

		rootNode = document;

	else

		rootNode = Spry.$(rootNode);



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



	var matches = [];

	Spry.$$.addExtensions(matches);

	++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 (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 (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;

};
