/* NO CACHE USED */
/*! SJS -- version 0.1.11 alpha
 *  Copyright (c) 2011 Daniel Huigens -- d.huigens@gmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


(function(undefined) {
	
	/* Function SJS
	 * Object SJS
	 * Function _: Alias of <functions/SJS>.
	 * Object _: Alias of <objects/SJS>.
	 */
	var SJS = function(v) {
		if(SJS.isElement(v))
		/* Function SJS(Element element)
		 * Alias of <g>.
		 * Returns <element>, if needed extended with the <Element> functions.
		 * Example: document.getElementById('test').animate('background', 'blue');
		 * Throws an error in Internet Explorer < 9.
		 * Example: _(document.getElementById('test')).animate('background', 'blue');
		 * Works in all browsers.
		 * Note: of course, you can also just do
		 $ _('#test').animate('background', 'blue');
		 * or
		 $ g('test').animate('background', 'blue');
		 */
			return window.g(v);
		if(SJS.isArray(v))
		/* Function SJS(Elements | Array elements)
		 * Wrapper of <Elements>.
		 * Returns <elements>. If elements is an array, it adds the <Elements> functions first.
		 */
			return new window.Elements(v.query, v);
		if(SJS.isFunction(v)) 
		/* Function SJS(Function function)
		 * Alias of window.<Elements#ready>.
		 * Binds <function> as an onready function, so <function> is called when the DOM is ready.
		 * Example:
		 $ _(function() {
		 $   // all kinds of magic
		 $ });
		 */
			return window.ready(v);
		/* Function SJS(String query)
		 * Alias of <SJS.search>.
		 * Queries the document for elements matching <query>.
		 * Example: _('div.test') // -> div elements that have 'test' as class
		 */
		return SJS.search(v);
	},
		rnReturn = /\r\n/g;
	
	
	/* Function SJS.extend(Object first, Object second, Bool overwrite)
	 * For every $key$/$value$ pair in <second>, copies value to $<first>[key]$
	 * - if it doesn't exist yet
	 * - or <overwrite> evaluates to true.
	 * Function SJS.extend(Object first, String key, Function | ... value, Bool overwrite)
	 * Copies <value> to $<first>[<key>]$.
	 * - if it doesn't exist yet
	 * - or <overwrite> evaluates to true.
	 */
	SJS.extend = function(t, k, v, overwrite) {
		if(k && k.charAt) {
			if(overwrite || t[k] === undefined || t[k] === null)
				t[k] = v;
		}
		else
			for(var i in k)
				if(k.hasOwnProperty(i) && (v /* =: overwrite */ || t[i] === undefined || t[i] === null))
					t[i] = k[i];
		return t;
	};
	
	SJS.extend(SJS, {
		/* Object SJS.Version
		 * String denoting the version of SJS.
		 */
		Version: '0.1.11',
		
		/* Object SJS.Features
		 * Object containing results of browser feature detections.
		 * Example:
		 $ if(SJS.isNull(SJS.Features.querySelectorAll))
		 $   SJS.Features.querySelectorAll = !!document.querySelectorAll;
		 $ if(!SJS.Features.querySelectorAll)
		 $   document.querySelectorAll = SJS.search;
		 * The existence of querySelectorAll is stored in Features.querySelectorAll. If it doesn't exist, it is created as an alias of <SJS.search>.
		 */
		Features: {},
		
		/* Object SJS.Settings
		 * Object that you can fill with any set of settings.
		 * Example:
		 $ _.Settings.myFancyPlugin = {
		 $   someSetting: 'someValue',
		 $   // etcetera
		 $ };
		 * ...
		 $ _.Settings.myFancyPlugin.someSetting // -> 'someValue', or something else if something changed it
		 */
		Settings: {},
		
		/* Function SJS.implement(Object first, Object second)
		 * <Extends @ SJS.extend> <first>'s prototype with <second>.
		 * Function SJS.implement(Object first, String key, Function | ... value)
		 * <Extends @ SJS.extend> <first>'s prototype with a <key> <value> pair.
		 */
		implement: function(t, k, v) {
			return SJS.extend(t.prototype, k, v);
		},
		/* Function SJS.classPropertyOf(value)
		 * Returns the internal 'Class' property of <value>.
		 * Example:
		 $ _.classPropertyOf('abc') // -> String
		 $ _.classPropertyOf(new String('abc')) // -> String
		 */
		classPropertyOf: function(t) {
			var ret = Object.prototype.toString.call(t);
			return ret.substr(8, ret.length - 9);
		},
		/* Function SJS.isString(value)
		 * Returns a bool indication wether <value> is a string or not.
		 $ var value = 1;
		 $ _.isString(value) // -> false
		 $ 
		 $ value = '1';
		 $ _.isString(value) // -> true
		 */
		isString: function(t) {
			return SJS.classPropertyOf(t) === 'String';
		},
		/* Function SJS.isNumber(value)
		 * Returns a bool indication wether <value> is a number or not.
		 $ var value = false;
		 $ _.isNumber(value) // -> false
		 $ 
		 $ value = '0';
		 $ _.isNumber(value) // -> false
		 $ 
		 $ value = 0;
		 $ _.isNumber(value) // -> true
		 */
		isNumber: function(t) {
			return SJS.classPropertyOf(t) === 'Number';
		},
		/* Function SJS.isFunction(value)
		 * Returns a bool indication wether <value> is a function or not.
		 $ function test () {}
		 $ _.isFunction(test) // -> true
		 $ _.isFunction(_) // -> true
		 */
		isFunction: function(t) {
			return SJS.classPropertyOf(t) === 'Function';
		},
		/* Function SJS.isArray(value)
		 * Returns a bool indication wether <value> is a array-like object or not.
		 * If this function returns true, you can use it with every SJS function that does something with arrays.
		 * If you need to know wether a variable is an object of type Array, check for $SJS.classPropertyOf(value) === 'Array'$.
		 * Example:
		 $ (function() {
		 $   _.isArray(arguments) // -> true
		 $ })();
		 */
		isArray: function(t) {
			return !SJS.isNull(t) && t.hasOwnProperty && t.hasOwnProperty('length') && !SJS.isString(t) && !SJS.isFunction(t);
		},
		/* Function SJS.isBoolean(value)
		 * Returns a bool indication wether <value> is a bool (true or false) or not.
		 $ var value = 1;
		 $ _.isBoolean(value) // -> false
		 $ 
		 $ value = false;
		 $ _.isBoolean(value) // -> true
		 */
		isBoolean: function(t) {
			return t === true || t === false;
		},
		/* Function SJS.isElement(value)
		 * Returns a bool indication wether <value> is a DOMElement or not.
		 $ var value = g('test');
		 $ _.isElement(value) // -> true if #test exists, false if #test does not exist
		 */
		isElement: function(t) {
			return SJS.classPropertyOf(t).indexOf('Element') > -1;
		},
		/* Function SJS.isElements(value)
		 * Returns a bool indication wether <value> is a SJS Elements object.
		 $ var value = _('#test');
		 $ _.isElements(value) // -> true (also if #test does not exist)
		 */
		isElements: function(t) {
			return t instanceof window.Elements;
		},
		/* Function SJS.isNull(value)
		 * Returns a bool indication wether <value> is undefined or null.
		 * Example:
		 $ var value;
		 $ _.isNull(value) // -> true
		 $ 
		 $ value = false;
		 $ _.isNull(value) // -> false
		 $ 
		 $ value = g('nonexistantelement');
		 $ _.isNull(value) // -> true
		 */
		isNull: function(t) {
			return t === undefined || t === null;
		},
		/* Function SJS.toArray(value)
		 * Returns:
		 * - An empty array if <value> is null
		 * - <value> if <value> is already an array
		 * - $[<value>]$ (i.e., a new array containing <value>) if <value> is not an array.
		 * Note: for array-like objects, toArray will not wrap them in an array.
		 */
		toArray: function(t) {
			return SJS.isNull(t) ? [] : (SJS.isArray(t) ? t : [t]);
		},
		/* Function SJS.toObject(key, value)
		 * Returns:
		 * - <key>, i.e. the first argument if that is an object (plain object or 'hash')
		 * - a new object containing one pair: <key>: <value>, otherwise
		 $ _.toObject('a', 'b') // -> {a: 'b'}
		 */
		toObject: function(k, v) {
			return SJS.isPlainObject(k) ? k : SJS.extend({}, k, v);
		},
		/* Function SJS.flatten(Array value)
		 * Returns an array containing <value>, but flattened.
		 * Example:
		 $ _.flatten([1, [2, 3], [[4], [[5], [6, 7]]]])
		 $ // -> [1, 2, 3, 4, 5, 6, 7]
		 */
		flatten: function(t) {
			var ret = [];
			SJS.each(t, function(el) {
				if(SJS.isArray(el))
					SJS.each(SJS.flatten(el), function(el) {
						ret.push(el);
					});
				else
					ret.push(el);
			});
			return ret;
		},
		filter: function(t, fn) {
			var ret;
			if(SJS.isArray(t)) {
				ret = [];
				/* Function SJS.filter(Array arr, Function fn)
				 * For each $value$ in <arr>, $<fn>(value)$ is called. If it returns true, it remains in the returned array. If false, it is removed.
				 * Example:
				 $ var arr = [1, 2, 3, 4, 5];
				 $ _.filter(arr, function(el) {
				 $   return el % 2;
				 $ }) // -> [1, 3, 5]
				 */
				if(SJS.isFunction(fn))
					SJS.each(t, function(el) {
						if(fn(el))
							ret.push(el);
					});
				/* Function SJS.filter(Array arr, Array allowed)
				 * For every $index$ $value$ pair in <arr>, if <allowed> contains $index$ (not $value$), it remains in the returned array. Otherwise it is removed.
				 * Example:
				 $ var arr = [1, 2, 3, 4, 5]
				 $ _.filter(arr, [3, 6]) // -> [4]
				 */
				else if(SJS.isArray(fn))
					SJS.each(t, function(el, i) {
						if(fn.contains(i))
							ret.push(el);
					});
				/* Function SJS.filter(Array arr)
				 * Returns <arr> with double values removed.
				 * Example:
				 $ var arr = [1, 1, 2, 3, 4, 5, 2, 4]
				 $ _.filter(arr) // -> [1, 2, 3, 4, 5]
				 */
				else
					SJS.each(t, function(el) {
						if(el && !ret.contains(el))
							ret.push(el);
					});
			}
			else {
				ret = {};
				/* Function SJS.filter(Object obj, Function fn)
				 * For each $value$ in <obj>, $<fn>(key, value)$ is called. If it returns true, it remains in the returned object. If false, it is removed.
				 * Example:
				 $ var obj = {
				 $   a: 1,
				 $   Aa: 2
				 $ }
				 $ _.filter(obj, function(key) {
				 $   return key[0].toUpperCase() == key[0];
				 $ }) // -> {Aa: 2}
				 */
				if(SJS.isFunction(fn))
					SJS.each(t, function(k, v) {
						if(fn(k, v))
							ret[k] = v;
					});
				/* Function SJS.filter(Object obj, Array allowed)
				 * For every $key$ $value$ pair in <obj>, if <allowed> contains $key$ (not $value$), it remains in the returned object. Otherwise it is removed.
				 * Example:
				 $ var obj = {
				 $   a: 1,
				 $   b: 2
				 $ };
				 $ _.filter(obj, ['b']) // -> {b: 2}
				 */
				else if(SJS.isArray(fn))
					SJS.each(t, function(k, v) {
						if(fn.contains(k))
							ret[k] = v;
					});
				/* Function SJS.filter(Object obj)
				 * Returns <obj> with undefined or null values removed.
				 * Example:
				 $ var obj = {
				 $   a: 0,
				 $   b: null
				 $ };
				 $ _.filter(obj) // -> {a: 0}
				 */
				else
					SJS.each(t, function(k, v) {
						if(!SJS.isNull(v))
							ret[k] = v;
					});
			}
			return ret;
		},
		/* Function SJS.isPlainObject(value)
		 * Returns a bool indicating wether <value> is a plain Object or 'Hash'.
		 $ var value = {
		 $   a: 1,
		 $   b: 2
		 $ };
		 $ _.isPlainObject(value) // -> true
		 $ value = 'test';
		 $ _.isPlainObject(value) // -> false
		 $ _.isPlainObject(_) // -> true
		 $ _.isPlainObject(_.isPlainObject) // -> false
		 */
		isPlainObject: function(t) {
			if(t === {})
				return true;
			for(var k in t) {}
			return !SJS.isNull(k) && SJS.hasOwn(t, k);
		},
		/* Function SJS.hasOwn(Object obj, String key)
		 * Returns a bool indicating wether $<obj>[<key>]$ exists.
		 $ var value = {
		 $   a: 1,
		 $   b: 2
		 $ };
		 $ 'a' in value // -> true
		 $ _.hasOwn(value, 'a') // -> true
		 * But the in operator can in some cases do what you do not want:

		 $ 'hasOwnProperty' in value // -> true
		 $ _.hasOwn(value, 'hasOwnProperty') // -> false
		 */
		hasOwn: function(t, name) {
			if(SJS.isNull(t))
				return false;
			if(!t.hasOwnProperty)
				return !SJS.isNull(t[name]);
			return t.hasOwnProperty(name);
		},
		/* Function SJS.each(Object | Array value, Function fn, Object context)
		 * For each $key$/$value$ pair in <value>, each calls $<fn>(key, value)$ with <context> or, if you leave that out, <value> as its this object.
		 $ var value = ['a', 'b', 3, 4],
		 $   result = '';
		 $ _.each(value, function(v) {
		 $   result += v + ', ';
		 $ });
		 $ result // -> 'a, b, 3, 4, '
		 $ 
		 $ value = {
		 $   a: 1,
		 $   b: 2
		 $ };
		 $ _.each(value, function(k, v) {
		 $   alert(k + v);
		 $ });
		 $ // alerts 'a1' and 'b2'
		 */
		each: function(t, fn, context) {
			var r = true,
				i,
				len;
			if(SJS.isArray(t))
				for(i = 0, len = t.length; i < len && r !== false; i++)
					r = fn.call(context || t, t[i], i, t);
			else
				for(i in t) {
					if(r === false)
						break;
					if(t.hasOwnProperty(i))
						r = fn.call(context || t, i, t[i], t);
				}
			return t;
		},
		/* Function SJS.forEach(Object | Array value, Function fn, Object context)
		 * For each $key$/$value$ pair in <value>, each calls $<fn>(key, value)$ with <context> or, if you leave that out, <value> as its this object.
		 * Note: with forEach, the argument order is always $key$, $value$, while with each, that depends on the type of <value>.
		 $ var value = ['a', 'b', 3, 4],
		 $   result = '';
		 $ _.forEach(value, function(k, v) {
		 $   result += k + ': ' + v + ', ';
		 $ });
		 $ result // -> '0: a, 1: b, 2: 3, 3: 4, '
		 $ 
		 $ value = {
		 $   a: 1,
		 $   b: 2
		 $ };
		 $ _.forEach(value, function(k, v) {
		 $   alert(k + v);
		 $ });
		 $ // alerts 'a1' and 'b2'
		 */
		forEach: function(t, fn, context) {
			if(SJS.isArray(t))
				SJS.each(t, function(v, k) {
					fn.call(context || t, k, v, t);
				});
			else
				SJS.each(t, fn, context);
		},
		/* Function SJS.invoke(Object | Array objects, String fn, arg1, arg2, ...)
		 * For each $value$ in <objects>, $value[<fn>]$ is called with <arg1>, <arg2>, etc.
		 * For example, instead of
		 $ _('.test').css('background', 'blue');
		 * You could also write the more verbose:
		 $ _.invoke(_('.test'), 'css', 'background', 'blue');
		 */
		invoke: function(t, fn) {
			var args = window.Array.prototype.slice.call(arguments, 2);
			SJS.forEach(t, function(k, v) {
				v[fn].apply(v, args);
			});
			return t;
		},
		times: function(t, obj, fn) {
			var i = 0;
			if(SJS.isFunction(obj)) {
				for(; i < t; i++) {
					fn();
				}
			}
			else if(fn in obj) {
				for(; i < t; i++) {
					obj[fn]();
				}
			}
		},
		/* Function SJS.without(Object | Array value, String | Int index)
		 * Returns a copy of <value>, but without $<value>[<index>]$.
		 $ var value = [0, 1, 2];
		 $ _.without(value, 1) // -> [0, 2]
		 $ value = {
		 $   a: 1,
		 $   b: 2
		 $ };
		 $ _.without(value, 'a') // -> {b: 2}
		 * Note: this function also works for Elements objects such as returned by <functions/_>.
		 */
		without: function(t, index) {
			if(SJS.isElements(t)) {
				var ret = Array.prototype.slice.call(t);
				ret = SJS.without(ret, index);
				ret = new window.Elements(t.query, ret);
				return ret;
			}
			else if(SJS.isArray(t)) {
				var arr = [];
				SJS.each(t, function(el, i) {
					if(i !== index)
						arr.push(el);
				});
				return arr;
			} else {
				var obj = t;
				delete obj[index];
				return obj;
			}
		},
		/* Function SJS.merge(Object first, Object second)
		 * Returns an object that contains all properties of <first> and <second>. Properties from <second> overwrite those from <first>.
		 $ var first = {
		 $   a: 1,
		 $   b: 2
		 $ },
		 $ second = {
		 $   b: 3,
		 $   c: 4
		 $ };
		 $ _.merge(first, second) // -> {a: 1, b: 3, c: 4}
		 $ _.merge(null, second) // -> {b: 3, c: 4}
		 */
		merge: function(t, k, v) {
			var r = SJS.isNull(t) ? {} : t,
				args = arguments;
			if(SJS.isString(k) && v !== undefined && v !== null)
				r[k] = v;
			else
				for(var i = 1, j; i < arguments.length; i++)
					for(j in args[i])
						if(args[i].hasOwnProperty(j) && args[i][j] !== undefined && args[i][j] !== null)
							r[j] = args[i][j];
			return r;
		},
		rgb2hex: function(t, alphaMode) {
			var r = '#',
				toHex = function(p) {
					var t = p.toString(16);
					return t.length == 1 ? '0' + t : t;
				},
				i = 0;
			if(alphaMode)
				r += toHex(Math.round(t[3] * 255));
			for(; i < 3; i++)
				r += toHex(t[i]);
			return r;
		},
		serialize: function(t) {
			if(SJS.isString(t))
				return t;
			var r = '', j = 0;
			SJS.each(t, function(i, el) {
				if(j++)
					r += '&';
				r += i + '=' + escape(el);
			});
			return r;
		}
	});
	
	SJS.implement(window.Array, {
		/* Function Array#contains(value, Bool strict)
		 * Returns a bool indicating wether <value> is an element in the array.
		 $ var value = ['a', 'b', 'c', 5, 6]
		 $ value.contains('b') // -> true
		 $ value.contains('6') // -> true
		 $ value.contains('6', true) // -> false
		 */
		contains: function(val, strict) {
			var c = false,
				i = 0,
				len = this.length;
			for(; i < len; i++)
				if((!strict && this[i] == val)
				|| (strict && this[i] === val)) {
					c = true;
					break;
				}
			return c;
		},
		containsKey: function(val) {
			return val < this.length;
		}
	});
	
	SJS.implement(window.String, {
		substringAfter: function(pos, len) {
			if(SJS.isNull(pos))
				return this;
			return SJS.isNumber(pos) ? this.substring(pos + 1, len) : this.substring(this.indexOf(pos) + pos.length, len);
		},
		/* Function String#htmlSpecialChars()
		 * Escapes:
		 * - $&amp;$ with $&amp;amp;$
		 * - $&lt;$ with $&amp;lt;$
		 * - $&gt;$ with $&amp;gt;$
		 * Example:
		 $ var value = '<div id="test">Hi & Bye!</div>';
		 $ value.htmlSpecialChars() // -> &lt;div id="test"&gt;Hi &amp; Bye!&lt;/div&gt;
		 */
		htmlSpecialChars: function() {
			return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
		},
		/* Function String#caps2dashes()
		 * Parses a javascript or python style camelCase string and returns a lower-case string with dashes ('$-$') between words.
		 $ var value = 'thisIsAMultiWordString';
		 $ value.caps2dashes() // -> 'this-is-a-multi-word-string'
		 $ 
		 $ value = 'WebkitBorderRadius';
		 $ value.caps2dashes() // -> '-webkit-border-radius'
		 */
		caps2dashes: function() {
			return this.replace(/[A-Z]/g, '-$&').toLowerCase();
		},
		/* Function String#hex2rgb()
		 * Parses a hexadecimal color string and returns an array that represents the red, green, blue values.
		 $ var value = 'FF0000';
		 $ value.hex2rgb() // -> [255, 0, 0]
		 $ 
		 $ value = '#ccc';
		 $ value.hex2rgb() // -> [204, 204, 204]
		 */
		hex2rgb: function() {
			var hex = this.charAt(0) == '#' ? this.substr(1) : this;
			if(hex.length == 3)
				hex = hex.replace(/(.)(.)(.)/, '$1$1$2$2$3$3');
			return [
				parseInt(hex.substr(0, 2), 16),
				parseInt(hex.substr(2, 2), 16),
				parseInt(hex.substr(4, 2), 16)
			];
		},
		insert: function(obj) {
			var r = this;
			SJS.each(obj, function(i, el) {
				r = r.replace(new RegExp('([^$])(\\$' + i + ')', 'gi'), '$1' + el);
			}, this);
			return r;
		},
		/* Function String#toElement(String html)
		 * Returns an <Element> as if <html> was placed somewhere in the source code.
		 * Example:
		 $ '<div id="test">content</div>'.toElement() // -> a div element with test as its id and content as its contents
		 */
		toElement: function() {
			var div = document.createElement('div'),
				children;
			div.innerHTML = this;
			
			children = g(div)._('> *');
			
			if(children.length === 1)
				return children[0];
			return g(div);
		}
	});
	
	window.SJS = SJS;
	if(!window._) window._ = SJS;
	
})();


/*
 * Copyright (C) 2005-2009 Diego Perini
 * All rights reserved.
 *
 * nwevents.js - Javascript Event Manager
 *
 * Author: Diego Perini <diego.perini at gmail com>
 * Version: 1.2.3
 * Created: 20051016
 * Release: 20091231
 *
 * License:
 *  http://javascript.nwbox.com/NWEvents/MIT-LICENSE
 * Download:
 *  http://javascript.nwbox.com/NWEvents/nwevents.js
 */

window.NW || (window.NW = {});

NW.Event = (function(global) {

  var version = 'nwevents-1.2.3',

  // default to DOM2
  USE_DOM2 = true,

  // event phases constants
  CAPTURING_PHASE = 1, AT_TARGET = 2, BUBBLING_PHASE = 3,

  // event collections and predefined DOM0 register
  Handlers = { }, Delegates = { }, Listeners = { }, Predefined = { },

  // initial script load context
  viewport = global, context = global.document, root = context.documentElement,

  EventCollection =
    function() {
      return {
        items: [],
        calls: [],
        parms: [],
        wraps: []
      };
    },

  /* ============================ FEATURE TESTING =========================== */

  // detect activation capabilities,
  // currently FF3, Opera and IE
  hasActive = 'activeElement' in context ?
    (function() {
      try {
        context.activeElement = null;
        return null === context.activeElement;
      } catch(e) {
        return false;
      }
    }) : true,

  // detect native methods
  isNative = (function() {
    var s = (global.open + '').replace(/open/g, '');
    return function(object, method) {
      var m = object ? object[method] : false, r = new RegExp(method, 'g');
      return !!(m && typeof m != 'string' && s === (m + '').replace(r, ''));
    };
  })(),

  // detect event model in use
  W3C_MODEL = root.addEventListener && root.removeEventListener ? true : false,
  MSIE_MODEL = root.attachEvent && root.detachEvent ? true : false,

  /* ============================ UTILITY METHODS =========================== */

  // get document from element
  getDocument =
    function(e) {
      return e.ownerDocument || e.document || e;
    },

  // get window from document
  getWindow = 'parentWindow' in top.document ?
    function(d) {
      return d.parentWindow || window;
    } : 'defaultView' in top.document && top === top.document.defaultView ?
    function(d) {
      return d.defaultView || window;
    } :
    function(d) {
      // fix for older Safari 2.0.x returning
      // [object AbstractView] instead of [window]
      if (window.frames.length === 0 && top.document === d) {
        return top;
      } else {
        for (var i in top.frames) {
          if (top.frames[i].document === d) {
            return top.frames[i];
          }
        }
      }
      return top;
    },

  // fix IE event properties to comply with w3c standards
  fixEvent =
    function(element, event, capture) {
      // needed for DOM0 events
      event || (event = getWindow(getDocument(element)).event);
      // bound element (listening the event)
      event.currentTarget = element;
      // fired element (triggering the event)
      event.target = event.srcElement || element;
      // add preventDefault and stopPropagation methods
      event.preventDefault = preventDefault;
      event.stopPropagation = stopPropagation;
      // bound and fired element are the same AT_TARGET
      event.eventPhase = capture ? CAPTURING_PHASE : BUBBLING_PHASE;
      // related element (routing of the event)
      event.relatedTarget =
        event[(event.target == event.fromElement ? 'to' : 'from') + 'Element'];
      // set time event was fixed
      event.timeStamp=+new Date();
      return event;
    },

  // prevent default action
  preventDefault =
    function() {
      this.returnValue = false;
    },

  // stop event propagation
  stopPropagation =
    function() {
      this.cancelBubble = true;
    },

  // block any further event processing
  stop =
    function(event) {
      if (event.preventDefault) {
        event.preventDefault();
      } else {
        event.returnValue = false;
      }
      if (event.stopPropagation) {
        event.stopPropagation();
      } else {
        event.cancelBubble = true;
      }
      return false;
    },

  // check collection for registered event,
  // match element, handler and capture
  isRegistered =
    function(registry, element, type, handler, capture) {
      var i, l, found = false;
      if (registry[type] && registry[type].items) {
        for (i = 0, l = registry[type].items.length; l > i; i++) {
          if (
            registry[type].items[i] === element &&
            registry[type].calls[i] === handler &&
            registry[type].parms[i] === capture) {
            found = i;
            break;
          }
        }
      }
      return found;
    },

  // list event handlers bound to
  // a given object for each type
  getRegistered =
    function(object, type, register) {
      var i, j, l, results = [ ];
      type || (type = '*');
      object || (object = '*');
      register || (register = Listeners);
      for (i in register) {
        if (type.indexOf(i) > -1 || type == '*') {
          for (j = 0, l = register[i].items.length; j < l; j++) {
            if (register[i].items[j] === object || object == '*') {
              results.push(register[i].calls[j]);
            }
          }
        }
      }
      return results;
    },

  // handle listeners chain for event type
  handleListeners =
    function(event) {
      var i, l, result = true,
        items, calls, parms, phase,
        type = event.type, valid;

      if (Listeners[type] && Listeners[type].items) {

        // cache eventPhase access
        phase = event.eventPhase;

        if (!event.propagated && FormActivationEvents[type]) {
          if (event.preventDefault) event.preventDefault();
          else event.returnValue = false;
          return true;
        }

        // only AT_TARGET event.target === event.currentTarget
        if (phase !== AT_TARGET && event.target === this) {
          phase = event.eventPhase = AT_TARGET;
        }

        // make a copy of the Listeners[type] array
        // since it can be modified run time by the
        // events deleting themselves or adding new
        items = Listeners[type].items.slice();
        calls = Listeners[type].calls.slice();
        parms = Listeners[type].parms.slice();

        // process chain in fifo order
        for (i = 0, l = items.length; l > i; i++) {
          valid = false;
          if (items[i] === this) {
            switch (phase) {
              case CAPTURING_PHASE:
                if (!event.propagated || parms[i] === true) {
                  valid = true;
                }
                break;
              case BUBBLING_PHASE:
                if (parms[i] === false) {
                  valid = true;
                }
                break;
              case AT_TARGET:
                if (!event.propagated || parms[i] === true) {
                  valid = true;
                }
                break;
              // Safari load events have eventPhase == 0
              default:
                valid = true;
                break;
            }
          }
          if (valid && (result = calls[i].call(this, event)) === false) break;
        }

      }

      return result;
    },

  // handle delegates chain for event type
  handleDelegates =
    function(event) {
      var i, l,
        items, calls, parms, target,
        result = true, type = event.type;

      if (Delegates[type] && Delegates[type].items) {

        // make a copy of the Delegates[type] array
        // since it can be modified run time by the
        // events deleting themselves or adding new
        items = Delegates[type].items.slice();
        calls = Delegates[type].calls.slice();
        parms = Delegates[type].parms.slice();

        // process chain in fifo order
        bubblingLoop:
        for (i = 0, l = items.length; l > i; i++) {
          // if event.target matches one of the registered elements and
          // if "this" element matches one of the registered delegates
          target = event.target;
          // bubble events up to parent nodes
          while (target && target != this) {
            if (NW.Dom.match(target, items[i])) {
              // execute registered function in element scope
              if (calls[i].call(target, event) === false) {
                result = false;
                break bubblingLoop;
              }
            }
            target = target.parentNode;
          }
        }

      }

      return result;
    },

  // append element handler to the registry
  // used by handlers, listeners, delegates
  appendItem =
    function(registry, element, type, handler, capture) {
      // registry is a reference to an EventCollection,
      // actually supported Handler, Listeners, Delegates
      //registry[type] || (registry[type] = new EventCollection);
	  (registry[type] && registry[type].items) || (registry[type] = new EventCollection);
      // append handler to the registry
      registry[type].items.push(element);
      registry[type].calls.push(handler);
      registry[type].parms.push(capture);
    },

  // remove element handler from the registry
  // used by handlers, listeners, delegates
  removeItem =
    function(registry, type, key) {
      // remove handler from the registry
      registry[type].items.splice(key, 1);
      registry[type].calls.splice(key, 1);
      registry[type].parms.splice(key, 1);
    },

  // lazy definition for addEventListener / attachEvent
  appendEvent = W3C_MODEL && USE_DOM2 ?
    function(element, type, handler, capture) {
      // use DOM2 event registration
      element.addEventListener(type, handler, capture || false);
    } : MSIE_MODEL && USE_DOM2 ?
    function(element, type, handler, capture) {
      // use MSIE event registration
      var key = Handlers[type].wraps.push(function(event) {
        return handler.call(element, fixEvent(element, event, capture));
      });
      element.attachEvent('on' + type, Handlers[type].wraps[key - 1]);
    } :
    function(element, type, handler, capture) {
      Predefined['on' + type] = element['on' + type] || new Function();
      // use DOM0 event registration
      element['on' + type] = function(event) {
        var result;
        event || (event = fixEvent(this, event, capture));
        result = handler.call(this, event);
        Predefined['on' + type].call(this, event);
        return result;
      };
    },

  // lazy definition for removeEventListener / detachEvent
  removeEvent = W3C_MODEL && USE_DOM2 ?
    function(element, type, handler, capture) {
      // use DOM2 event registration
      element.removeEventListener(type, handler, capture || false);
    } : MSIE_MODEL && USE_DOM2 ?
    function(element, type, handler, capture, key) {
      // use MSIE event registration
      element.detachEvent('on' + type, handler);
      Handlers[type].wraps.splice(key, 1);
    } :
    function(element, type, handler, capture) {
      // use DOM0 event registration
      element['on' + type] = Predefined['on' + type];
      delete Predefined['on' + type];
    },

  // append an event handler
  appendHandler =
    function(element, type, handler, capture) {
      var i, k, l, types;
      if (typeof type == 'string') {
        types = type.split(' ');
        for (i = 0, l = types.length; i < l; i++) {
          k = isRegistered(Handlers, element, types[i], handler, capture);
          if (k === false) {
            appendItem(Handlers, element, types[i], handler, capture);
            appendEvent(element, types[i], handler, capture);
          }
        }
      } else {
        // a hash of "rules" containing type-handler pairs
        for (i in type) {
          appendHandler(element, i, type[i], capture);
        }
      }
      return this;
    },

  // remove an event handler
  removeHandler =
    function(element, type, handler, capture) {
      var i, k, l, types;
      if (typeof type == 'string') {
        types = type.split(' ');
        for (i = 0, l = types.length; i < l; i++) {
          k = isRegistered(Handlers, element, types[i], handler, capture);
          if (k !== false) {
            removeEvent(element, types[i], Handlers[types[i]].wraps[k], capture, k);
            removeItem(Handlers, types[i], k);
          }
        }
      } else {
        // a hash of "rules" containing type-handler pairs
        for (i in type) {
          removeHandler(element, i, type[i], capture);
        }
      }
      return this;
    },

  // append an event listener
  appendListener =
    function(element, type, handler, capture) {
      var i, k, l, types;
      if (typeof type == 'string') {
        types = type.split(' ');
        for (i = 0, l = types.length; i < l; i++) {
          k = isRegistered(Listeners, element, types[i], handler, capture);
          if (k === false) {
            appendItem(Listeners, element, types[i], handler, capture);
            if (getRegistered(element, types[i], Listeners).length === 1) {
              appendHandler(element, types[i], handleListeners, capture);
            }
          }
        }
      } else {
        // a hash of "rules" containing type-handler pairs
        for (i in type) {
          appendListener(element, i, type[i], capture);
        }
      }
      return this;
    },

  // remove an event listener
  removeListener =
    function(element, type, handler, capture) {
      var i, k, l, types;
      if (typeof type == 'string') {
        types = type.split(' ');
        for (i = 0, l = types.length; i < l; i++) {
          k = isRegistered(Listeners, element, types[i], handler, capture);
          if (k !== false) {
            if (getRegistered(element, types[i], Listeners).length === 1) {
              removeHandler(element, types[i], handleListeners, capture);
            }
            removeItem(Listeners, types[i], k);
          }
        }
      } else {
        // a hash of "rules" containing type-handler pairs
        for (i in type) {
          removeListener(element, i, type[i], capture);
        }
      }
      return this;
    },

  // append an event delegate
  appendDelegate =
    // with iframes pass a delegate parameter
    // "delegate" defaults to documentElement
    function(selector, type, handler, delegate) {
      var i, j, k, l, types;
      if (typeof selector == 'string') {
        types = type.split(' ');
        delegate = delegate || root;
        for (i = 0, l = types.length; i < l; i++) {
          k = isRegistered(Delegates, selector, types[i], handler, delegate);
          if (k === false) {
            appendItem(Delegates, selector, types[i], handler, delegate);
            if (Delegates[types[i]].items.length === 1) {
              appendListener(delegate, types[i], handleDelegates, true);
            }
          }
        }
      } else {
        // a hash of "rules" containing selector-event-handler
        for (i in selector) {
          if (typeof i == 'string') {
            for (j in selector[i]) {
              appendDelegate(i, j, selector[i][j]);
            }
          }
        }
      }
      return this;
    },

  // remove an event delegate
  removeDelegate =
    // with iframes pass a delegate parameter
    // "delegate" defaults to documentElement
    function(selector, type, handler, delegate) {
      var i, j, k, l, types;
      if (typeof type == 'string') {
        types = type.split(' ');
        delegate = delegate || root;
        for (i = 0, l = types.length; i < l; i++) {
          k = isRegistered(Delegates, selector, types[i], handler, delegate);
          if (k !== false) {
            if (Delegates[types[i]].items.length === 1) {
              removeListener(delegate, types[i], handleDelegates, true);
            }
            removeItem(Delegates, types[i], k);
          }
        }
      } else {
        // hash of "rules" containing selector-event-handler
        for (i in selector) {
          if (typeof i == 'string') {
            for (j in selector[i]) {
              removeDelegate(i, j, selector[i][j]);
            }
          }
        }
      }
      return this;
    },

  // programatically dispatch native or custom events
  dispatch = root.dispatchEvent ?
    // W3C event model
    function(element, type, capture) {
      var event, d = getDocument(element), w = getWindow(d);
      if (/mouse|click/.test(type)) {
        try {
          event = d.createEvent('MouseEvents');
          event.initMouseEvent(type, true, true, w, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        } catch(e) {
          event = d.createEvent('HTMLEvents');
          event.initEvent(type, true, true);
        }
      } else if (/key(down|press|out)/.test(type)) {
        event = d.createEvent('KeyEvents');
        event.initKeyEvent(type, true, true, w, false, false, false, false, 0, 0);
      } else {
        event = d.createEvent('HTMLEvents');
        event.initEvent(type, true, true);
      }
      // dispatch event type to element
      return element.dispatchEvent(event);
    } : root.fireEvent ?
    // IE event model
    function(element, type, capture) {
      var event, d = getDocument(element);
      event = d.createEventObject();
      event.type = type;
      event.target = element;
      event.eventPhase = 0;
      event.currentTarget = element;
      event.cancelBubble= !!capture;
      event.returnValue= undefined;
      // fire event type on element
      return element.fireEvent('on' + type, fixEvent(element, event, capture));
    } :
    // try manual dispatch
    function(element, type, capture) {
      // (TODO)
    },

  /* =========================== EVENT PROPAGATION ========================== */

  //
  // known available activation events:
  //
  // Internet Explorer:
  //   focusin, focusout, activate, deactivate,
  //   beforeactivate, beforedeactivate
  //
  // FF/Opera/Safari/K:
  //   DOMActivate, DOMFocusIn, DOMFocusOut
  //
  // DOM0/1 and inline:
  //   focus, blur
  //
  // we use just a few of them to emulate the capturing
  // and bubbling phases of the focus and blur events
  // where not available or named/used differently
  //
  ActivationMap = {
    'blur': 'blur',
    'focus': 'focus',
/*
    'focusin': 'focus',
    'focusout': 'blur',
    'activate': 'focus',
    'deactivate': 'blur',
    'DOMFocusIn': 'focus',
    'DOMFocusOut': 'blur',
*/
    'beforeactivate': 'focus',
    'beforedeactivate': 'blur'
  },

  FormActivationEvents = {
    blur: 1,
    focus: 1,
    reset: 1,
    submit: 1,
    change: 1
  },

  FormAction = 'keydown mousedown',
  Activation = context.addEventListener ?
    'focus blur' : 'beforeactivate beforedeactivate',

  // create a synthetic event
  synthesize =
    function(element, type, capture) {
      return {
        type: type,
        target: element,
        bubbles: true,
        cancelable: true,
        currentTarget: element,
        relatedTarget: null,
        timeStamp: +new Date(),
        preventDefault: preventDefault,
        stopPropagation: stopPropagation,
        eventPhase: capture ? CAPTURING_PHASE : BUBBLING_PHASE
      };
    },

  // propagate events traversing the
  // ancestors path in both directions
  propagate =
    function(event) {
      var result = true, target = event.target, type = event.type;
      // execute the capturing phase
      result && (result = propagatePhase(target, type, true));
      // execute the bubbling phase
      result && (result = propagatePhase(target, type, false));
      // remove the trampoline event
      removeHandler(target, type, propagate, false);
      // submit/reset events relayed to parent forms
      if (target.form) { target = target.form; }
      // execute existing native methods if not overwritten
      result && isNative(target, type) && target[type]();
      // return flag
      return result;
    },

  // propagate event capturing or bubbling phase
  propagatePhase =
    function(element, type, capture) {
      var i, l,
        result = true,
        node = element, ancestors = [],
        event = synthesize(element, type, capture);
      // add synthetic flag
      event.propagated=true;
      // collect ancestors
      while(node.nodeType == 1) {
        ancestors.push(node);
        node = node.parentNode;
      }
      // capturing, reverse ancestors collection
      if (capture) ancestors.reverse();
      // execute registered handlers in fifo order
      for (i = 0, l = ancestors.length; l > i; i++) {
        // set currentTarget to current ancestor
        event.currentTarget = ancestors[i];
        // set eventPhase to the requested phase
        event.eventPhase = capture ? CAPTURING_PHASE : BUBBLING_PHASE;
        // execute listeners bound to this ancestor and set return value
        if (handleListeners.call(ancestors[i], event) === false || event.returnValue === false) {
          result = false;
          break;
        }
      }
      // remove synthetic flag
      delete event.propagated;
      return result;
    },

  // propagate activation events
  // captured/emulated activations
  // only applied to form elements
  propagateActivation =
    function(event) {
      var result = true, target = event.target;
      result && (result = propagatePhase(target, ActivationMap[event.type], true));
      result && (result = propagatePhase(target, ActivationMap[event.type], false));
      result || (event.preventDefault ? event.preventDefault() : (event.returnValue = false));
      return result;
    },

  // propagate form action events
  // mousedown and keydown events
  // only applied to form elements
  propagateFormAction =
    function(event) {
      var target = event.target, type = target.type;
      // handle activeElement on context document
      if (target != context.activeElement) {
        if (!hasActive && target.nodeType == 1) {
          context.activeElement = target;
          context.focusElement = null;
        }
      }
      // html form elements only
      if (type) {
        // handle focusElement on context document
        if (target != context.focusElement) {
          if (!hasActive) {
            context.focusElement = target;
          }
        }
        // keydown or mousedown on form elements
        if (/file|text|password/.test(type) &&
          event.keyCode == 13 && target.form) {
          type = 'submit';
          target = target.form;
        } else if (/select-(one|multi)/.test(type)) {
          type = 'change';
        } else if (/reset|submit/.test(type) && target.form) {
          target = target.form;
        } else {
          // action was on a form element but
          // no extra processing is necessary
          return;
        }
        appendHandler(target, type, propagate, false);
      }
    },

  // enable event propagation
  enablePropagation =
    function(context) {
      if (!context.forcedPropagation) {
        context.forcedPropagation = true;
        // deregistration on page unload
        appendHandler(getWindow(context), 'unload',
          function(event) {
            disablePropagation(context);
            // we are removing ourself here, so do it as last
            removeHandler(this, 'unload', arguments.callee, false);
          }, false);
        // register capturing keydown and mousedown event handlers
        appendHandler(context, FormAction, propagateFormAction, true);
        // register emulated capturing focus and blur event handlers
        appendHandler(context, Activation, propagateActivation, true);
      }
    },

  // disable event propagation
  disablePropagation =
    function(context) {
      if (context.forcedPropagation) {
        context.forcedPropagation = false;
        // deregister capturing keydown and mousedown event handlers
        removeHandler(context, FormAction, propagateFormAction, true);
        // deregister emulated capturing focus and blur event handlers
        removeHandler(context, Activation, propagateActivation, true);
      }
    },

  /* ========================== DOM CONTENT LOADED ========================== */

  //
  // available loading notification events:
  //
  // HTML5 + DOM2 FF/Opera/Safari/K:
  //   DOMContentLoaded, DOMFrameContentLoaded, onload
  //
  // MS Internet Explorer 6, 7 and 8:
  //   readyState, onreadystatchange, onload
  //
  // DOM0/1 and inline:
  //   onload
  //
  // we use a bad browser sniff just to find out the best
  // implementation/fallback for each of the old browsers
  // to support the standard HTML5 DOMContentLoaded event
  // http://www.whatwg.org/specs/web-apps/current-work/#the-end
  //

  isReady = false,

  readyHandlers = new EventCollection,

  onDOMReady =
    function(host, callback, scope) {
      if (isReady) {
        callback.call(scope);
      } else {
        var k = isRegistered(readyHandlers, host, 'ready', callback, null);
        if (k === false) {
          appendItem(readyHandlers, host, 'ready', callback, null);
        } else {
          throw new Error('NWEvents: duplicate ready handler for host: ' + host);
        }
      }
    },

  ready =
    function(host, callback, scope) {
      isReady = true;
      if (readyHandlers['ready'] && readyHandlers['ready'].items) {
        var i, length = readyHandlers['ready'].items.length;
        for (i = 0; length > i; ++i) {
          readyHandlers['ready'].calls[i].call(scope);
        }
      }
    },

  // Cross-browser wrapper for DOMContentLoaded
  // http://javascript.nwbox.com/ContentLoaded/ +
  // http://javascript.nwbox.com/IEContentLoaded/
  contentLoaded =
    function(host, callback, scope) {

      var done = false, size = 0,
        document = host.document,
        W3Type = 'DOMContentLoaded',
        MSType = 'onreadystatechange',
        root = document.documentElement;

      function init(event) {
        if (!done) {
          done = true;
          callback.call(scope, event);
        }
      }

      // W3C Event model
      if (document.addEventListener) {

        // browsers having native DOMContentLoaded
        function DOMContentLoaded(event) {
          document.removeEventListener(event.type, DOMContentLoaded, false);
          init(event);
        }
        document.addEventListener(W3Type, DOMContentLoaded, false);

        // onload fall back for older browsers
        host.addEventListener('load', DOMContentLoaded, false);

      // MSIE Event model (all versions)
      } else if (document.attachEvent) {

        function IEContentLoaded(event) {
          document.detachEvent(MSType, IEContentLoaded);
          function poll() {
            try {
              // throws errors until after ondocumentready
              root.doScroll('left');
              size = root.outerHTML.length;
              if (size * 1.03 < d.fileSize * 1) {
                return !done && setTimeout(poll, 50);
              }
            } catch (e) {
              return !done && setTimeout(poll, 50);
            }
            init({ type: 'poll' });
            return done;
          }
          poll();
        }
        document.attachEvent(MSType, IEContentLoaded);

        function IEReadyState(event) {
          if (document.readyState == 'complete') {
            document.detachEvent(MSType, IEReadyState);
            init(event);
          }
        }
        document.attachEvent(MSType, IEReadyState);
        document.attachEvent('load', IEReadyState);

      // fallback to last resort for older browsers
      } else {

        // from Simon Willison
        var oldonload = host.onload;
        host.onload = function (event) {
          init(event || host.event);
          if (typeof oldonload == 'function') {
            oldonload(event || host.event);
          }
        };

      }
    };

  // inititalize the activeElement
  // to a known cross-browser state
  if (!hasActive) {
    context.activeElement = root;
  }

  // initialize context propagation
  if (!context.forcedPropagation) {
    enablePropagation(context);
  }

  // initialize global ready event
  contentLoaded(global, ready);

  return {

    // controls the type of registration
    // for event listeners (DOM0 / DOM2)
    USE_DOM2: USE_DOM2,

    // exposed event methods

    stop: stop,

    dispatch: dispatch,

    onDOMReady: onDOMReady,

    contentLoaded: contentLoaded,

    getRegistered: getRegistered,

    appendHandler: appendHandler,

    removeHandler: removeHandler,

    appendListener: appendListener,

    removeListener: removeListener,

    appendDelegate: appendDelegate,

    removeDelegate: removeDelegate,

    // helpers and debugging functions

    enablePropagation: enablePropagation,

    disablePropagation: disablePropagation

  };

})(this);


NW.Dom = {
	match: SJS.match
};

// Requires Core, Selecting

/* Function g(String id)
 * Gets an element by its id. Returns $null$ if such an element does not exist.
 $ g('test').animate('background', 'blue') // animates the background of #test to blue
 * Function g(Element el)
 * Returns <el>. If needed, all <Element> functions are added to <el> first.
 $ g(document.getElementById('test'))
 $ // -> same as g('test') if the browser correctly supports document.getElementById.
 */
window.g = function(id) {
	var r = SJS.isString(id) ? SJS.byId(id) : id,
		i;
	if(!SJS.Features.Element)
		for(i in window.Element.prototype)
			if(window.Element.prototype.hasOwnProperty(i)) {
				if(i in r)
					continue;
				r[i] = window.Element.prototype[i];
			}
	return r;
};

SJS.extend(SJS.Features, {
	/* Object SJS.Features.Element
	 * Boolean indicating wether the browser natively supports the <Element> object.
	 */
	Element: !!window.Element
});

SJS.extend(SJS, {
	colorParsers: [
		function(color) {
			if(!SJS.isString(color))
				return;
			var match = color.match(/(rgb\(\d+,\s?\d+,\s?\d+\))|(rgba\(\d+,\s?\d+,\s?\d+,\s?\d+(\.\d+)?\))/);
			if(!match)
				return;
			match = match[0].substr(match[0].charAt(3) === 'a' ? 5 : 4).split(',');
			for(var i = 0, len = match.length; i < len; i++)
				match[i] = parseFloat(match[i].trim());
			return match;
		},
		function(color) {
			if(!SJS.isString(color))
				return;
			var match = color.match(/#[a-z0-9]{3,6}/i);
			if(match)
				return match[0].hex2rgb();
		}
	],
	parseColor: function(color) {
		if(SJS.isString(color)) {
			var parts = color.split('-'),
				main,
				alpha;
			SJS.each(SJS.colorParsers, function(parser) {
				main = parser(parts[0]);
				return SJS.isNull(main);
			});
			if(SJS.isNull(main))
				return color;
			alpha = parseFloat(parts[1]);
			if(!isNaN(alpha))
				main[3] = alpha;
			return main;
		}
		return color;
	}
});

/* Function Element
 * DOM Elements should have all elements from this object's prototype on them.
 * When you call <g> or <_> on a DOM element, those functions are (if needed) added to it.
 * All SJS functions that return an element, have that element also contain the Element functions.
 * Function Element(DOMElement el):
 * Function Element(String id): Alias of <g>.
 */
if(!SJS.Features.Element)
	window.Element = window.g;
if(!window.Element.prototype)
	window.Element.prototype = {};

/* Function Elements
 * All SJS Elements objects, as for example returned by <_>, have this function's prototype on them.
 * Function Elements(String query, Array elements)
 * Constructor returning an Elements object.
 * This function does not actually query the DOM for <query>, but rather stores it on the returned element for usage by, for example, <Elements#live>.
 * If needed, the <Element> prototype functions are added to each element in <elements>.
 $ new Elements('.test', document.getElementsByClassName('test'))
 $ // -> same as _('.test'), as long as the browser supports getElementsByClassName
 */
window.Elements = SJS.Features.Element ? function(query, els) {
	this.query = query;
	this.length = 0;
	if(els && els.length)
		Array.prototype.splice.apply(this, [0, 0].concat(els));
} : function(query, els) {
	var i = 0, len = els ? els.length : 0, j;
	for(; i < len; i++) {
		this[i] = els[i];
		for(j in window.Element.prototype)
			this[i][j] = window.Element.prototype[j];
	}
	this.query = query;
	this.length = i;
};
SJS.implement(window.Elements, {
	push: SJS.Features.Element ? function(el) {
		this[this.length++] = el;
	} : function(el) {
		var len = this.length;
		this[len] = el;
		for(var i in window.Element.prototype) {
			if(i in this[len])
				continue;
			this[len][i] = window.Element.prototype[i];
		}
		this.length++;
	},
	sort: Array.prototype.sort,
	/* Function Elements#queryOf()
	 * Returns the original query of the Elements object.
	 $ var value = _('.foo#bar');
	 $ value.queryOf() // -> '.foo#bar'
	 $ value = value._('div');
	 $ value.queryOf() // -> '.foo#bar div'
	 */
	queryOf: function() {
		return this.query;
	},
	/* Function Elements#_(String query)
	 * Queries for <query> in every element in the Elements object and returns a new Elements object containing the elements found.
	 $ var value = _('.foo');
	 $ value._('#bar div') // -> same as _('.foo #bar div') if the DOM didn't change
	 */
	_: function(v) {
		return SJS.searchEach(v, this, this.query + ' ' + (v || '*'));
	},
	/* Function Elements#each(Function fn, Object context)
	 * Iterates through the elements, like <SJS.each>.
	 */
	each: function(fn, context) {
		return SJS.each(this, fn, context);
	},
	/* Functions Elements#filter(String query)
	 * Returns a new <Elements> object containing all elements in the elements object matching <query>.
	 */
	filter: function(query) {
		return new window.Elements(this.queryOf() + ':matches(' + query + ')', SJS.filter(this, function(el) {
			return el.match(query);
		}));
	}
});

SJS.extend(SJS, {
	alias: function(orig, alias) {
		return SJS.each(['Element', 'Elements'], function(c) {
			SJS.implement(window[c], alias, window[c].prototype[orig]);
		});
	},
	live: function(q, obj, fn) {
		if(fn) {
			var name = obj;
			obj = {};
			obj[name] = fn;
		}
		SJS.each(obj, function(name, fn) {
			window.document.bind(name, function(evt, collection, type) {
				if(window.Element.prototype.match.call(this, q))
					fn.call(this, evt, this, type);
			});
		});
		return this;
	}
});

SJS.implement(window.Element, {
	/* Function Element#queryOf()
	 * Returns a string that
	 * - is unique for the element
	 * - matches the element
	 $ var el = g('test');
	 $ el.queryOf() // -> '#test', asuming it exists
	 $ el = el.parent();
	 $ el.queryOf() // -> '.sjs-uniqclass-6319', or another unique class
	 */
	queryOf: function() {
		if(this.query)
			return this.query;
		if(this.id)
			return '#' + this.id;
		var classes = this.classes(),
			sjsUniqclass;
		if(SJS.filter(classes, function(el) {
			if(el.substr(0, 14) === 'sjs-uniqclass-') {
				sjsUniqclass = el;
				return true;
			}
		}).length)
			return '.' + sjsUniqclass;
		else {
			do
				sjsUniqclass = '.sjs-uniqclass-' + Math.round(Math.random() * 100000);
				while(_(sjsUniqclass).length);
			this.addClass(sjsUniqclass.substr(1));
			return sjsUniqclass;
		}
	},
	toElement: function() {
		return this;
	},
	/* Function Element#_(String query)
	 * Returns elements matching <query> in the element.
	 $ var value = g('test');
	 $ value._('div') // -> divs in #test
	 */
	_: function(v) {
		var q = this.queryOf() + ' ' + v;
		return SJS.search(v, this, q);
	},
	/* Function Element#getFirst(String query)
	 * Returns the first element in the element matching <query>.
	 $ var value = g('test');
	 $ value.getFirst('div') // -> first div in #test
	 */
	getFirst: function(q) {
		return SJS.find(q, this);
	},
	/* Function Element#getLast(String query)
	 * Returns the last element in the element matching <query>.
	 $ var value = g('test');
	 $ value.getLast('div') // -> last div in #test
	 */
	getLast: function(q) {
		var r = SJS.search(q, this);
		return window.g(r[r.length - 1]);
	},
	/* Function Element#html()
	 * Returns the inner html of the element.
	 $ var value = g('test');
	 $ value.html() // -> the html in #test
	 * Function Element#html(String html)
	 * Sets the inner html of the element to <html>.
	 $ var value = g('test');
	 $ value.html('<div>hi</div>') // -> clears #test and puts a div saying 'hi' in it.
	 */
	html: function(val) {
		if(SJS.isNull(val))
			return this.innerHTML;
		this.innerHTML = val;
		return this;
	},
	/* Function Element#prepend(Element el)
	 * Prepends <el> to the beginning of the element.
	 $ var value = g('foo');
	 $ value.prepend(g('bar')) // -> moves #bar to the beginning of #foo
	 * Function Element#prepend(String html)
	 * Prepends <html> to the beginning of the element.
	 $ var value = g('foo')
	 $ value.prepend('<div>bar</div>') // -> adds a div saying bar before #foo's contents
	 */
	prepend: function(html) {
		this.insertBefore(html.toElement(), this.firstChild);
		return this;
	},
	/* Function Element#append(Element el)
	 * Appends <el> to the end of the element.
	 $ var value = g('foo');
	 $ value.append(g('bar')) // -> moves #bar to the end of #foo
	 * Function Element#append(String html)
	 * Appends <html> to the end of the element.
	 $ var value = g('foo')
	 $ value.append('<div>bar</div>') // -> adds a div saying bar after #foo's contents
	 */
	append: function(html) {
		this.appendChild(html.toElement());
		return this;
	},
	/* Function Element#text()
	 * Returns the text in the element.
	 $ '<div>foo</div>'.toElement().text() // -> foo
	 $ var value = g('bar');
	 $ value.text() // -> inner text of #bar
	 * Function Element#text(String text)
	 * <Encodes @ String#htmlSpecialChars> html characters in <text> and sets that as the element's html.
	 $ var value = g('foo');
	 $ foo.text('To create a paragraph, use <p>.') // '<' and '>' are encoded first
	 */
	text: function(text) {
		return SJS.isNull(text) ? this.textContent || this.innerText.replace(rnReturn, '') : this.html(text.htmlSpecialChars());
	},
	/* Function Element#prependText(String text)
	 * Prepends <text> at the beginning of the element.
	 * Special html characters are encoded.
	 */
	prependText: function(text) {
		this.insertBefore(document.createTextNode(text), this.firstChild);
		return this;
	},
	/* Function Element#appendText(String text)
	 * Appends <text> after everything in the element.
	 * Special html characters are encoded.
	 */
	appendText: function(text) {
		this.appendChild(document.createTextNode(text));
		return this;
	},
	/* Function Element#before(String html)
	 * Adds <html> before the element.
	 $ <div id="test">foo</div>
	 * ...
	 $ g('test').before('<div>bar</div>'); // -> <div>bar</div><div id="test">foo</div>
	 */
	before: function(html) {
		this.parent().insertBefore(html.toElement(), this);
		return this;
	},
	/* Function Element#after(String html)
	 * Adds <html> after the element.
	 $ !html <div id="test">foo</div>
	 * ...
	 $ g('test').after('<div>bar</div>'); // -> <div id="test">foo</div><div>bar</div>
	 */
	after: function(html) {
		this.parent().insertBefore(html.toElement(), this.next() || null); // null for IE
		return this;
	},
	/* Function Element#remove()
	 * Removes an element from the DOM.
	 $ var el = g('test');
	 $ el.remove(); // -> removes #test
	 */
	remove: function() {
		var parent = this.parent()
		if(!SJS.isNull(parent))
			parent.removeChild(this);
	},
	/* Function Element#live(String event, Function handler)
	 * Adds a delegate for <event>.
	 * When an event
	 * - bubbles all the way up to $window$
	 * - is fired on an element matching the <query of @ Element#queryOf> the original element
	 * <handler> is called.
	 $ var clickHandler = function() {
	 $   alert('Click!');
	 $ };
	 $ $('.test').live('click', clickHandler);
	 $ // On a click on an element with .test, 'Click!' is alerted.
	 */
	live: function(obj, fn) {
		_.live(this.queryOf(), obj, fn);
		return this;
	},
	/* Function Element#val()
	 * Returns the value of the element.
	 $ !html <input type="text" id="text" /> <!-- user typed in 'test' -->
	 $ <select>
	 $   <option value="1">1</option>
	 $   <option value="2">2</option> <!-- someone selected '2' -->
	 $ </select>
	 $ <select multiple>
	 $   <option value="1">1</option>
	 $   <option value="2">2</option> <!-- someone selected '2' -->
	 $   <option value="3">3</option> <!-- and also '3' -->
	 $ </select>
	 * ...
	 $ g('text').val() // -> 'test'
	 $ g('select').val() // -> '2'
	 $ g('multiple').val() // -> ['2', '3']
	 * Note: if you call val on a multiple select element with only one element selected, val also returns an array.
	 * Function Element#val(String value)
	 * Sets the value of the element to <value>.
	 * If the element is a select element, all options in it that match <value> are selected.
	 */
	val: function(value) {
		if(this.match('select')) {
			if(value) {
				SJS.each(this._('option'), function(el, i) {
					el.selected = el.value == value;
				});
			} else {
				var r;
				if(this.multiple)
					r = [];
				SJS.each(this._('option'), function(el, i) {
					if(this.multiple) {
						if(el.selected)
							r.push(el.value);
					} else {
						if(r)
							return;
						if(el.selected)
							r = el.value;
					}
				}, this);
				return r;
			}
		} else {
			if(!value)
				return this.value;
			this.value = value;
			return this;
		}
	},
	/* Function Element#attr(String name)
	 * Returns the attribute <name> of the element.
	 $ !html <select multiple id="multi"></select>
	 $ <input id="foo" name="bar"></input>
	 * ...
	 $ g('multi').attr('multiple') // -> true
	 $ g('foo').attr('name') // -> 'bar'
	 * Function Element#attr(String name, String | Bool value)
	 * Sets the attribute <name> of the element to <value>.
	 * Note: setting attributes like 'multiple' to false with this method won't work. Use <Element#removeAttr> instead.
	 $ !html <input id="foo" name="bar"></input>
	 * ...
	 $ g('foo').attr('name', 'newname') // -> change #foo's name attribute
	 */
	attr: function(key, val) {
		var isArray = SJS.isArray(key);
		if(isArray || SJS.isPlainObject(key)) {
			SJS.each(key, function(k, v) {
				this.attr(k, isArray ? val : v);
			}, this);
		}
		var rewrites = {
			'class': 'className',
			'for': 'htmlFor',
			'colpan': 'colSpan',
			'rowspan': 'rowSpan'
		};
		if(SJS.isNull(val)) {
			if(SJS.hasOwn(rewrites, key.toLowerCase()))
				key = rewrites[key];
			return this[key] || this.getAttribute(key);
		}
		else {
			if(!SJS.isString(key)) return this;
			if(['href', 'src'].contains(key))
				this[key] = val;
			else if(key === 'style')
				this.style.cssText = val;
			else {
				if(SJS.hasOwn(rewrites, key.toLowerCase()))
					this[rewrites[key]] = val;
				else
					this.setAttribute(key, val);
			}
			return this;
		}
	},
	/* Function Element#removeAttr(String name)
	 * Removes attribute <name> from the element.
	 $ !html <select multiple id="multi"></select>
	 * ...
	 $ g('multi').removeAttr('multiple') // -> #multi is no longer multiple
	 */
	removeAttr: function(name) {
		if(!SJS.isString(name)) return this;
		var rewrites = {
			'class': 'className',
			'for': 'htmlFor',
			'colpan': 'colSpan',
			'rowspan': 'rowSpan'
		};
		if(['href', 'src'].contains(name))
			this[name] = null;
		else if(SJS.hasOwn(rewrites, name.toLowerCase()))
			this[rewrites[name]] = null;
		else
			this.removeAttribute(name);
		return this;
	},
	/* Function Element#addClass(String class1, String class2, ...)
	 * Function Element#addClass(Array classes, Array moreClasses, ...)
	 * Adds one or more classes to the element.
	 $ !html <div id="foo" class="bar"></div>
	 * ...
	 $ g('foo').addClass('baz') // -> class="bar baz"
	 $ g('foo').addClass('bar') // -> class="bar baz"
	 $ g('foo').addClass('foo', 'baz') // -> class="bar baz foo"
	 */
	addClass: function() {
		var classes = this.className.split(' ');
		SJS.each(SJS.flatten(arguments), function(c) {
			classes = classes.concat(c.split(' '));
		});
		this.className = SJS.filter(classes).join(' ');
		return this;
	},
	/* Function Element#removeClass(String class1, String class2, ...)
	 * Function Element#removeClass(Array classes, Array moreClasses, ...)
	 * Removes one or more classes from the element.
	 $ !html <div id="foo" class="foo bar baz test"></div>
	 * ...
	 $ g('foo').removeClass('baz') // -> class="foo bar test"
	 $ g('foo').addClass('bar', 'foo') // -> class="test"
	 $ g('foo').addClass(['bla', 'test'], 'another') // -> class=""
	 */
	removeClass: function() {
		var classes = this.className.split(' ');
		SJS.each(SJS.flatten(arguments), function(c) {
			SJS.each(c.split(' '), function(c) {
				classes = SJS.without(classes, classes.indexOf(c));
			});
		});
		this.className = SJS.filter(classes).join(' ');
		return this;
	},
	/* Function Element#hasClass(String className)
	 * Retuns a bool indicating whether the element has a class matching <className>.
	 */
	hasClass: function(className) {
		return this.classes().contains(className);
	},
	/* Function Element#classes()
	 * Returns an array of all classes of the element.
	 */
	classes: function() {
		return this.className.split(' ');
	},
	computedStyle: function() {
		return document.defaultView && document.defaultView.getComputedStyle
			? function(style, tryCss) {
				var r;
				if(tryCss)
					r = this.css(style);
				if(!r)
					r = document.defaultView.getComputedStyle(this, null).getPropertyValue(style.caps2dashes());
				r = SJS.parseColor(r);
				return r;
			}
			: function(style, tryCss) {
				var r;
				if(tryCss)
					r = this.css(style);
				if(!r)
					r = this.currentStyle[style];
				r = SJS.parseColor(r);
				if(SJS.isNull(r) || r === 'auto') {
					switch(style) {
						case 'width':	return this.offsetWidth;
						case 'height':	return this.offsetHeight;
						case 'opacity':	return 1;
					}
				}
				return r;
			};
	}(),
	/* Function Element#css(String property)
	 * Returns the element's $style[<property>]$.
	 $ !html <div id="test" style="background: blue"></div>
	 * ...
	 $ g('test').css('background') // -> 'blue'
	 * Function Element#css(String property, String | Number value)
	 * Sets the element's $style[<property>]$ to <value>.
	 $ !html <div id="test"></div>
	 * ...
	 $ g('test').css('background', 'blue') // -> style="background: blue"
	 * Function Element#css(Array properties)
	 * Returns an object ('hash') containing <properties> as keys and the style as values.
	 $ !html <div id="test" style="background: blue; padding: 5px"></div>
	 * ...
	 $ g('test').css(['background', 'padding'])
	 $ // -> {
	 $ //   background: 'blue',
	 $ //   padding: '5px'
	 $ // }
	 * Function Element#css(Object styles)
	 * Extends the element's style with <styles>.
	 $ !html <div id="test"></div>
	 * ...
	 $ g('test').css({
	 $   background: 'blue',
	 $   padding: '5px'
	 $ }) // -> sets a background and padding
	 */
	css: function(key, val) {
		if(SJS.isArray(key)) {
			if(SJS.isNull(val)) {
				var ret = {};
				SJS.each(key, function(el) {
					ret[el] = this.css(el);
				}, this);
				return ret;
			}
			else
				SJS.each(key, function(el) {
					this.css(el, val);
				}, this);
		}
		else {
			if(SJS.isNull(val) && !SJS.isPlainObject(key))
				return this.style[key];
			SJS.each(SJS.toObject(key, val), function(k, v) {
				this.style[k] = SJS.isNumber(v) ? v + 'px' : v;
			}, this);
		}
		return this;
	},
	/* Function Element#parent()
	 * Returns an element's parent.
	 $ !html <div id="foo"><div id="bar"><div id="baz"></div></div></div>
	 * ...
	 $ g('baz').parent().parent() // -> Element #foo
	 */
	parent: function() {
		return g(this.parentNode);
	},
	/* Function Element#prev()
	 * Gets the element before the current element.
	 $ !html <div id="foo"></div><div id="bar"></div>
	 * ...
	 $ g('bar').prev() // -> Element #foo
	 */
	prev: function() {
		return this.getFirst('!+ *')[0];
	},
	/* Function Element#next()
	 * Gets the element after the current element.
	 $ !html <div id="foo"></div><div id="bar"></div>
	 * ...
	 $ g('foo').next() // -> Element #bar
	 */
	next: function() {
		return this.getFirst('+ *');
	}
});

SJS.extend(window.Elements, {
	implementBoth: function(names, i) {
		if(!i) i = 0;
		SJS.each(SJS.toArray(names), function(name) {
			SJS.implement(window.Elements, name, function() {
				var args = arguments;
				if(args.length > i)
					return SJS.each(this, function(el) {
						window.Element.prototype[name].apply(el, args);
					});
				else
					return window.Element.prototype[name].apply(this[0], args);
			});
		});
	},
	implementEach: function() {
		SJS.each(SJS.flatten(arguments), function(name) {
			SJS.implement(window.Elements, name, function() {
				var args = arguments;
				return SJS.each(this, function(el) {
					window.Element.prototype[name].apply(el, args);
				});
			});
		});
	},
	implementSame: function() {
		SJS.each(SJS.flatten(arguments), function(name) {
			SJS.implement(window.Elements, name, function() {
				return window.Element.prototype[name].apply(this, arguments);
			});
		});
	}
});

window.Elements.implementBoth(['html', 'text']);
window.Elements.implementBoth('css', 1);

window.Elements.implementEach('prepend', 'append', 'prependText', 'appendText', 'before', 'after', 'remove', 'addClass', 'removeClass');

/* Function Elements#getAll(String query)
 * Alias of <Elements#_>.
 */
SJS.alias('_', 'getAll');

// Requires Core, DOM

SJS.implement(window.Element, 'bind', function(event, fn) {
	var _this = this,
		ffn = function(evt) {
			if(!evt)
				evt = this;
			if(SJS.isFunction(fn))
				fn.call(evt.target, evt, _this, evt.type);
		};
	switch(event) {
		case 'ready':
			NW.Event.contentLoaded(this, ffn, this);
			break;
		case 'dblclick':
		case 'submit':
		case 'change':
			NW.Event.appendHandler(this, event, ffn, false);
			break;
		default:
			NW.Event.appendListener(this, event, ffn, false);
			break;
	}
	return this;
});
window.bind = window.document.bind = function(event, fn) {
	Element.prototype.bind.call(this, event, fn);
	return this;
};
SJS.each([
	'ready',
	'load',
	'mousedown',
	'mouseup',
	'click',
	'dblclick',
	'contextmenu',
	'mousemove',
	'keydown',
	'keyup',
	'keypress',
	'change'
], function(type) {
	SJS.implement(window.Element, type, window[type] = window.document[type] = function(fn) {
		return this.bind(type, fn);
	});
	window.Elements.implementEach(type);
});

window.Elements.implementEach('bind');
window.Elements.implementSame('live');

// Requires Core, DOM

(function(SJS) {
	var namedColors = {
		aqua: [0, 255, 255],
		azure: [240, 255, 255],
		beige: [245, 245, 220],
		black: [0, 0, 0],
		blue: [0, 0, 255],
		brown: [165, 42, 42],
		cyan: [0, 255, 255],
		darkblue: [0, 0, 139],
		darkcyan: [0, 139, 139],
		darkgrey: [169, 169, 169],
		darkgreen: [0, 100, 0],
		darkkhaki: [189, 183, 107],
		darkmagenta: [139, 0, 139],
		darkolivegreen: [85, 107, 47],
		darkorange: [255, 140, 0],
		darkorchid: [153, 50, 204],
		darkred: [139, 0, 0],
		darksalmon: [233, 150, 122],
		darkviolet: [148, 0, 211],
		fuchsia: [255, 0, 255],
		gold: [255, 215, 0],
		green: [0, 128, 0],
		indigo: [75, 0, 130],
		khaki: [240, 230, 140],
		lightblue: [173, 216, 230],
		lightcyan: [224, 255, 255],
		lightgreen: [144, 238, 144],
		lightgrey: [211, 211, 211],
		lightpink: [255, 182, 193],
		lightyellow: [255, 255, 224],
		lime: [0, 255, 0],
		magenta: [255, 0, 255],
		maroon: [128, 0, 0],
		navy: [0, 0, 128],
		olive: [128, 128, 0],
		orange: [255, 165, 0],
		pink: [255, 192, 203],
		purple: [128, 0, 128],
		violet: [128, 0, 128],
		red: [255, 0, 0],
		silver: [192, 192, 192],
		white: [255, 255, 255],
		yellow: [255, 255, 0]
	};
	
	SJS.colorParsers.push(function(color) {
		return namedColors[color];
	});
})(window.SJS);

// Standalone

/*
---
name: Slick.Parser
description: Standalone CSS3 Selector parser
provides: Slick.Parser
...
*/

;(function(){

var parsed,
	separatorIndex,
	combinatorIndex,
	reversed,
	cache = {},
	reverseCache = {},
	reUnescape = /\\/g;

var parse = function(expression, isReversed){
	if (expression == null) return null;
	if (expression.Slick === true) return expression;
	expression = ('' + expression).replace(/^\s+|\s+$/g, '');
	reversed = !!isReversed;
	var currentCache = (reversed) ? reverseCache : cache;
	if (currentCache[expression]) return currentCache[expression];
	parsed = {
		Slick: true,
		expressions: [],
		raw: expression,
		reverse: function(){
			return parse(this.raw, true);
		}
	};
	separatorIndex = -1;
	while (expression != (expression = expression.replace(regexp, parser)));
	parsed.length = parsed.expressions.length;
	return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
};

var reverseCombinator = function(combinator){
	if (combinator === '!') return ' ';
	else if (combinator === ' ') return '!';
	else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
	else return '!' + combinator;
};

var reverse = function(expression){
	var expressions = expression.expressions;
	for (var i = 0; i < expressions.length; i++){
		var exp = expressions[i];
		var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};

		for (var j = 0; j < exp.length; j++){
			var cexp = exp[j];
			if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
			cexp.combinator = cexp.reverseCombinator;
			delete cexp.reverseCombinator;
		}

		exp.reverse().push(last);
	}
	return expression;
};

var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
	return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
		return '\\' + match;
	});
};

var regexp = new RegExp(
/*
#!/usr/bin/env ruby
puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
__END__
	"(?x)^(?:\
	  \\s* ( , ) \\s*               # Separator          \n\
	| \\s* ( <combinator>+ ) \\s*   # Combinator         \n\
	|      ( \\s+ )                 # CombinatorChildren \n\
	|      ( <unicode>+ | \\* )     # Tag                \n\
	| \\#  ( <unicode>+       )     # ID                 \n\
	| \\.  ( <unicode>+       )     # ClassName          \n\
	|                               # Attribute          \n\
	\\[  \
		\\s* (<unicode1>+)  (?:  \
			\\s* ([*^$!~|]?=)  (?:  \
				\\s* (?:\
					([\"']?)(.*?)\\9 \
				)\
			)  \
		)?  \\s*  \
	\\](?!\\]) \n\
	|   :+ ( <unicode>+ )(?:\
	\\( (?:\
		(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
	) \\)\
	)?\
	)"
*/
	"^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
	.replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
	.replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
	.replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
);

function parser(
	rawMatch,

	separator,
	combinator,
	combinatorChildren,

	tagName,
	id,
	className,

	attributeKey,
	attributeOperator,
	attributeQuote,
	attributeValue,

	pseudoMarker,
	pseudoClass,
	pseudoQuote,
	pseudoClassQuotedValue,
	pseudoClassValue
){
	if (separator || separatorIndex === -1){
		parsed.expressions[++separatorIndex] = [];
		combinatorIndex = -1;
		if (separator) return '';
	}

	if (combinator || combinatorChildren || combinatorIndex === -1){
		combinator = combinator || ' ';
		var currentSeparator = parsed.expressions[separatorIndex];
		if (reversed && currentSeparator[combinatorIndex])
			currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
		currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
	}

	var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];

	if (tagName){
		currentParsed.tag = tagName.replace(reUnescape, '');

	} else if (id){
		currentParsed.id = id.replace(reUnescape, '');

	} else if (className){
		className = className.replace(reUnescape, '');

		if (!currentParsed.classList) currentParsed.classList = [];
		if (!currentParsed.classes) currentParsed.classes = [];
		currentParsed.classList.push(className);
		currentParsed.classes.push({
			value: className,
			regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
		});

	} else if (pseudoClass){
		pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
		pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;

		if (!currentParsed.pseudos) currentParsed.pseudos = [];
		currentParsed.pseudos.push({
			key: pseudoClass.replace(reUnescape, ''),
			value: pseudoClassValue,
			type: pseudoMarker.length == 1 ? 'class' : 'element'
		});

	} else if (attributeKey){
		attributeKey = attributeKey.replace(reUnescape, '');
		attributeValue = (attributeValue || '').replace(reUnescape, '');

		var test, regexp;

		switch (attributeOperator){
			case '^=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue)            ); break;
			case '$=' : regexp = new RegExp(            escapeRegExp(attributeValue) +'$'       ); break;
			case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
			case '|=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue) +'(-|$)'   ); break;
			case  '=' : test = function(value){
				return attributeValue == value;
			}; break;
			case '*=' : test = function(value){
				return value && value.indexOf(attributeValue) > -1;
			}; break;
			case '!=' : test = function(value){
				return attributeValue != value;
			}; break;
			default   : test = function(value){
				return !!value;
			};
		}

		if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
			return false;
		};

		if (!test) test = function(value){
			return value && regexp.test(value);
		};

		if (!currentParsed.attributes) currentParsed.attributes = [];
		currentParsed.attributes.push({
			key: attributeKey,
			operator: attributeOperator,
			value: attributeValue,
			test: test
		});

	}

	return '';
};

// Slick NS

var Slick = (this.Slick || {});

Slick.parse = function(expression){
	return parse(expression);
};

Slick.escapeRegExp = escapeRegExp;

if (!this.Slick) this.Slick = Slick;

}).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);


/*
---
name: Slick.Finder
description: The new, superfast css selector engine.
provides: Slick.Finder
requires: Slick.Parser
...
*/

;(function(){

var local = {},
	featuresCache = {},
	toString = Object.prototype.toString;

// Feature / Bug detection

local.isNativeCode = function(fn){
	return (/\{\s*\[native code\]\s*\}/).test('' + fn);
};

local.isXML = function(document){
	return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
	(document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
};

local.setDocument = function(document){

	// convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
	var nodeType = document.nodeType;
	if (nodeType == 9); // document
	else if (nodeType) document = document.ownerDocument; // node
	else if (document.navigator) document = document.document; // window
	else return;

	// check if it's the old document

	if (this.document === document) return;
	this.document = document;

	// check if we have done feature detection on this document before

	var root = document.documentElement,
		rootUid = this.getUIDXML(root),
		features = featuresCache[rootUid],
		feature;

	if (features){
		for (feature in features){
			this[feature] = features[feature];
		}
		return;
	}


	features = featuresCache[rootUid] = {};

	features.root = root;
	features.isXMLDocument = this.isXML(document);

	features.brokenStarGEBTN
	= features.starSelectsClosedQSA
	= features.idGetsName
	= features.brokenMixedCaseQSA
	= features.brokenGEBCN
	= features.brokenCheckedQSA
	= features.brokenEmptyAttributeQSA
	= features.isHTMLDocument
	= features.nativeMatchesSelector
	= false;

	var starSelectsClosed, starSelectsComments,
		brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
		brokenFormAttributeGetter;

	var selected, id = 'slick_uniqueid';
	var testNode = document.createElement('div');

	var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
	testRoot.appendChild(testNode);

	// on non-HTML documents innerHTML and getElementsById doesnt work properly
	try {
		testNode.innerHTML = '<a id="'+id+'"></a>';
		features.isHTMLDocument = !!document.getElementById(id);
	} catch(e){};

	if (features.isHTMLDocument){

		testNode.style.display = 'none';

		// IE returns comment nodes for getElementsByTagName('*') for some documents
		testNode.appendChild(document.createComment(''));
		starSelectsComments = (testNode.getElementsByTagName('*').length > 1);

		// IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
		try {
			testNode.innerHTML = 'foo</foo>';
			selected = testNode.getElementsByTagName('*');
			starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
		} catch(e){};

		features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;

		// IE returns elements with the name instead of just id for getElementsById for some documents
		try {
			testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
			features.idGetsName = document.getElementById(id) === testNode.firstChild;
		} catch(e){};

		if (testNode.getElementsByClassName){

			// Safari 3.2 getElementsByClassName caches results
			try {
				testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
				testNode.getElementsByClassName('b').length;
				testNode.firstChild.className = 'b';
				cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
			} catch(e){};

			// Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
			try {
				testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
				brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
			} catch(e){};

			features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
		}

		if (testNode.querySelectorAll){
			// IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
			try {
				testNode.innerHTML = 'foo</foo>';
				selected = testNode.querySelectorAll('*');
				features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
			} catch(e){};

			// Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
			try {
				testNode.innerHTML = '<a class="MiX"></a>';
				features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
			} catch(e){};

			// Webkit and Opera dont return selected options on querySelectorAll
			try {
				testNode.innerHTML = '<select><option selected="selected">a</option></select>';
				features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
			} catch(e){};

			// IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
			try {
				testNode.innerHTML = '<a class=""></a>';
				features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
			} catch(e){};

		}

		// IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
		try {
			testNode.innerHTML = '<form action="s"><input id="action"/></form>';
			brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
		} catch(e){};

		// native matchesSelector function


		features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
		if (features.nativeMatchesSelector) try {
			// if matchesSelector trows errors on incorrect sintaxes we can use it
			features.nativeMatchesSelector.call(root, ':slick');
			features.nativeMatchesSelector = null;
		} catch(e){};

	}

	try {
		root.slick_expando = 1;
		delete root.slick_expando;
		features.getUID = this.getUIDHTML;
	} catch(e) {
		features.getUID = this.getUIDXML;
	}

	testRoot.removeChild(testNode);
	testNode = selected = testRoot = null;

	// getAttribute

	features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
		var method = this.attributeGetters[name];
		if (method) return method.call(node);
		var attributeNode = node.getAttributeNode(name);
		return (attributeNode) ? attributeNode.nodeValue : null;
	} : function(node, name){
		var method = this.attributeGetters[name];
		return (method) ? method.call(node) : node.getAttribute(name);
	};

	// hasAttribute

	features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
		return node.hasAttribute(attribute);
	} : function(node, attribute) {
		node = node.getAttributeNode(attribute);
		return !!(node && (node.specified || node.nodeValue));
	};

	// contains
	// FIXME: Add specs: local.contains should be different for xml and html documents?
	features.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){
		return context.contains(node);
	} : (root && root.compareDocumentPosition) ? function(context, node){
		return context === node || !!(context.compareDocumentPosition(node) & 16);
	} : function(context, node){
		if (node) do {
			if (node === context) return true;
		} while ((node = node.parentNode));
		return false;
	};

	// document order sorting
	// credits to Sizzle (http://sizzlejs.com/)

	features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
		if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
		return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
	} : ('sourceIndex' in root) ? function(a, b){
		if (!a.sourceIndex || !b.sourceIndex) return 0;
		return a.sourceIndex - b.sourceIndex;
	} : (document.createRange) ? function(a, b){
		if (!a.ownerDocument || !b.ownerDocument) return 0;
		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
		aRange.setStart(a, 0);
		aRange.setEnd(a, 0);
		bRange.setStart(b, 0);
		bRange.setEnd(b, 0);
		return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
	} : null ;

	root = null;

	for (feature in features){
		this[feature] = features[feature];
	}
};

// Main Method

var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
	reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
	qsaFailExpCache = {};

local.search = function(context, expression, append, first){

	var found = this.found = (first) ? null : (append || []);

	if (!context) return found;
	else if (context.navigator) context = context.document; // Convert the node from a window to a document
	else if (!context.nodeType) return found;

	// setup

	var parsed, i,
		uniques = this.uniques = {},
		hasOthers = !!(append && append.length),
		contextIsDocument = (context.nodeType == 9);

	if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);

	// avoid duplicating items already in the append array
	if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;

	// expression checks

	if (typeof expression == 'string'){ // expression is a string

		/*<simple-selectors-override>*/
		var simpleSelector = expression.match(reSimpleSelector);
		simpleSelectors: if (simpleSelector) {

			var symbol = simpleSelector[1],
				name = simpleSelector[2],
				node, nodes;

			if (!symbol){

				if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;

				nodes = context.getElementsByTagName(name);
				if (first) return nodes[0] || null;
				for (i = 0; node = nodes[i++];){
					if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
				}

			} else if (symbol == '#'){

				if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
				node = context.getElementById(name);
				if (!node) return found;
				if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
				if (first) return node || null;
				if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);

			} else if (symbol == '.'){

				if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
				if (context.getElementsByClassName && !this.brokenGEBCN){
					nodes = context.getElementsByClassName(name);
					if (first) return nodes[0] || null;
					for (i = 0; node = nodes[i++];){
						if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
					}
				} else {
					var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
					nodes = context.getElementsByTagName('*');
					for (i = 0; node = nodes[i++];){
						className = node.className;
						if (!(className && matchClass.test(className))) continue;
						if (first) return node;
						if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
					}
				}

			}

			if (hasOthers) this.sort(found);
			return (first) ? null : found;

		}
		/*</simple-selectors-override>*/

		/*<query-selector-override>*/
		querySelector: if (context.querySelectorAll) {

			if (!this.isHTMLDocument
				|| qsaFailExpCache[expression]
				//TODO: only skip when expression is actually mixed case
				|| this.brokenMixedCaseQSA
				|| (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
				|| (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
				|| (!contextIsDocument //Abort when !contextIsDocument and...
					//  there are multiple expressions in the selector
					//  since we currently only fix non-document rooted QSA for single expression selectors
					&& expression.indexOf(',') > -1
				)
				|| Slick.disableQSA
			) break querySelector;

			var _expression = expression, _context = context;
			if (!contextIsDocument){
				// non-document rooted QSA
				// credits to Andrew Dupont
				var currentId = _context.getAttribute('id'), slickid = 'slickid__';
				_context.setAttribute('id', slickid);
				_expression = '#' + slickid + ' ' + _expression;
				context = _context.parentNode;
			}

			try {
				if (first) return context.querySelector(_expression) || null;
				else nodes = context.querySelectorAll(_expression);
			} catch(e) {
				qsaFailExpCache[expression] = 1;
				break querySelector;
			} finally {
				if (!contextIsDocument){
					if (currentId) _context.setAttribute('id', currentId);
					else _context.removeAttribute('id');
					context = _context;
				}
			}

			if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
				if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
			} else for (i = 0; node = nodes[i++];){
				if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
			}

			if (hasOthers) this.sort(found);
			return found;

		}
		/*</query-selector-override>*/

		parsed = this.Slick.parse(expression);
		if (!parsed.length) return found;
	} else if (expression == null){ // there is no expression
		return found;
	} else if (expression.Slick){ // expression is a parsed Slick object
		parsed = expression;
	} else if (this.contains(context.documentElement || context, expression)){ // expression is a node
		(found) ? found.push(expression) : found = expression;
		return found;
	} else { // other junk
		return found;
	}

	/*<pseudo-selectors>*//*<nth-pseudo-selectors>*/

	// cache elements for the nth selectors

	this.posNTH = {};
	this.posNTHLast = {};
	this.posNTHType = {};
	this.posNTHTypeLast = {};

	/*</nth-pseudo-selectors>*//*</pseudo-selectors>*/

	// if append is null and there is only a single selector with one expression use pushArray, else use pushUID
	this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;

	if (found == null) found = [];

	// default engine

	var j, m, n;
	var combinator, tag, id, classList, classes, attributes, pseudos;
	var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;

	search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){

		combinator = 'combinator:' + currentBit.combinator;
		if (!this[combinator]) continue search;

		tag        = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
		id         = currentBit.id;
		classList  = currentBit.classList;
		classes    = currentBit.classes;
		attributes = currentBit.attributes;
		pseudos    = currentBit.pseudos;
		lastBit    = (j === (currentExpression.length - 1));

		this.bitUniques = {};

		if (lastBit){
			this.uniques = uniques;
			this.found = found;
		} else {
			this.uniques = {};
			this.found = [];
		}

		if (j === 0){
			this[combinator](context, tag, id, classes, attributes, pseudos, classList);
			if (first && lastBit && found.length) break search;
		} else {
			if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
				this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
				if (found.length) break search;
			} else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
		}

		currentItems = this.found;
	}

	// should sort if there are nodes in append and if you pass multiple expressions.
	if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);

	return (first) ? (found[0] || null) : found;
};

// Utils

local.uidx = 1;
local.uidk = 'slick-uniqueid';

local.getUIDXML = function(node){
	var uid = node.getAttribute(this.uidk);
	if (!uid){
		uid = this.uidx++;
		node.setAttribute(this.uidk, uid);
	}
	return uid;
};

local.getUIDHTML = function(node){
	return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
};

// sort based on the setDocument documentSorter method.

local.sort = function(results){
	if (!this.documentSorter) return results;
	results.sort(this.documentSorter);
	return results;
};

/*<pseudo-selectors>*//*<nth-pseudo-selectors>*/

local.cacheNTH = {};

local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;

local.parseNTHArgument = function(argument){
	var parsed = argument.match(this.matchNTH);
	if (!parsed) return false;
	var special = parsed[2] || false;
	var a = parsed[1] || 1;
	if (a == '-') a = -1;
	var b = +parsed[3] || 0;
	parsed =
		(special == 'n')	? {a: a, b: b} :
		(special == 'odd')	? {a: 2, b: 1} :
		(special == 'even')	? {a: 2, b: 0} : {a: 0, b: a};

	return (this.cacheNTH[argument] = parsed);
};

local.createNTHPseudo = function(child, sibling, positions, ofType){
	return function(node, argument){
		var uid = this.getUID(node);
		if (!this[positions][uid]){
			var parent = node.parentNode;
			if (!parent) return false;
			var el = parent[child], count = 1;
			if (ofType){
				var nodeName = node.nodeName;
				do {
					if (el.nodeName != nodeName) continue;
					this[positions][this.getUID(el)] = count++;
				} while ((el = el[sibling]));
			} else {
				do {
					if (el.nodeType != 1) continue;
					this[positions][this.getUID(el)] = count++;
				} while ((el = el[sibling]));
			}
		}
		argument = argument || 'n';
		var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
		if (!parsed) return false;
		var a = parsed.a, b = parsed.b, pos = this[positions][uid];
		if (a == 0) return b == pos;
		if (a > 0){
			if (pos < b) return false;
		} else {
			if (b < pos) return false;
		}
		return ((pos - b) % a) == 0;
	};
};

/*</nth-pseudo-selectors>*//*</pseudo-selectors>*/

local.pushArray = function(node, tag, id, classes, attributes, pseudos){
	if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
};

local.pushUID = function(node, tag, id, classes, attributes, pseudos){
	var uid = this.getUID(node);
	if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
		this.uniques[uid] = true;
		this.found.push(node);
	}
};

local.matchNode = function(node, selector){
	if (this.isHTMLDocument && this.nativeMatchesSelector){
		try {
			return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
		} catch(matchError) {}
	}

	var parsed = this.Slick.parse(selector);
	if (!parsed) return true;

	// simple (single) selectors
	var expressions = parsed.expressions, simpleExpCounter = 0, i;
	for (i = 0; (currentExpression = expressions[i]); i++){
		if (currentExpression.length == 1){
			var exp = currentExpression[0];
			if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
			simpleExpCounter++;
		}
	}

	if (simpleExpCounter == parsed.length) return false;

	var nodes = this.search(this.document, parsed), item;
	for (i = 0; item = nodes[i++];){
		if (item === node) return true;
	}
	return false;
};

local.matchPseudo = function(node, name, argument){
	var pseudoName = 'pseudo:' + name;
	if (this[pseudoName]) return this[pseudoName](node, argument);
	var attribute = this.getAttribute(node, name);
	return (argument) ? argument == attribute : !!attribute;
};

local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
	if (tag){
		var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
		if (tag == '*'){
			if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
		} else {
			if (nodeName != tag) return false;
		}
	}

	if (id && node.getAttribute('id') != id) return false;

	var i, part, cls;
	if (classes) for (i = classes.length; i--;){
		cls = node.getAttribute('class') || node.className;
		if (!(cls && classes[i].regexp.test(cls))) return false;
	}
	if (attributes) for (i = attributes.length; i--;){
		part = attributes[i];
		if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
	}
	if (pseudos) for (i = pseudos.length; i--;){
		part = pseudos[i];
		if (!this.matchPseudo(node, part.key, part.value)) return false;
	}
	return true;
};

var combinators = {

	' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level

		var i, item, children;

		if (this.isHTMLDocument){
			getById: if (id){
				item = this.document.getElementById(id);
				if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
					// all[id] returns all the elements with that name or id inside node
					// if theres just one it will return the element, else it will be a collection
					children = node.all[id];
					if (!children) return;
					if (!children[0]) children = [children];
					for (i = 0; item = children[i++];){
						var idNode = item.getAttributeNode('id');
						if (idNode && idNode.nodeValue == id){
							this.push(item, tag, null, classes, attributes, pseudos);
							break;
						}
					}
					return;
				}
				if (!item){
					// if the context is in the dom we return, else we will try GEBTN, breaking the getById label
					if (this.contains(this.root, node)) return;
					else break getById;
				} else if (this.document !== node && !this.contains(node, item)) return;
				this.push(item, tag, null, classes, attributes, pseudos);
				return;
			}
			getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
				children = node.getElementsByClassName(classList.join(' '));
				if (!(children && children.length)) break getByClass;
				for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
				return;
			}
		}
		getByTag: {
			children = node.getElementsByTagName(tag);
			if (!(children && children.length)) break getByTag;
			if (!this.brokenStarGEBTN) tag = null;
			for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
		}
	},

	'>': function(node, tag, id, classes, attributes, pseudos){ // direct children
		if ((node = node.firstChild)) do {
			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
		} while ((node = node.nextSibling));
	},

	'+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
		while ((node = node.nextSibling)) if (node.nodeType == 1){
			this.push(node, tag, id, classes, attributes, pseudos);
			break;
		}
	},

	'^': function(node, tag, id, classes, attributes, pseudos){ // first child
		node = node.firstChild;
		if (node){
			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
			else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
		}
	},

	'~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
		while ((node = node.nextSibling)){
			if (node.nodeType != 1) continue;
			var uid = this.getUID(node);
			if (this.bitUniques[uid]) break;
			this.bitUniques[uid] = true;
			this.push(node, tag, id, classes, attributes, pseudos);
		}
	},

	'++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
		this['combinator:+'](node, tag, id, classes, attributes, pseudos);
		this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
	},

	'~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
		this['combinator:~'](node, tag, id, classes, attributes, pseudos);
		this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
	},

	'!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
		while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
	},

	'!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
		node = node.parentNode;
		if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
	},

	'!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
		while ((node = node.previousSibling)) if (node.nodeType == 1){
			this.push(node, tag, id, classes, attributes, pseudos);
			break;
		}
	},

	'!^': function(node, tag, id, classes, attributes, pseudos){ // last child
		node = node.lastChild;
		if (node){
			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
			else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
		}
	},

	'!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
		while ((node = node.previousSibling)){
			if (node.nodeType != 1) continue;
			var uid = this.getUID(node);
			if (this.bitUniques[uid]) break;
			this.bitUniques[uid] = true;
			this.push(node, tag, id, classes, attributes, pseudos);
		}
	}

};

for (var c in combinators) local['combinator:' + c] = combinators[c];

var pseudos = {

	/*<pseudo-selectors>*/

	'empty': function(node){
		var child = node.firstChild;
		return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
	},

	'not': function(node, expression){
		return !this.matchNode(node, expression);
	},

	'contains': function(node, text){
		return (node.innerText || node.textContent || '').indexOf(text) > -1;
	},

	'first-child': function(node){
		while ((node = node.previousSibling)) if (node.nodeType == 1) return false;
		return true;
	},

	'last-child': function(node){
		while ((node = node.nextSibling)) if (node.nodeType == 1) return false;
		return true;
	},

	'only-child': function(node){
		var prev = node;
		while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false;
		var next = node;
		while ((next = next.nextSibling)) if (next.nodeType == 1) return false;
		return true;
	},

	/*<nth-pseudo-selectors>*/

	'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),

	'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),

	'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),

	'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),

	'index': function(node, index){
		return this['pseudo:nth-child'](node, '' + index + 1);
	},

	'even': function(node){
		return this['pseudo:nth-child'](node, '2n');
	},

	'odd': function(node){
		return this['pseudo:nth-child'](node, '2n+1');
	},

	/*</nth-pseudo-selectors>*/

	/*<of-type-pseudo-selectors>*/

	'first-of-type': function(node){
		var nodeName = node.nodeName;
		while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false;
		return true;
	},

	'last-of-type': function(node){
		var nodeName = node.nodeName;
		while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false;
		return true;
	},

	'only-of-type': function(node){
		var prev = node, nodeName = node.nodeName;
		while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false;
		var next = node;
		while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false;
		return true;
	},

	/*</of-type-pseudo-selectors>*/

	// custom pseudos

	'enabled': function(node){
		return !node.disabled;
	},

	'disabled': function(node){
		return node.disabled;
	},

	'checked': function(node){
		return node.checked || node.selected;
	},

	'focus': function(node){
		return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
	},

	'root': function(node){
		return (node === this.root);
	},

	'selected': function(node){
		return node.selected;
	}

	/*</pseudo-selectors>*/
};

for (var p in pseudos) local['pseudo:' + p] = pseudos[p];

// attributes methods

var attributeGetters = local.attributeGetters = {

	'class': function(){
		return this.getAttribute('class') || this.className;
	},

	'for': function(){
		return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
	},

	'href': function(){
		return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
	},

	'style': function(){
		return (this.style) ? this.style.cssText : this.getAttribute('style');
	},

	'tabindex': function(){
		var attributeNode = this.getAttributeNode('tabindex');
		return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
	},

	'type': function(){
		return this.getAttribute('type');
	},

	'maxlength': function(){
		var attributeNode = this.getAttributeNode('maxLength');
		return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
	}

};

attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength;

// Slick

var Slick = local.Slick = (this.Slick || {});

Slick.version = '1.1.6';

// Slick finder

Slick.search = function(context, expression, append){
	return local.search(context, expression, append);
};

Slick.find = function(context, expression){
	return local.search(context, expression, null, true);
};

// Slick containment checker

Slick.contains = function(container, node){
	local.setDocument(container);
	return local.contains(container, node);
};

// Slick attribute getter

Slick.getAttribute = function(node, name){
	local.setDocument(node);
	return local.getAttribute(node, name);
};

Slick.hasAttribute = function(node, name){
	local.setDocument(node);
	return local.hasAttribute(node, name);
};

// Slick matcher

Slick.match = function(node, selector){
	if (!(node && selector)) return false;
	if (!selector || selector === node) return true;
	local.setDocument(node);
	return local.matchNode(node, selector);
};

// Slick attribute accessor

Slick.defineAttributeGetter = function(name, fn){
	local.attributeGetters[name] = fn;
	return this;
};

Slick.lookupAttributeGetter = function(name){
	return local.attributeGetters[name];
};

// Slick pseudo accessor

Slick.definePseudo = function(name, fn){
	local['pseudo:' + name] = function(node, argument){
		return fn.call(node, argument);
	};
	return this;
};

Slick.lookupPseudo = function(name){
	var pseudo = local['pseudo:' + name];
	if (pseudo) return function(argument){
		return pseudo.call(this, argument);
	};
	return null;
};

// Slick overrides accessor

Slick.override = function(regexp, fn){
	local.override(regexp, fn);
	return this;
};

Slick.isXML = local.isXML;

Slick.uidOf = function(node){
	return local.getUIDHTML(node);
};

if (!this.Slick) this.Slick = Slick;

}).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);

// Requires Core, DOM, Slick. This file should be replaced by a custom Selecting.js if another selector engine is used.

(function(pairs) {
	SJS.extend(SJS, pairs);
	SJS.each(pairs, function(k) {
		SJS.implement(window.Element, k, function() {
			return SJS[k].apply(this, [arguments[0], this].concat(SJS.without(arguments, 0)));
		});
		SJS.implement(window.Elements, k, function() {
			return SJS[k].apply(this, [arguments[0], this].concat(SJS.without(arguments, 0)));
		});
	});
})({
	byId: function(id, context) {
		return SJS.find({
			Slick: 1,
			expressions: [[{
				combinator: ' ',
				tag: '*',
				id: id
			}]]
		}, context, (context ? context.queryOf() + ' ' : '') + '#' + id);
	},
	byClass: function(className, context) {
		return SJS.search({
			Slick: 1,
			expressions: [[{
				combinator: ' ',
				tag: '*',
				classList: [
					className
				],
				classes: [{
					regexp: new RegExp('(^|\\s)' + Slick.escapeRegExp(className) + '(\\s|$)')
				}]
			}]]
		}, context, (context ? context.queryOf() + ' ' : '') + '.' + className);
	},
	search: function(queryFor, context, queryAttr) {
		return new window.Elements(queryAttr || queryFor || '*', window.Slick.search(context || window.document, queryFor || '*'));
	},
	searchEach: function(queryFor, context, queryAttr) {
		if(!context)
			return SJS.search.apply(arguments);
		var ret = new window.Elements(queryAttr || queryFor || '*');
		SJS.each(context, function(el) {
			Slick.search(el, queryFor || '*', ret);
		});
		return ret;
	},
	find: function(queryFor, context, queryAttr) {
		var el = g(window.Slick.find(context || window.document, queryFor || '*'));
		el.query = queryAttr;
		return el;
	},
	match: function(query, node) {
		if(SJS.isElements(node)) {
			var match;
			SJS.each(node, function(el) {
				return match = window.Slick.match(el, query);
			});
			return match || false;
		}
		return window.Slick.match(node, query);
	},
	closest: function(query, node) {
		return SJS.match(query, node) ? node : SJS[SJS.isElements(node) ? 'searchEach' : 'find']('! ' + (query || '*'), node, node.queryOf() + ' ! ' + (query || '*'));
	}
});

// Requires Core

SJS.extend(SJS, {
	ajax: function(arg, data, success, type, method) {
		if(SJS.isString(arg))
			return SJS.ajax({
				url: arg,
				data: data,
				success: success,
				type: type,
				method: method
			});
		
		var httpRequest, isGet;
		if(window.XMLHttpRequest)
			httpRequest = new window.XMLHttpRequest();
		else if(window.ActiveXObject) {
			try {
				httpRequest = new window.ActiveXObject('Msxml2.XMLHTTP.6.0');
			} catch(e) {
				try {
					httpRequest = new window.ActiveXObject('Msxml2.XMLHTTP.3.0');
				} catch(f) {
					return false;
				}
			}
		}
		else
			return false;
		
		arg = SJS.merge({
			data: '',
			method: arg.data ? 'post' : 'get',
			type: 'plain',
			thisObj: httpRequest
		}, arg);
		isGet = arg.method === 'get';
		
		httpRequest.onreadystatechange = function() {
			if(httpRequest.readyState == 4) {
				var success = httpRequest.status == 200,
					data = httpRequest.responseText;
				if(arg.type == 'json')
					data = data.jsonDecode();
				SJS.each([success ? 'success' : 'fail', 'callback'], function(el) {
					if(arg[el])
						arg[el].call(arg.thisObj, data);
				});
			}
		};
		
		if(SJS.isNull(arg.url))
			throw 'Ajax url is undefined.';
		
		httpRequest.open(arg.method, arg.url + (isGet ? '?' + SJS.serialize(arg.data) : ''));
		httpRequest.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
		if(!isGet)
			httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		httpRequest.send(isGet ? null : SJS.serialize(arg.data));
		
		return this;
	}
});

SJS.implement(window.Element, {
	ajax: function(arg, data, success, type, method) {
		return SJS.ajax(SJS.isString(arg) ? {
			url: arg,
			data: data,
			success: success,
			type: type,
			method: method,
			thisObj: this
		} : SJS.merge({thisObj: this}, arg));
	},
	pull: function(arg, data, success, type, method) {
		return SJS.ajax(SJS.isString(arg) ? {
			url: arg,
			data: data,
			success: function(data) {
				this.html(data);
				success.call(this, data);
			},
			type: type,
			method: method,
			thisObj: this
		} : SJS.merge({
			success: function(data) {
				this.html(data);
				arg.success.call(this, data);
			},
			thisObj: this
		}, SJS.without(arg, 'success')));
	}
});

SJS.each(['get', 'post'], function(method) {
	SJS.extend(SJS, method, function(arg, data, success, type) {
		return SJS.ajax(SJS.isString(arg) ? {
				url: arg,
				data: data,
				success: success,
				type: type,
				method: method
			} : SJS.merge({method: method}, arg));
	});
	SJS.implement(window.Element, method, function(arg, data, success, type) {
		return SJS.ajax(SJS.isString(arg) ? {
				url: arg,
				data: data,
				success: success,
				type: type,
				method: method,
				thisObj: this
			} : SJS.merge({method: method, thisObj: this}, arg));
	});
});

window.Elements.implementEach('ajax', 'get', 'post');
window.Elements.implementSame('pull');

// Requires Core, DOM

(function(SJS, undefined) {
	var toggleFunction = function(name) {
			var show = 'show' + name,
				hide = 'hide' + name;
			return function() {
				var args = arguments;
				return this.chain(function() {
					this[this.css('display') === 'none' ? show : hide].apply(this, args);
				});
			};
		},
		anims = {
			/* Function Element#animate(String property, String | Int value, String | Int duration, String easing, Function callback)
			 * Animates the elements css property <property> to <value>.
			 * Supported $<value>s$ are:
			 * - Absolute values, such as pixels (numbers are interpreted as pixels)
			 * - Colors:
			 * - - $#rgb$: $#f00$ or $#F00$
			 * - - $#rrggbb$: $#ff0000$ or $#FF0000$
			 * - - $rgb(red, green, blue)$: $rgb(255, 0, 0)$
			 * - - $rgba(red, green, blue, alpha)$: $rgba(255, 0, 0, 1)$
			 * SJS also tries to make rgba work in older versions of Internet Explorer.
			 * The <duration> is in milliseconds. You can also provide:
			 * - $'fast'$: 200 ms
			 * - $'normal'$: 400 ms
			 * - $'slow'$: 600 ms
			 * The easings currently available are:
			 * - $'swing'$: a sine easing
			 * - $'linear'$: constant pace easing
			 * When the animation finishes, <callback> is called.
			 $ var el = g('animateMe');
			 $ el
			 $   .css('position', 'absolute')
			 $   .animate('top', 100, 'slow', function() { // note that we skip easing
			 $     alert('animated!');
			 $   });
			 * Function Element#animate(Object settings1, Object settings2, ...)
			 * Starts an animation for every argument.
			 * A settings object can have the following properties:
			 * - $prop$: the CSS property (necessary)
			 * - $from$: the start value or color array, see $rgb$
			 * - $to$: the end value (necessary)
			 * - $rgb$: an array $[red, green, blue]$ or $[red, green, blue, alpha]$, alternative for $to$
			 * - $type$: if you set type: 'color', $to$ doesn't have to start with $'#'$
			 * - $duration$: the duration
			 * - $easing$: easing function ID
			 * - $callback$: function to be called at animation end
			 * Function Element#animate(String property, Array values, String | Int duration, String easing, Function callback)
			 * The first value in <values> ($<value>[0]$) is used as $from$, the second ($<value>[1]$) as $to$.
			 * Function Element#animate(Array properties, String | Int value, String | Int duration, String easing, Function callback)
			 * Animates all of <properties> to <value>.
			 * Function Element#animate(Array properties, Array value, String | Int duration, String easing, Function callback)
			 * Animates all of <properties> from $<value>[0]$ to $<value>[1]$.
			 */
			animate: function(key, val, duration, easing, callback) {
				if(SJS.isArray(key)) {
					SJS.each(key, function(el) {
						this.animate(el, val, duration, easing, callback);
					}, this);
					return this;
				}
				else if(SJS.isArray(val))
					return this.animate({
						prop: key,
						from: val[0],
						to: val[1],
						duration: duration,
						easing: easing,
						callback: callback
					});
				else if(SJS.isString(key))
					return this.animate({
						prop: key,
						to: val,
						duration: SJS.isNumber(duration) || SJS.isFunction(duration) ? duration : null,
						easing: SJS.isString(easing) ? easing : null,
						callback: SJS.isFunction(duration) ? duration : SJS.isFunction(easing) ? easing : callback
					});
				SJS.each(arguments, function(el) {
					var settings = SJS.merge({
							type: 'unit',
							duration: 400,
							easing: 'swing',
							start: new Date(),
							element: this
						}, SJS.Settings.animationDefaults, el),
						widthFixed;
					switch(settings.duration) {
						case 'fast': settings.duration = 200; break;
						case 'normal': settings.duration = 400; break;
						case 'slow': settings.duration = 600; break;
					}
					if(SJS.hasOwn(SJS.animationTypes, settings.prop)) {
						settings.type = settings.prop;
						settings.customType = true;
					}
					else if(settings.rgb || (settings.rgb = SJS.parseColor(settings.to)) !== settings.to)
						settings.type = 'color';
					
					if(SJS.isNull(settings.from)) {
						if(settings.customType && SJS.animationTypes[settings.prop].get)
							settings.from = SJS.animationTypes[settings.prop].get(this);
						else
							settings.from = this.computedStyle(settings.prop, true);
					}
					else if(settings.type === 'color')
						settings.from = SJS.parseColor(settings.from);
					if(settings.type === 'color' && !SJS.isArray(settings.from)) {
						settings.from = Array.prototype.slice.call(settings.rgb);
						settings.from[3] = 0;
					}
					if(settings.to == 'auto') {
						this.css(settings.prop, '');
						if(settings.prop == 'height' && parseFloat(this.css('width') || 1) === 0) {
							widthFixed = true;
							this.css('width', '');
						}
						settings.to = this.computedStyle(settings.prop);
						if(widthFixed)
							this.css('width', 0);
						this.css(settings.prop, settings.from);
					}
					if(settings.prop == 'height' || settings.prop == 'width') {
						settings.origOverflow = this.css('overflow');
						this.css('overflow', 'hidden');
					}
					if(settings.prop == 'opacity') {
						settings.type = 'opacity';
						if(!settings.from && settings.from !== 0)
							settings.from = 1;
						else
							settings.from = parseFloat(settings.from);
						this.style.zoom = 1;
					} else if(settings.type == 'color') {
						settings.isRGBa = settings.rgb.length == 4;
					} else {
						settings.toUnit = (settings.to.toString().match(/[\d\.]+([a-z]+|%)/) || [0, 'px'])[1];
						settings.to = parseFloat(settings.to);
						if(settings.from)
							settings.fromUnit = (settings.from.toString().match(/[\d\.]+([a-z]+|%)/) || [0, 'px'])[1];
						else
							settings.from = 0;
						settings.from = settings.toUnit == '%' ? 100 : parseFloat(settings.from) || 0;
					}
					animations.push(settings);
					doAnimations();
				}, this);
				return this;
			},
			/* Function Element#animateQ(...)
			 * Alias of <Element#animate>, but waits for current animations on the element to stop first.
			 */
			animateQ: function() {
				var args = arguments;
				return this.chain(function() {
					this.animate.apply(this, args);
				});
			},
			
			continuous: function() {
				var args = arguments;
				if(SJS.isArray(args[0])) {
					var next = 0,
						element = this,
						doNext = function() {
							if(next == args.length) next = 0;
							element.chain.apply(element, args[next]);
							element.chain(doNext);
							next++;
						};
					doNext();
				}
				else
					this.continuous(arguments);
			},
			
			/* Function Element#visible()
			 * Returns a bool indicating if 'display' is not 'none' and 'visibility' is not 'hidden'.
			 */
			visible: function() {
				return this.css('display') !== 'none' && this.css('visibility') !== 'hidden';
			},
			/* Function Element#hide()
			 * Waits for current animations and sets $display: none$.
			 */
			hide: function() {
				return this.chain('css', 'display', 'none');
			},
			/* Function Element#show()
			 * Waits for current animations and removes $display: none$.
			 */
			show: function() {
				return this.chain('css', 'display', '');
			},
			/* Function Element#toggle()
			 * Waits for current animations and toggles the visibility of the element.
			 */
			toggle: toggleFunction(),
			
			/* Function Element#hideSmooth(String | Int duration, String easing, Function callback)
			 * Smoothly animates the width, height and opacity of the element to 0.
			 */
			hideSmooth: function(duration, easing, callback) {
				return this.chain(function() {
					var styles = ['width', 'height', 'opacity', 'margin'],
						origStyles = this.css(styles);
					
					this.animate(styles, 0, duration, easing)
						.chain('css', 'display', 'none')
						.chain('css', origStyles)
						.chain(callback);
				});
			},
			/* Function Element#showSmooth(String | Int duration, String easing, Function callback)
			 * Smoothly animates the width and height of the element to auto, and the opacity to 1.
			 */
			showSmooth: function(duration, easing, callback) {
				return this.chain(function() {
					if(this.css('display') !== 'none')
						return this;
					this.chain(function() {
							this
								.css('display', '')
								.animate(['width', 'height'], [0, 'auto'], duration, easing)
								.animate('opacity', [0, 1], duration, easing)
								.animate('margin', [0, this.css('margin')], duration, easing)
								.chain(callback);
						});
				});
			},
			/* Function Element#toggleSmooth(String | Int duration, String easing, Function callback)
			 * <Toggle @ Element#toggle> of <Element#showSmooth> and <Element#hideSmooth>.
			 */
			toggleSmooth: toggleFunction('Smooth'),
			
			/* Function Element#hideSlide(String | Int duration, String easing, Function callback)
			 * Animates the height and opacity of the element to 0.
			 */
			hideSlide: function(duration, easing, callback) {
				return this.chain(function() {
					var styles = ['height', 'opacity', 'marginTop', 'marginBottom'],
						origStyles = this.css(styles);
						
					this.animate(styles, 0, duration, easing)
						.chain('css', 'display', 'none')
						.chain('css', origStyles)
						.chain(callback);
				});
			},
			/* Function Element#hideSlide(String | Int duration, String easing, Function callback)
			 * Animates the height and opacity of the element to respectively auto and 1.
			 */
			showSlide: function(duration, easing, callback) {
				return this.chain(function() {
					if(this.css('display') !== 'none')
						return;
					return this
						.css('display', '')
						.animate('height', [0, 'auto'], duration, easing)
						.animate('opacity', [0, 1], duration, easing)
						.animate(['marginTop', 'marginBottom'], [0, this.css('margin')], duration, easing)
						.chain(callback);
				});
			},
			/* Function Element#toggleSlide(String | Int duration, String easing, Function callback)
			 * <Toggle @ Element#toggle> of <Element#showSlide> and <Element#hideSlide>.
			 */
			toggleSlide: toggleFunction('Slide'),
			
			/* Function Element#hideFade(String | Int duration, String easing, Function callback)
			 * Animates the opacity of the element to 0.
			 */
			hideFade: function(duration, easing, callback) {
				return this.chain(function() {
					this.animate('opacity', 0, duration, easing)
						.chain('css', 'display', 'none')
						.chain(callback);
				});
			},
			/* Function Element#showFade(String | Int duration, String easing, Function callback)
			 * Animates the opacity of the element to 1.
			 */
			showFade: function(duration, easing, callback) {
				return this.chain(function() {
					if(this.css('display') !== 'none')
						return;
					this.css('display', '')
						.animate('opacity', [0, 1], duration, easing)
						.chain(callback);
				});
			},
			/* Function Element#toggleFade(String | Int duration, String easing, Function callback)
			 * <Toggle @ Element#toggle> of <Element#showFade> and <Element#hideFade>.
			 */
			toggleFade: toggleFunction('Fade'),
			
			/* Function Element#highlight(String | Int duration, String easing, Function callback)
			 * Highlights the background of element from the current background to $#fea$ and back.
			 */
			highlight: function(duration, easing, callback) {
				return this.chain(function() {
					this.animate('background', '#fea-1', duration, easing)
						.animateQ('background', ['#fea-1', '#fea-0'], duration, easing)
						.chain(callback);
				});
			},
			
			/* Function Element#chain(Function | String fn, String | Number arg1, arg2, ...)
			 * When all animations on the element end, <fn> will be called with the other arguments (<arg1>, <arg2>, etc.).
			 * If <fn> is a string (e.g. 'css'), that method of the element will be called.
			 * Function Element#chain(Function | String fn, Array args)
			 * When all animations on the element end, <fn> will be called with <args>.
			 * If <fn> is a string (e.g. 'css'), that method of the element will be called.
			 * Function Element#chain(Function | String fn, String chainName, String | Number arg1, arg2, ...)
			 * When all animations on the element in the chain identified by <chainName> end, <fn> will be called with the other arguments (<arg1>, <arg2>, etc.).
			 * If <fn> is a string (e.g. 'css'), that method of the element will be called.
			 * Function Element#chain(Function | String fn, String chainName, Array args)
			 * When all animations on the elementin the chain identified by <chainName>  end, <fn> will be called with <args>.
			 * If <fn> is a string (e.g. 'css'), that method of the element will be called.
			 */
			chain: function(fn, name, args) {
				var el = this,
					ffn = function() {
						fn.apply(el, args);
					},
					isArgsArray;
				
				if(SJS.isString(fn))
					fn = el[fn];
				if(!SJS.isFunction(fn))
					return;
				if(!(isArgsArray = SJS.isArray(args)))
					args = SJS.without(arguments, 0);
				if(!isArgsArray || !(name && SJS.isString(name)))
					name = 'default';
				
				if(this.animationsRunning()) {
					if(SJS.hasOwn(this, 'fnChains'))
						SJS.hasOwn(this.fnChains, name)
							? this.fnChains[name].push(ffn)
							: this.fnChains[name] = [ffn];
					else
						this.fnChains = SJS.toObject(name, [ffn]);
				}
				else
					setTimeout(ffn);
				
				return this;
			},
			/* Function Element#callChain(String name)
			 * Calls the <name> or $'default'$ chain of the element.
			 * If there are <animations running @ Element#animationsRunning> on the element, this function does nothing.
			 * Usually, you don't need to call this function yourself, as it is also done at the end of every animation.
			 */
			callChain: function(name) {
				if(!SJS.isString(name))
					name = 'default';
				if(SJS.hasOwn(this, 'fnChains') && SJS.hasOwn(this.fnChains, name)) {
					while(!this.animationsRunning() && this.fnChains[name].length) {
						this.fnChains[name][0]();
						this.fnChains[name] = SJS.without(this.fnChains[name], 0);
					}
				}
				return this;
			},
			/* Function Element#clearChain(String name)
			 * Clears everyting in the chain.
			 */
			clearChain: function(name) {
				if(!SJS.isString(name))
					name = 'default';
				if(SJS.hasOwn(this, 'fnChains') && SJS.hasOwn(this.fnChains, name))
					this.fnChains[name] = [];
			},
			/* Function Element#animationsRunning()
			 * Returns a bool indicating whether there are any animations running on the element.
			 */
			animationsRunning: function() {
				var ret = false;
				SJS.each(animations, function(el) {
					if(el.element == this) {
						ret = true;
						return false;
					}
				}, this);
				return ret;
			}
		};
	
	SJS.extend(SJS, {
		/* Object SJS.animationTypes
		 */
		animationTypes: {}
	});
	
	SJS.extend(SJS.Settings, {
		/* Object SJS.Settings.animationInterval
		 * Default: 15.
		 * The amount of milliseconds between two screen updates in an animation.
		 * This number does not change the animation speed.
		 */
		animationInterval: 15,
		/* Object SJS.Settings.animationDefaults
		 * In this object, you can store animation defaults.
		 * See <Element#animate> for the available options.
		 $ _.Settings.animationDefaults.duration = 300;
		 */
		animationDefaults: {}
	});
	
	SJS.implement(window.Element, anims);
	/* Function Elements#animate(...)
	 * All animation functions animate, when called on an <Elements> object, all of the elements in it.
	 $ _('.test').hideSmooth('slow') // hide .test elements
	 */
	SJS.each(anims, function(k) {
		window.Elements.implementEach(k);
	});

	var easings = {
			'linear': function(t) {
				return t;
			},
			'swing': function(t) {
				return Math.cos(t * Math.PI) * -0.5 + 0.5;
			}
		},
		easingsCache = {},
		animations = [],
		animationsRunning = false,
		animationsTimeout,
		doAnimations = function() {
			if(animationsRunning)
				return;
			animationsRunning = true;
			setTimeout(animationsStep);
			animationsInterval = setInterval(animationsStep, SJS.Settings.animationInterval);
		},
		animationsStep = function() {
			if(!animations.length) {
				animationsRunning = false;
				clearInterval(animationsInterval);
				return;
			}
			SJS.each(animations, function(el, i) {
				var tProgress, pProgress, progress, newVal, j;
				if(el.duration) {
					tProgress = new Date() - el.start;
					if(tProgress >= el.duration)
						progress = 1;
					else {
						tProgress = tProgress.toFixed(2);
						if(!easingsCache[el.easing])
							easingsCache[el.easing] = {};
						pProgress = tProgress / el.duration;
						if(easingsCache[el.easing]) {
							if(!SJS.isNull(easingsCache[el.easing][pProgress]))
								progress = easingsCache[el.easing][pProgress];
							else
								easingsCache[el.easing][pProgress] = progress = easings[el.easing](pProgress);
						}
						else {
							easingsCache[el.easing] = {};
							easingsCache[el.easing][pProgress] = progress = easings[el.easing](pProgress);
						}
					}
				}
				else progress = 1;
				
				if(el.customType) {
					newVal = progress * (el.to - el.from) + el.from;
					if(!SJS.animationTypes[el.prop].noRounding)
						newVal = Math.round(newVal);
					SJS.animationTypes[el.prop].set(el.element, newVal);
				}
				else {
					switch(el.type) {
						case 'unit':
							el.element.style[el.prop] = Math.round(progress * (el.to - el.from) + el.from) + el.toUnit;
							break;
						case 'color':
							newVal = [];
							for(j = 0; j < 3; j++)
								newVal[j] = Math.round(progress * (el.rgb[j] - el.from[j]) + el.from[j]);
							if(el.isRGBa) {
								if(isNaN(el.from[3]))
									el.from[3] = 1;
								newVal[3] = (progress * (el.rgb[3] - el.from[3]) + el.from[3]).toFixed(2);
							}
							try {
								el.element.style[el.prop] = el.isRGBa ? 'rgba(' + newVal.join(',') + ')'
																	  :  'rgb(' + newVal.join(',') + ')';
							} catch(e) {
								if(el.isRGBa) {
									newVal = SJS.rgb2hex(newVal, 1);
									newVal = 'progid:DXImageTransform.Microsoft.gradient(startColorstr=' + newVal + ', endColorstr=' + newVal + ')';
									el.element.style.filter = newVal;
								}
							}
								
							break;
						case 'opacity':
							newVal = progress * (el.to - el.from) + el.from;
							el.element.style.opacity = newVal;
							el.element.style.filter = 'alpha(opacity=' + (newVal * 100).toFixed(2) + ')';
					}
				}
				
				if(progress == 1) {
					if(!SJS.isNull(el.origOverflow)) {
						var haveOrigOverflow = false;
						SJS.each(animations, function(elov, iov) {
							if(iov != i && !SJS.isNull(elov.origOverflow)) {
								haveOrigOverflow = true;
							}
						});
						if(!haveOrigOverflow)
							el.element.css('overflow', el.origOverflow);
					}
					
					animations = SJS.without(animations, i);
					
					if(el.callback)
						el.callback.call(el.element);
					
					el.element.callChain();
					
					return false;
				}
			});
		};

	/* Function Element#smoothHide(...): Alias of <Element#hideSmooth>.
	 * Function Element#smoothShow(...): Alias of <Element#showSmooth>.
	 * Function Element#smoothToggle(...): Alias of <Element#toggleSmooth>.
	 * Function Element#slideHide(...): Alias of <Element#hideSlide>.
	 * Function Element#slideShow(...): Alias of <Element#showSlide>.
	 * Function Element#slideToggle(...): Alias of <Element#toggleSlide>.
	 * Function Element#slideUp(...): Alias of <Element#hideSlide>.
	 * Function Element#slideDown(...): Alias of <Element#showSlide>.
	 * Function Element#fadeHide(...): Alias of <Element#hideFade>.
	 * Function Element#fadeShow(...): Alias of <Element#showFade>.
	 * Function Element#fadeToggle(...): Alias of <Element#toggleFade>.
	 */
	SJS.each([
		['hideSmooth', 'smoothHide'],
		['showSmooth', 'smoothShow'],
		['toggleSmooth', 'smoothToggle'],
		['hideSlide', 'slideHide'],
		['showSlide', 'slideShow'],
		['toggleSlide', 'slideToggle'],
		['hideSlide', 'slideUp'],
		['showSlide', 'slideDown'],
		['hideFade', 'fadeHide'],
		['showFade', 'fadeShow'],
		['toggleFade', 'fadeToggle']
	], function(arr) {
		SJS.alias(arr[0], arr[1]);
	});
	
})(window.SJS);

// Requires Animations

SJS.animationTypes.rotation = {
	get: function(element) {
		var style = element.style.transform;
		if(!style)
			return 0;
		var match = style.match(/^rotate\((\d+\)[a-z]+)$/);
		return match ? parseInt(match[1]) : 0;
	},
	set: function(element, value) {
		var newVal = 'rotate(' + value + 'deg)';
		SJS.each(['transform', 'MozTransform', 'WebkitTransform', 'OTransform', 'msTransform'], function(s) {
			element.style[s] = newVal;
		});
	},
	
	noRounding: true
};

// Requires Core

/* Function SJS.Class(classProperties)
 * Returns a class-like object.
 * - Functions in <classProperties> are added to the class's prototype
 * - Other type values in <classProperties> are added to every instance of the class
 * - the Init property (function) is called at instance creation (after adding values)
 * - the Extends property's (class) prototype is accessible from within the class
 * - if B extends A, if $C instanceof B$, also $C instanceof A$.
 * - the Implements property (class or array of classes) prototypes are also accessible,
 * - but $instanceof$ doesn't work in this case.
 */
 
SJS.Class = function(props) {
	var defaultClassValues = {},
		extendsProto = {},
		getParent = function(t) {
			var ret = {};
			SJS.each(extendsProto, function(k, v) {
				ret[k] = function() {
					return v.apply(t, arguments);
				};
			});
			return ret;
		},
		Class = function(data) {
			var instance = this;
			this.parent = getParent(this);
			SJS.extend(this, SJS.merge(Class['_defaultValues_'], data));
				// not using ._defaultValues_ to make Closure Compiler happy,
				// it replaces with that anyway 
			for(var i = 0, len = Class['_inits_'].length; i < len; i++)
				Class['_inits_'][i].call(this);
		};
	Class['_inits_'] = [];
	Class['_defaultValues_'] = {};
	SJS.each(props, function(k, v) {
		switch(k) {
			case 'Init':
				if(SJS.isArray(v))
					Class['_inits_'] = Class['_inits_'].concat(v);
				else
					Class['_inits_'].push(v);
				break;
			case 'Extends':
				Class['_inits_'] = Class['_inits_'].concat(v['_inits_']);
				Class.prototype = v['prototype'];
				SJS.extend(Class['_defaultValues_'], v['_defaultValues_'], true);
				extendsProto = SJS['merge']({}, v['prototype']);
				break;
			case 'Implements':
				SJS.each(SJS.toArray(v), function(el) {
					Class['_inits_'] = Class['_inits_'].concat(el['_inits_']);
					SJS.extend(Class['prototype'], el['prototype'], true);
					SJS.extend(Class['_defaultValues_'], el['_defaultValues_'], true);
				});
				break;
			default:
				if(SJS.isFunction(v))
					Class['prototype'][k] = v;
				else
					Class['_defaultValues_'][k] = v;
		}
	});
	return Class;
};

// Requires Core, Selecting

SJS.each(['text', 'checkbox', 'radio', 'button', 'submit'], function(el) {
	window.Slick.definePseudo(el, function(arg) {
		return Slick.match(this, '[type='+el+']');
	});
});

window.Slick.definePseudo('matches', function(arg) {
	return Slick.match(this, arg);
});

(function(SJS) {
	/* source: http://stackoverflow.com/questions/235411/is-there-an-internet-explorer-approved-substitute-for-selectionstart-and-selecti
	 * license: Stack Overflow Creative Commons license
	 */
	var getInputSelection = function(el) {
		var start = 0, end = 0, normalizedValue, range,
			textInputRange, len, endRange;
	
		if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
			start = el.selectionStart;
			end = el.selectionEnd;
		} else {
			range = document.selection.createRange();
	
			if (range && range.parentElement() == el) {
				len = el.value.length;
				normalizedValue = el.value.replace(/\r\n/g, "\n");
	
				// Create a working TextRange that lives only in the input
				textInputRange = el.createTextRange();
				textInputRange.moveToBookmark(range.getBookmark());
	
				// Check if the start and end of the selection are at the very end
				// of the input, since moveStart/moveEnd doesn't return what we want
				// in those cases
				endRange = el.createTextRange();
				endRange.collapse(false);
	
				if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
					start = end = len;
				} else {
					start = -textInputRange.moveStart("character", -len);
					start += normalizedValue.slice(0, start).split("\n").length - 1;
	
					if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
						end = len;
					} else {
						end = -textInputRange.moveEnd("character", -len);
						end += normalizedValue.slice(0, end).split("\n").length - 1;
					}
				}
			}
		}
		
		len = end - start;
		return {
			start: start,
			end: end,
			length: len,
			text: el.value.substr(start, len)
		};
	};

	SJS.implement(window.Element, {
		selection: function(start, length) {
			if(SJS.isNull(start))
				return getInputSelection(this);
			else {
				if(SJS.isPlainObject(start)) {
					length = start.length;
					start = start.start;
				}
				if(typeof this.selectionStart == "number" && typeof this.selectionEnd == "number") {
					this.selectionStart = start;
					this.selectionEnd = start + (length || 0);
				}
				else if(this.createTextRange) {
					var range = this.createTextRange();
					range.collapse(true);
					range.moveStart('character', start);
					range.moveEnd('character', length);
					range.select();
				}
				return this;
			}
		},
		caretToStart: function() {
			return this.selection(0, 0);
		},
		caretToEnd: function() {
			return this.selection(this.value.length);
		},
		selectFrom: function(start) {
			return this.selection(start, this.value.length);
		},
		selectTo: function(end) {
			return this.selection(0, end);
		}
	});
})(window.SJS);

// JSON - Standalone

/*
http://www.JSON.org/json2.js
2011-10-19

Public Domain.

NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

See http://www.JSON.org/js.html


This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html

USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.


This file creates a global JSON object containing two methods: stringify
and parse.

JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.

replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.

space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.

This method produces a JSON text from a JavaScript value.

When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value

For example, this would serialize Dates as ISO strings.

Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}

return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};

You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.

If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.

Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.

The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.

If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.

Example:

text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'


text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'


JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.

The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.

Example:

// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.

myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});

myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});


This is a reference implementation. You are free to copy, modify, or
redistribute.
*/

/*jslint evil: true, regexp: true */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

var JSON;
if (!JSON) {
    JSON = {};
}

(function () {
    'use strict';

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear() + '-' +
                    f(this.getUTCMonth() + 1) + '-' +
                    f(this.getUTCDate()) + 'T' +
                    f(this.getUTCHours()) + ':' +
                    f(this.getUTCMinutes()) + ':' +
                    f(this.getUTCSeconds()) + 'Z'
                : null;
        };

        String.prototype.toJSON =
            Number.prototype.toJSON =
            Boolean.prototype.toJSON = function (key) {
                return this.valueOf();
            };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = { // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string'
                ? c
                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i, // The loop counter.
            k, // The member key.
            v, // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0
                    ? '[]'
                    : gap
                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
                    : '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === 'string') {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0
                ? '{}'
                : gap
                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
                : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                    typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/
                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function'
                    ? walk({'': j}, '')
                    : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());

SJS.Absolute = new SJS.Class({
	
	element: '',
	container: window.document.documentElement,
	
	shadow: true,
	
	position: 'absolute',
	
	Init: function() {
		this.element = g(this.element);
	},
	
	pull: function() {
		if(this.shadow) {
			this.shadowElement = document.createElement(this.element.tagName);
			this.shadowElement.css(this.element.css(['margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'position', 'top', 'left']));
			this.element.after(this.shadowElement);
		}
		this.update(this.element);
		this.element.css('position', this.position);
		this.container.append(this.element);
	},
	
	update: function(shadowElement) {
		if(!shadowElement)
			shadowElement = this.shadowElement;
		this.element.css({
			top: shadowElement.pageY,
			left: shadowElement.pageX
		});
	},
	
	put: function() {
		this.shadowElement.after(this.element);
		this.element.css(this.shadowElement.css(['position', 'top', 'left']));
		this.shadowElement.remove();
	}
	
});


