/*!
 *	Jelly JavaScript, Copyright (c) 2008-2009 Pete Boere.
 *	MIT Style License: http://www.opensource.org/licenses/mit-license.php 
 *  last modified 2009-06-02
 */
(function () {   

var J = window.JELLY = {},
	win = window,
	doc = win.document,
	rootElement = doc.documentElement,
	standardEventModel = 'addEventListener' in doc,
	_function = function () {},
	extend = function (a, b, overwrite) {
		for (var i in b) {
			if (typeof a[i] !== 'undefined' && overwrite === false) {continue;}
			a[i] = b[i];
		}
		return a;
	},
	trace = function () {
		if ( 'console' in win ) { return function (arg) { win.console.log(arg); }; } 
		return _function;
	}(),
	uidCounter = 0,
	uid = function () { return ++uidCounter; },
	elementData = { ns:'jelly_'+(+new Date) },
	fireEvent = function () {
		var args = toArray( arguments ),
			event = 'on' + args.shift().toLowerCase().replace( /^\w/, 
				function (m) { return m.toUpperCase(); } 
			),
			_func = this[event];
		return _func ? _func.apply(this, args) : false;
	};

extend(J,{
	extend: extend,
	trace: trace,
	uid: uid,
	isDefined: function (obj) {	return typeof obj !== 'undefined'; },
	isString: function (obj) { return typeof obj === 'string'; },
	isNumber: function (obj) { return typeof obj === 'number'; },
	isNumeric: function (obj) { 
		return isString(obj) || isNumber(obj) ? /^\d+\.?\d*?$/.test( (obj+'').trim() ) : false;
	},
	isInteger: function (obj) { return J.isNumber(obj) ? /^\d+$/.test( (obj+'').trim() ) : false; }, 
	isFunction: function (obj) { return typeof obj === 'function'; },
	isElement: function (obj) {	return !!obj && typeof obj === 'object' && obj.nodeType === 1; },
	isObject: function (obj) { return obj.constructor === Object; },
	isNull: function (obj) { return obj === null; },
	isArray: function (obj) { return {}.toString.call(obj) === '[object Array]'; },	
	inArray: function (obj, arr) { return arr.indexOf(obj) !== -1; },
	toArray: function (obj) {
		var result = [], n = obj.length, i = 0;
		for (i; i < n; i++) {result[i] = obj[i];}
		return result;
	},
	getElement: function (obj) { 
		return typeof obj === 'string' ? document.getElementById(obj) : obj; 
	},
	defineClass: function (opts) {
		var _constructor = opts.Constructor || _function,
			_static = opts.Static || {},
			_extends = opts.Extends,
			_implements = opts.Implements,
			_prototype = _constructor.prototype; 
		(isArray(_implements) ? _implements : 
			( _implements ? [_implements] : [] )).each(function (o) {
			extend( _prototype, o ); 
		});
		(isArray(_extends) ? _extends : 
			( _extends ? [_extends] : [] )).each(function (o) {
			extend( _prototype, o.prototype ); 
		});
		extend( _constructor, _static );
		['Constructor', 'Static', 'Extends', 'Implements'].each( function (m) {delete opts[m];} );
		extend( _prototype, opts );
		_prototype.constructor = _constructor;
		return _constructor;
	},
	browser: function () {
		var win = window,
			nav = win.navigator,
			ua = nav.userAgent,
			ActiveX = 'ActiveXObject' in win,
			xhr = 'XMLHttpRequest' in win,
			SecurityPolicy = 'securityPolicy' in nav,
			TaintEnabled = 'taintEnabled' in nav,
			Opera = /opera/i.test(ua),
			Firefox = /firefox/i.test(ua),				
			Webkit = /webkit/i.test(ua),
			ie = ActiveX ? ( 
				'querySelectorAll' in document ? 8 : (xhr ? 7 : 6) 
			) : 0;
		return {
			ie: ie,
			ie6: ie === 6,
			ie7: ie === 7,
			ie8: ie === 8,
			opera: Opera,
			firefox: Firefox || (SecurityPolicy && !ActiveX && !Opera),
			webkit: Webkit || (!TaintEnabled && !ActiveX && !Opera),
			safariMobile: /safari/i.test(ua) && /mobile/i.test(ua),
			chrome: Webkit && /chrome/i.test(ua)
		};
	}()
});

var	browser = J.browser,
	msie = browser.ie,
	extend = J.extend,
	defineClass = J.defineClass,
	toArray = J.toArray,
	isArray = J.isArray,
	isDefined = J.isDefined,
	isElement = J.isElement,
	isString = J.isString,
	getElement = J.getElement;
	
extend(J, { // -------------------------------------- >>>  Elements  
	addClass: function (el, cn) {
		if ( J.hasClass(el, cn) ) {
			return;
		}
		el.className += el.className ? ' ' + cn : cn;
	}, 
	removeClass: function (el, cn) {
		if ( !el.className ) {
			return;
		}
		var patt = new RegExp( '(^|\\s)' + cn + '(\\s|$)' );
		el.className = J.normalize( el.className.replace( patt, '' ) );
	},
	hasClass: function (el, cn) {
		return (' ' + el.className + ' ').indexOf(cn) !== -1;
	},
	toggleClass: function (el, cn){
		if ( J.hasClass(el, cn) ) {
			J.removeClass(el, cn);
		} 
		else {
			J.addClass(el, cn);
		}
	},
	createElement: function (arg, attrs) {
		var elem;
		if ( !/[#:\.]/.test(arg) ) {
			elem = doc.createElement(arg), i;
			for (i in attrs) {
				switch (i) {
					case 'setHTML': elem.innerHTML = attrs[i]; break;
					case 'setText': elem.appendChild(doc.createTextNode(attrs[i])); break;
					case 'class': elem.className = attrs[i]; break;
					case 'style': elem.style.cssText = attrs[i]; break;
					default: elem.setAttribute(i, attrs[i]);
				}
			}
		} 
		else {
			var arg = arg.trim(),
				stringKey = 'JELLY_STR_TKN',
				stringTokens = [], 
				m, elem;
			while ( m = /('|")([^\1]*?)\1/.exec(arg) ) {
				arg = arg.replace(m[0], stringKey);
				stringTokens.push(m[2]);
			}
			arg = arg.replace(/\s*(:|,)\s*/g, '$1');
			var parts = arg.split(' '),
				first = parts.shift(),
				leadId = first.indexOf('#') !== -1,
				leadClass = first.indexOf('.') !== -1,
				type = 'div',
				attributes = {},
				branchMapData = null,
				tmp;
			if ( leadId || leadClass ) {
				tmp = leadId ? first.split('#') : first.split('.'); 
				type = tmp.shift() || type;
				attributes[leadId ? 'id':'class'] = tmp.join(' ');
			} 
			else {
				type = first;
			}
			if ( parts[0] ) {
				parts[0].split(',').each(function (tkn) {
					tkn = tkn.split(':');
					var value = tkn[1] === stringKey ? stringTokens.shift() : tkn[1];
					if (tkn[0] === '@') {
						branchMapData = value;
					} 
					else {
						attributes[tkn[0]] = value;
					}
				});
			} 
			elem = J.createElement(type.toLowerCase(), attributes);
		}
		return attrs === true ? { "elem": elem, "ref": branchMapData } : elem;
	},
	wrapElement: function (el, wrapper) {
		el = getElement(el);
		var pnt = el.parentNode, next = el.nextSibling;
		wrapper.appendChild(el);
		return next ? pnt.insertBefore(wrapper, next) : pnt.appendChild(wrapper);	
	},
	withElement: function (el, callback, scope) {
		el = getElement(el);
		if (el) { return callback.call(scope || el, el); }
		return el;
	},
	replaceElement: function (el, replacement) {
		el = getElement(el);
		return el.parentNode.replaceChild(replacement, el);
	},
	removeElement: function (el) {
		el = getElement(el);
		return el.parentNode.removeChild(el);
	},
	createBranch: function () {
		var args = toArray(arguments),
			res = {},
			context,
			parseToken = function (arg) {
				if ( arg && typeof arg === 'object' ) {
					if ( typeof arg.root === 'object' ) {
						for (var i in arg) {
							if ( isArray(arg[i]) ) {
								var nodeName = arg[i][0].nodeName.toLowerCase();
								res[nodeName] = res[nodeName] || [];
								arg[i].each(function (el) { 
									res[nodeName].push(el); 
								});
							} 
							else if (i !== 'root') { 
								res[i] = arg[i]; 
							}
						} 
						return arg.root;
					} 
					else if ( J.isElement(arg) ) { 
						return arg; 
					}
				} 
				else if ( !isString(arg) ) { 
					return; 
				} 
				var obj = J.createElement(arg, true),
					elem = obj.elem,
					type = elem.nodeName.toLowerCase();
				res[type] = res[type] || [];
				res[type].push(elem);
				if ( obj.ref ) { 
					res[obj.ref] = elem; 
				}
				return elem;
			};
		res.root = context = parseToken( args.shift() );
		args.each(function (feed) {
			if ( !isArray(feed) ) {
				context = context.appendChild( parseToken( feed ) );
			} else {
				feed.each(function (o) { context.appendChild( parseToken(o) ) });
			}
		});
		return res;
	},
	insertElement: function (el, datum) {
		el = getElement(el);
		datum = getElement(datum);
		return (datum || doc.body).appendChild(el);
	},
	insertTop: function (el, datum) {
		el = getElement(el);
		datum = getElement(datum);
		if (datum.firstChild) {return datum.insertBefore(el, datum.firstChild);}
		else {return datum.appendChild(el);}
	},
	insertBefore: function (el, datum) {
		return datum.parentNode.insertBefore(el, datum);
	},
	insertAfter: function (el, datum) {
		var next = J.getNext(datum);
		if (next) {return datum.parentNode.insertBefore(el, next);} 
		else {return datum.parentNode.appendChild(el);}
	},
	getFirst: function (el) {
		el = el.firstChild;
		while (el && el.nodeType !== 1) {el = el.nextSibling;}
		return el;
	},
	getLast: function (el) {
		el = el.lastChild;
		while (el && el.nodeType !== 1) {el = el.previousSibling;}
		return el;
	},
	getNext: function (el) {
		el = el.nextSibling;
		while (el && el.nodeType !== 1) {el = el.nextSibling;}
		return el;
	},
	getPrevious: function (el) {
		el = el.previousSibling;
		while (el && el.nodeType !== 1) {el = el.previousSibling;}
		return el;
	},
	getChildren: function (el) {
		var elements = [], el = el.firstChild;
		while (el) {
			if (el.nodeType === 1) {elements[elements.length] = el;}
			el = el.nextSibling;
		}
		return elements;
	},
	getXY: function (el) {
		el = getElement(el);
		var xy = [0, 0];
		do {
			xy[0] += el.offsetLeft;
			xy[1] += el.offsetTop;
		} while (el = el.offsetParent);
		return xy;
	},
	getX: function (el) {
		return J.getXY(el)[0];
	},
	getY: function (el) {
		return J.getXY(el)[1];
	},
	setXY: function (el, X, Y, unit) {
		el = getElement(el);
		unit = unit || 'px';
		el.style.left = X + unit;
		el.style.top = Y + unit;
	},
	getAttribute: function () {
		if (!isDefined(rootElement.hasAttibute) && msie) {
			return function (node, attr) {
				switch (attr) {
					case 'for': return node.attributes[attr].nodeValue || null;
					case 'class': return node.className || null;
					case 'href': 
					case 'src': return node.getAttribute(attr, 2) || null;						
					case 'style': return node.getAttribute(attr).cssText.toLowerCase() || null;
				}
				return node.getAttribute(attr) || null;
			};
		}
		return function (node, attr) {return node.getAttribute(attr);};
	}(),
	getStyle: function (el, prop, parseInteger) {
		prop = J.toCamelCase(prop);
		var value;
		if (prop === 'opacity') { 
			if (el.__opacity === undefined) {el.__opacity = 1;}
			return el.__opacity;
		}
		if (el.style[prop]) {value = el.style[prop];} 
		else if ('getComputedStyle' in win) {value = win.getComputedStyle(el, null)[prop];} 
		else if ('currentStyle' in el) {value = el.currentStyle[prop];}
		return parseInteger === true ? parseInt(value, 10) : value;
	},
	setOpacity: function () {
		if ('filters' in rootElement) {
			return function (el, val) {
				if (el.__opacity === undefined) {el.__opacity = 1;}
				el.style.filter = val === 1 ? '' : 'alpha(opacity='+ (val * 100) +')';
				el.__opacity = val;
			};
		} 
		return function (el, val) {
			if (el.__opacity === undefined) {el.__opacity = 1;}
			el.style.opacity = el.__opacity = val;
		};
	}(),
	storeData: function (el, name, value) {
		var cache = elementData, elementKey = cache.ns;
		if ( !(el = getElement(el)) ) {return;}
		if ( !(elementKey in el) ) { 
			el[elementKey] = uid(); 
			cache[el[elementKey]] = {};
		}
		cache[el[elementKey]][name] = value;
	},
	retrieveData: function (el, name) {
		var cache = elementData, elementKey = cache.ns;
		if ( !(el = getElement(el)) ) {return;}
		if ( elementKey in el && el[elementKey] in cache ) {
			return cache[el[elementKey]][name];
		}
		return null;
	},
	removeData: function (el, name) {
		var cache = elementData, elementKey = cache.ns;
		if ( !(el = getElement(el)) ) {return;}
		if ( elementKey in el && el[elementKey] in cache ) {  
			delete cache[el[elementKey]][name];
		}
	}
});
	
extend(J, { // --------------------------------------- >>>  Events  <<<
	addEvent: function (obj, type, fn) {
		obj = J.getElement(obj);
		var mouseEnter = type === 'mouseenter',
			mouseLeave = type === 'mouseleave',
			wrapper, 
			handle;
		if ( !standardEventModel ) {
			wrapper = function (e) {
				e = J.fixEvent(e);
				fn.call(obj, e);
			};
		}
		if ( mouseEnter || mouseLeave ) {
			wrapper = function (e) {
				e = J.fixEvent(e);
				if (!J.mouseEnterLeave.call(obj, e)) {return;}
				fn.call(obj, e);
			};
			type = mouseEnter ? 'mouseover' : 'mouseout';
		}
		handle = [obj, type, wrapper || fn];
		J.eventLog.push(handle);
		if (standardEventModel) {obj.addEventListener(type, wrapper || fn, false);} 
		else {obj.attachEvent('on' + type, wrapper);}
		return handle;
	},
	addEventOnce: function (obj, type, fn, ref) {
		ref = ref || 'addEventOnce_'+uid();
		if ( !J.retrieveData(obj, ref) ) {
			J.storeData(obj, ref, J.addEvent(obj, type, fn));
		}
	},
	removeEvent: function () {
		if (standardEventModel) {
			return function (arr) { 
				if (arr) { arr[0].removeEventListener(arr[1], arr[2], false); }
			};
		} 
		return function (arr) { 
			if (arr) { arr[0].detachEvent('on' + arr[1], arr[2]); }
		};
	}(),
	purgeEventLog: function () {
		if (J.eventLog.length > 1) {
			var arr = J.eventLog, i, c;
			for (i = 0; arr[i]; i++) {
				c = arr[i];					
				if (c[0] === win && c[1] === 'unload') {continue;}
				J.removeEvent(c);
			}
		}
	}, 
	fixEvent: function () {
		if (standardEventModel) {return function (e) {return e;};}
		return function (e) {
			e = window.event;
			e.target = e.srcElement;
			e.relatedTarget = function () {
				switch (e.type) {
					case 'mouseover': return e.fromElement;
					case 'mouseout': return e.toElement;
				}
			}();
			e.stopPropagation = function () {e.cancelBubble = true;};
			e.preventDefault = function () {e.returnValue = false;};
			e.pageX = e.clientX + rootElement.scrollLeft;
			e.pageY = e.clientY + rootElement.scrollTop;
			return e;
		};		
	}(),
	mouseEnterLeave: function (e) { 
		var related, i;
		if (e.relatedTarget) {
			related = e.relatedTarget;
			if (related.nodeType !== 1 || related === this) {return false;}
			var children = this.getElementsByTagName('*');
			for (i=0; children[i]; i++) {if (related === children[i]) {return false;}}
		}
		return true;
	},
	stopEvent: function (e) {
		e = J.fixEvent(e);
		e.stopPropagation();
		e.preventDefault();
		return e;
	},
	eventLog: [] 
});
	
extend(J, { // --------------------------------------- >>>  String related  <<<
	normalize: function (str) {
		return str.replace(/\s{2,}/g, ' ').trim();
	},
	toCamelCase: function (str) {
		return str.replace(/-\D/gi, function (m) {
			return m.charAt(m.length - 1).toUpperCase();
		});
	}, 
	toCssCase: function (str) {
		return str.replace(/([A-Z])/g, '-$1').toLowerCase();
	}, 
	rgbToHex: function (str) {
		var rgb = str.match(/[\d]{1,3}/g), hex = [], i;
		for (i = 0; i < 3; i++) {
			var bit = (rgb[i]-0).toString(16);
			hex.push(bit.length === 1 ? '0'+bit : bit);
		}
		return '#' + hex.join('');
	},
	hexToRgb: function (str, array) {
		var hex = str.match(/^#([\w]{1,2})([\w]{1,2})([\w]{1,2})$/), rgb = [], i;
		for (i = 1; i < hex.length; i++) {
			if (hex[i].length === 1) {hex[i] += hex[i];}
			rgb.push(parseInt(hex[i], 16));
		}
		return array ? rgb : 'rgb(' + rgb.join(',') + ')';
	},
	parseColour: function (str, mode) {
		var rgbToHex = J.rgbToHex,
			hexToRgb = J.hexToRgb,
			hex = /^#/.test(str), 
			tempArray = [], temp;
		switch (mode) {
			case 'hex':	return hex ? str : rgbToHex(str);
			case 'rgb': return hex ? hexToRgb(str) : str;
			case 'rgb-array': 
				if (hex) {return hexToRgb(str, true);} 
				else {
					temp = str.replace(/rgb| |\(|\)/g, '').split(',');
					temp.each(function (item) {tempArray.push(parseInt(item, 10));});
					return tempArray;
				}
		}
	},
	evalScripts: function ( str ) {
		var container = J.createElement('div', {setHTML: str}), res = [];
		toArray(container.getElementsByTagName('script')).each(function (el) {
			res.push( eval(el.innerHTML) );
		});
		return res;
	}	
});

extend(J, { // --------------------------------------- >>>  Cookies  <<<
	getCookie: function (name) {
		var result = new RegExp(name + '=([^; ]+)').exec(doc.cookie);
		if (!result) {return null;}
		return unescape(result[1]);
	},
	setCookie: function (name, value, expires, path, domain, secure) {
		if (expires) {expires = new Date(new Date().getTime()+((1000*60*60*24)*expires)).toGMTString();}
		doc.cookie = name + '=' + escape(value) +
			(expires ? ';expires=' + expires : '') + 
			(path ? ';path=' + path : '') +
			(domain ? ';domain=' + domain : '') +	
			(secure ? ';secure' : '');
	},
	removeCookie: function (name, path, domain) {
		if (JELLY.getCookie(name)) {
			doc.cookie = name + '=' +
				(path ? ';path=' + path : '') +
				(domain ? ';domain=' + domain : '') +	
				(';expires=' + new Date(0));
		}
	}
});

extend(J, { // --------------------------------------- >>>  Misc  <<<
	getViewport: function () {
		if (isDefined(win.innerWidth)) {
			return function () {return [win.innerWidth, win.innerHeight];};
		} 
		if (isDefined(rootElement) && isDefined(rootElement.clientWidth) && rootElement.clientWidth !== 0) { 
			return function () {return [rootElement.clientWidth, rootElement.clientHeight];};
		}
		return function () {
			return [doc.body.clientWidth || 0, doc.body.clientHeight || 0];
		};
	}(),
	getWindowScroll: function () {
		if (isDefined(win.pageYOffset)) {
			return function () {return [win.pageXOffset, win.pageYOffset];};
		} 
		return function () {
			if (isDefined(rootElement.scrollTop) && 
				(rootElement.scrollTop > 0 || rootElement.scrollLeft > 0)) {
				return [rootElement.scrollLeft, rootElement.scrollTop];
			}
			return [doc.body.scrollLeft, doc.body.scrollTop];
		};
	}(),
	parseQuery: function (el) {
		el = el || win.location;
		var data = {};
		if (/\?/.test(el.href)) {
			var queries = el.href.split('?')[1].split('&'),
				i = queries.length-1,
				parts;
			do {
				parts = queries[i].split('=');
				data[parts[0]] = parts[1];
			} while (i--);
		}
		return data;
	},
	bindEventListener: function (scope, fn, args) {
		var args = toArray(arguments), scope = args.shift(), fn = args.shift();
		return function (e) { return fn.apply(scope, [e].concat(args)); };
	},
	delay: function (scope, fn, delay, args) {
		var args = toArray(arguments), scope = args.shift(), fn = args.shift(), delay = args.shift();
		return setTimeout( function () { fn.apply(scope, args); } , delay);	
	},
	unpack: function () {
		var str = 'var J=JELLY';
		for (var i in JELLY) { str += (',' + i + '=J.' + i); }
		return str + ';';
	}
});

/*! 
Page routines  */

var classname = ['unknown'], i;
for (i in browser) {
	if (browser[i]) {
		if (classname[0] === 'unknown') {classname = [i];} 
		else {classname.push(i);}
	}
}
J.addClass(rootElement, 'js ' + classname.join(' '));
if (browser.ie6) {try {document.execCommand('BackgroundImageCache', false, true);} catch(ex) {};}
J.addEvent(window, 'unload', J.purgeEventLog);

/*! 
Prototype Extensions */

J.extend(Array.prototype, {
	forEach: function (fn, obj){
		var i = 0, n = this.length;
		for (i; i < n; i++) { fn.call(obj, this[i], i, this); }
	},
	indexOf: function (obj, from) {
		from = isDefined(from) ? 
			(from < 0 ? Math.max(0, this.length + from) : from) : 0;
		for (var i = from, n = this.length; i < n; i++) { if (this[i] === obj) return i; }
		return -1;
	},
	filter: function (fn, obj) {
		var i = 0, n = this.length, arr = [];
		for (i; i < n; i++) { if (fn.call(obj, this[i], i, this)) arr[arr.length] = this[i]; }
		return res;
	},
	map: function (fn, obj) {
		var i = 0, n = this.length, arr = [];
		for (i; i < n; i++) { arr.push(fn.call(obj, this[i], i, this)); }
		return arr;
	},
	some: function (fn, obj) {
		var i = 0, n = this.length;
		for (i; i < n; i++) { if (fn.call(obj, this[i], i, this)) return true; }
		return false;
	},
	every: function (fn, obj) {
		var i = 0, n = this.length;
		for (i; i < n; i++) { if (!fn.call(obj, this[i], i, this)) return false; }
		return true;
	}
}, false);
Array.prototype.each = Array.prototype.forEach;

J.extend(String.prototype, {
	trim: function () {
		return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	}
}, false);

J.extend(Function.prototype, {
	bind: function () {
		if ( arguments.length < 2 && !isDefined(arguments[0]) ) return this;
		var args = toArray(arguments),
			scope = args.shift(),
			fn = this; 
		return function () {
			for (var i = 0; arguments.length > i; i++) { args.push(arguments[i]); }
			return fn.apply(scope, args);
		}
	}
}, false);

/*! 
Selector Engine */

J._Q = {
	'A': function (a, b) {
		try {return toArray(b ? a.querySelectorAll(b) : 
			document.querySelectorAll(a));} catch (ex) {}
	},
	'B': function (a, b) {	
		var toArray = J.toArray, 
			getNext = J.getNext,
			getPrevious = J.getPrevious,
			msie = J.browser.ie,
			win = window,
			doc = win.document,
			loc = win.location,
			rootElement = doc.documentElement,
			unMark = function (collection, mark) {
				var n = collection.length, i = 0;
				for (i; i < n; i++) {collection[i][mark] = undefined;}
			},
			contains = function () {
			    if (rootElement.contains)  { 
			        return function (needle, haystack) {return haystack.contains(needle);};
			    } 
				return function (needle, haystack) {
					return !!(haystack.compareDocumentPosition(needle) & 16);
				};
			}(),
			mergeId = function (tkn) {
				var tag = tkn.val[0], id = tkn.val[1];
				if (tkn.mode === 'filter') { 
					var tags = collection, n = collection.length, i = 0;
					for (i; i < n; i++) {
						if (tag) {
							if ((tags[i].tagName.toLowerCase() === tag && tags[i].id === id) !== tkn.not) {
								tmp[tmp.length] = tags[i]; 
							}
						} else if ((tags[i].id === id) !== tkn.not) {
							tmp[tmp.length] = tags[i]; 
						}
						if (!tkn.not && tmp[0]) {return;}
					}
				} else {
					if (!tag) {
						tmp[0] = doc.getElementById(id);
					} else {
						var elem = doc.getElementById(id);
						if (elem && elem.tagName.toLowerCase() === tag) {
							tmp[0] = elem;	
						}
					}
					if (!firstRun && tmp[0]) {
						var tags = collection, n = collection.length, flag = false, i = 0;
						for (i; i < n; i++) {
							if (contains(tmp[0], tags[i])) {
								flag = true;
								break;
							}
						}
						if (!flag) {tmp[0] = null;}
					} 
				}
			}, 
			mergeTags = function (tkn) {
				var tags, n, test, i = 0, extra = (tkn.val === '*' && msie);
				if (firstRun) {
					tags = doc.getElementsByTagName(tkn.val); n = tags.length;	
					for (i; i < n; i++) {
						if (extra) {if (tags[i].nodeType === 1) {tmp[tmp.length] = tags[i];}}
						else {tmp[tmp.length] = tags[i];}
					}
				} else if (tkn.not || tkn.mode === 'filter') {
					tags = collection; n = tags.length; test = tkn.val.toUpperCase();
					for (i; i < n; i++) {
						if ((tags[i].nodeName.toUpperCase() === test) !== tkn.not) {
							tmp[tmp.length] = tags[i];
						}
					}
				} else {
					tags = collection; 
					n = tags.length;
					for (i; i < n; i++) {
						var tags2 = tags[i].getElementsByTagName(tkn.val), n2 = tags2.length, j;
						for (j = 0; j < n2; j++) {
							if (extra) {if (tags2[j].nodeType === 1) {tmp[tmp.length] = tags2[j];}}
							else {tmp[tmp.length] = tags2[j];}
						}
					}
				}
			},
			mergeClass = function (tkn) {
				var tags = collection, val = tkn.val, not = tkn.not, n = tags.length, i = 0;
				if (tkn.mode === 'fetch') {
					if (firstRun) {
						tmp = toArray(doc.getElementsByClassName(val));
					} else {
						for (i; i < n; i++) {
							var tags2 = tags[i].getElementsByClassName(val), n2 = tags2.length, j = 0;
							for (j; j < n2; j++) {
								tmp[tmp.length] = tags2[j];
							}
						}
					}
				} else {
					var patt = new RegExp('(^|\\s)' + val + '(\\s|$)'), cn;
					for (i; i < n; i++) {
						cn = tags[i].className;
						if (!cn) {
							if (not) {tmp[tmp.length] = tags[i];}
							continue;
						} 
						if (patt.test(cn) !== not) {tmp[tmp.length] = tags[i];} 
					}
				}
			},
			attributeTests = {
				'=': function (attr, val) {return attr === val;}, 
				'^=': function (attr, val) {return attr.indexOf(val) === 0;}, 
				'$=': function (attr, val) {return attr.substr(attr.length - val.length) === val;}, 
				'*=': function (attr, val) {return attr.indexOf(val) !== -1;}, 
				'|=': function (attr, val) {return attr.indexOf(val) === 0;}, 
				'~=': function (attr, val) {return (' ' + attr + ' ').indexOf(' ' + val + ' ') !== -1;} 
			},
			mergeAttribute = function (tkn) {
				var tags = collection, n = tags.length, getAttribute = J.getAttribute, attrValue = tkn.val, i = 0;
				if (/=/.test(attrValue)) {
					var parts = /([\w-]+)([^=]?=)(.+)/.exec(attrValue), attr, mode = attributeTests,
						val = tkn.spValue !== undefined ? tkn.spValue : parts[3];
					for (i; i < n; i++) {
						attr = getAttribute(tags[i], parts[1]);
						if ((attr !== null && mode[parts[2]](attr, val)) !== tkn.not) {
							tmp[tmp.length] = tags[i];
						}
					}
				} else {
					for (i; i < n; i++) {
						if ((getAttribute(tags[i], attrValue) !== null) !== tkn.not) {
							tmp[tmp.length] = tags[i];                    
						}
					}
				}
			},
			mergeDirectSibling = function (tkn) {
				var tags = collection, n = tags.length, next, i = 0;
				for (i; i < n; i++) {
					next = getNext(tags[i]);
					if (next) {tmp[tmp.length] = next;}
				}
			},
			mergeAdjacentSibling = function (tkn) {
				var tags = collection, n = tags.length, store = [], sibs = [], i = 0; 
				for (i; i < n; i++) {
					var parental = tags[i].parentNode;
					parental.__jelly = true;
					store[store.length] = {
						parent: parental, 
						child: tags[i]
					};
				}	
				for (i = 0; i < store.length; i++) {
					if (store[i].parent.__jelly !== undefined) {
						store[i].parent.__jelly = undefined;
						sibs[sibs.length] = store[i].child;
					}
				}
				for (i = 0; i < sibs.length; i++) {
					var next = sibs[i].nextSibling;
					while (next) {
						if (next.nodeType === 1) {tmp[tmp.length] = next;}
						next = next.nextSibling;
					}
				}
			},
			filterChildren = function () {
				var tags = collection, n = tags.length, n2 = tmp.length, result = [], i = 0; 
				for (i; i < n2; i++) {
					var parentElem = tmp[i].parentNode; 
					for (var j = 0; j < n; j++) {  
						if (tags[j] === parentElem) {
							result[result.length] = tmp[i];
							break;
						}
					}
				}
				tmp = result;
			},
			mergePseudo = function (tkn) {
				var tags = collection, n = tags.length, i = 0;
				if (/^(nth-|first-of|last-of)/.test(tkn.kind)) {
					tmp = pseudoTests[tkn.kind](tags, tkn); 
				} else if (tkn.kind === 'root' && !tkn.not) {
					tmp[0] = rootElement;
				} else if (tkn.kind === 'target' && !tkn.not) {
					var hash = loc.href.split('#')[1] || null;
					tmp[0] = doc.getElementById(hash) || doc.getElementsByName(hash)[0];
				} else {
					for (i; i < n; i++) {
						if (pseudoTests[tkn.kind](tags[i], tkn) !== tkn.not) {
							tmp[tmp.length] = tags[i];
						}
					}
				}
			},
			parseNthExpr = function (expr) {
				var obj = {};
				obj.direction = /^\-/.test(expr) ? 'neg' : 'pos';
				if (/^n$/.test(expr)) { 
					obj.mode = 'all';
					return obj;
				} else if (/^\d+$/.test(expr)) {
					obj.mode = 'child';
					obj.val = parseInt(expr, 10);
					return obj;
				} 
				obj.mode = 'an+b';
				if (/^(even|2n|2n\+2)$/.test(expr)) {obj.oddEven = 0;} 
				else if (/^(odd|2n\+1)$/.test(expr)) {obj.oddEven = 1;}
				var pts = expr.split('n');
				obj.start = pts[1] ? parseInt(pts[1], 10) : 1;
				obj.jump = pts[0] && !/^\-$/.test(pts[0]) ? parseInt(pts[0].replace(/^\-/, ''), 10) : 1;		
				return obj;
			},
			nthChildFilter = function (collection, expr, oftype, last, not) {
				expr = parseNthExpr(expr);
				if (expr.mode === 'all') {return collection;}
				var	result = [], parentCache = [], n = collection.length, i = 0,
					nodeName = collection[0].nodeName,
					testType = oftype ? 
						function (el) {return el.nodeType === 1 && el.nodeName === nodeName;} : 
						function (el) {return el.nodeType === 1;},		
					append = function (cond) {if (cond) {result[result.length] = collection[i];}};
				for (i; i < n; i++) {
					var pnt = collection[i].parentNode, c = 1;
					if (!pnt._indexedChilden) {
						parentCache[parentCache.length] = pnt;
						if (!last) {
							for (var el = pnt.firstChild; el; el = el.nextSibling) {
								if (testType(el)) {el.nodeIndex = c++;}
							}
						} else {
							for (var el = pnt.lastChild; el; el = el.previousSibling) {
								if (testType(el)) {el.nodeIndex = c++;}
							}
						}
						pnt._indexedChilden = true;
					}
					if (expr.mode === 'child') { 
						append(((collection[i].nodeIndex === expr.val) !== not));
					} else if (expr.oddEven !== undefined) { 
						append((collection[i].nodeIndex % 2 === expr.oddEven) !== not);
					} else {
						if (expr.direction === 'pos') {
							if (collection[i].nodeIndex < expr.start) {
								if (not) {append(true);} else {continue;}
							} else { 
								append(((collection[i].nodeIndex - expr.start) % expr.jump === 0) !== not);
							}
						} else {
							if (collection[i].nodeIndex > expr.start) {
								if (not) {append(true);} else {continue;}
							} else {
								append(((expr.start - collection[i].nodeIndex) % expr.jump === 0) !== not);
							}
						}
					}
				}
				unMark(parentCache, '_indexedChilden');
				return expr.direction === 'neg' ? result.reverse() : result;
			},
			pseudoTests = {
				'nth-child': function (tags, tkn) {return nthChildFilter(tags, tkn.val, false, false, tkn.not);},
				'nth-of-type': function (tags, tkn) {return nthChildFilter(tags, tkn.val, true, false, tkn.not);},
				'nth-last-child': function (tags, tkn) {return nthChildFilter(tags, tkn.val, false, true, tkn.not);},
				'nth-last-of-type': function (tags, tkn) {return nthChildFilter(tags, tkn.val, true, true, tkn.not);},
				'first-of-type': function (tags, tkn) {return nthChildFilter(tags, '1', true, false, tkn.not);},
				'last-of-type': function (tags, tkn) {return nthChildFilter(tags, '1', true, true, tkn.not);},
				'only-child': function (el) {return !getNext(el) && !getPrevious(el);},
				'only-of-type': function (el) {
					var tags = el.parentNode.getElementsByTagName(el.nodeName);
					if (tags.length === 1 && tags[0].parentNode === el.parentNode) {return true;} 
					else {
						var bool = true, n = tags.length, i = 0, c = 0;
						for (i; i < n; i++) {if (el.parentNode === tags[i].parentNode) {c++; if (c > 1) {return false;}}}
						return true;
					}
				},
				'first-child': function (el) {return !getPrevious(el);},
				'last-child': function (el) {return !getNext(el);}, 
				'checked': function (el) {return el.checked;},
				'enabled': function (el) {return !el.disabled;},
				'disabled': function (el) {return el.disabled;},
				'empty': function (el) {return !el.firstChild;},
				'lang': function (el, tkn) {return el.getAttribute('lang') === tkn.val;},
				'root': function (el) {return el === rootElement;},
				'target': function (el) {
					var hash = loc.href.split('#')[1] || null;
					return el.id === hash || el.name === hash;
				}
			},
			filterUnique = function (collection) {
				var c, n = collection.length, uniques = [];
				while (n) {
					c = collection[--n];
					if (!c.__jelly) {
						c.__jelly = true;
						uniques[uniques.length] = c;
					}
				}
				n = uniques.length;
				while (n) {uniques[--n].__jelly = undefined;}
				return uniques.reverse();
			},
			parseTokenComponent = function (part, fetchOrFilter) {
				var obj = {mode: fetchOrFilter ? 'fetch' : 'filter', not: false};
				if (/^(\w+)?#[^\s]+$/.test(part)) {
					obj.type = 'ID'; obj.val = part.split('#');
				} else if (/^(\w+|\*)$/.test(part)) {
					obj.type = 'TAG'; obj.val = part;
				} else if (/^\.[^\s]+$/.test(part)) { 
					obj.type = 'CLASS';	obj.val = part.replace(/^\./, '');
				} else if (/^\[[^\s]+$/.test(part)) { 
					obj.type = 'ATTR';	obj.val = part.replace(/^\[|\]$/g, '');	
				} else if (/^\+|>|~$/.test(part)) { 
					obj.type = 'COMBI'; obj.val = part;			
				} else if (/^\:not[\s\S]+$/.test(part)) {
					var tmp = part.replace(/^\:not\(|\)$/g, '');
					obj = parseTokenComponent(tmp);
					obj.not = true;
				} else if (/^:[^\s]+$/.test(part)) { 
					var tmp = part.replace(/^\:|\)$/g, '').split('(');
					obj.type = 'PSEUDO'; 
					obj.kind = tmp[0];
					obj.val = tmp[1];
				} 
				return obj;
			},
			parseSelector = function (feed) {
				// Seperate out the combinators + > ~, then split
				var result = [],
					parts = J.normalize( feed.replace(/(>|~(?!=)|\+(?!\d))/g, ' $1 ') ).split(' '),
				    universal = {mode:'fetch', type:'TAG', val:'*'},
				    getByClass = 'getElementsByClassName' in doc,
				    sibling = false;
				for (var i = 0; i < parts.length; i++) { 
					var tmp = parts[i].replace(/([^\(\#\.\[])(:)/g, '$1 $2').
						replace(/([^\(])(\[|\.)/g, '$1 $2').
						replace(/\:not\(\s*/g, ':not(').trim().split(' ');	
					for (var j = 0; j < tmp.length; j++) {
						var obj = parseTokenComponent(tmp[j], !j);
						if (sibling) {
							obj.mode = 'filter';
						} else if (j === 0 && (/PSEUDO|ATTR/.test(obj.type) || (obj.type === 'CLASS' && !getByClass) || obj.not)) {
							result[result.length] = universal;
							obj.mode = 'filter';
						}
						if (tmp[j].indexOf(uniqueKey) !== -1) {
							obj[obj.type === 'ATTR' ? 'spValue' : 'val'] = strings.shift();
						}
						result[result.length] = obj;
						sibling = /^(~|\+)$/.test(obj.val);
					}
				}
				result.postFilter = !(parts.length === 1 || parts.length === 3 && /^[\+~]$/.test(parts[1]));
				return result;
			};
		
		/* ---------------------------------------------------------------------------------------- */
		var selector = b || a,
			quoteMarkTest = /('|")([^\1]*?)\1/,
			_Q = J._Q, 
			uniqueKey = _Q.uniqueKey, 
			firstRun = _Q.firstRun, 
			strings = _Q.strings, 
			m;

		if (firstRun) {
			while (selector.indexOf(uniqueKey) !== -1) {uniqueKey += uniqueKey;}
			m = quoteMarkTest.exec(selector);
			while (m) {
				strings[strings.length] = m[2];
				selector = selector.split(m[0]);
				selector = [selector[0], uniqueKey, selector[1]].join('');   
				m = quoteMarkTest.exec(selector);
			}
		}
		
		// Split and recurse for comma chained selectors
		if (/,/.test(selector)) {
			var combo = [],	parts = selector.split(','), i = 0;
			firstRun = false;
			for (i; i < parts.length; i++) {combo = combo.concat(J.Q(parts[i]));}
			firstRun = true;
			return filterUnique(combo);
		}

		var tokens = parseSelector(selector),
			collection = b ? [a] : [],	
			firstRun = true && !b,
			children = null, 
			k = 0;
		
		for (k; k < tokens.length; k++) {
			var tmp = [], tkn = tokens[k];						
			switch (tkn.type) {
				case 'ID': mergeId(tkn); break;
				case 'TAG': mergeTags(tkn); break;
				case 'CLASS': mergeClass(tkn); break;
				case 'ATTR': mergeAttribute(tkn); break;
				case 'PSEUDO': mergePseudo(tkn); break
				case 'COMBI': 
					if (tkn.val === '+') {mergeDirectSibling(tkn);} 
					else if (tkn.val === '~') {mergeAdjacentSibling(tkn);}
			}
			if (children) {filterChildren();}
			if (tkn.val === '>') {
				children = true;
				continue;
			}
			if (!tmp[0]) {return [];}
			children = null;
			collection = tmp;
			firstRun = false;	
		}
		if (tokens.postFilter) {return filterUnique(collection);}
		return collection;
	},
	strings: [],
	uniqueKey: '@@',
	firstRun: true
};
J.Q = function () {
	if ('querySelectorAll' in doc) {
		if (!browser.ie) { 
			return J._Q.A; 
		} 
		return function (a, b) {
			if (/\:(nth|las|onl|not|tar|roo|emp|ena|dis|che)/.test(b || a)) { 
				return J._Q.B(a, b); 
			}
			return J._Q.A(a, b);
		}
	} 
	return J._Q.B;
}();


/*! 
Request Class */

J.Request = defineClass({
	Constructor: function (obj) { 
		extend(this, obj || {}); 
	},
	Static: {
		transId: 0,
		getFieldData: function ( elements ) {
			var append = function (name, val) {
					data[data.length] = name + '=' + encodeURIComponent(val).replace(/%20/g, '+');
				}, 
				data = [], 
				i = 0;
			for (i; i < elements.length; i++) {
				var field = elements[i], 
					name = field.name, 
					value = field.value;
				switch ( field.type.toLowerCase() ) {
					case 'checkbox': 
						if ( field.checked ) {
							append(name, value || 'on');
						}
						break;
					case 'radio': 
						if ( field.checked ) {
							append( name, value );
						}
						break;
					default: 
						append( name, value );
				}
			}
			return data.join('&');
		}
	},
	fireEvent: fireEvent,
    timeout: 15000,
	noCache: true,
	async: true,
	cleanUp: true,
	feedback: { start: _function, stop: _function },
	requestHeaders: {},
	
	configure: function (obj) {
		extend(this, obj || {});
		return this;
	},
	
	send: function ( method, request, callback ) {
		var self = this, 
			file = request, 
			data = null, 
			method = method.toUpperCase(),
			xhr = self.xhr ? self.xhr : self.getXHR();
        
		// For error reporting
		self.file = request;
		if ( self.inProgress || !xhr ) { 
			return false; 
		}
		
		if ( method === 'POST' ) {
			var tmp = request.split('?');
			file = tmp[0];
			data = tmp[1];
			self.requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
            self.requestHeaders['Content-length'] = data.length;
        } 
		if ( method === 'GET' && self.noCache ) { 
			self.requestHeaders['If-Modifed-Since'] = 'Sat, 1 Jan 2000 00:00:00 GMT';
		}
		
		xhr.open( method, file, self.async );
		xhr.onreadystatechange = function () {
            if ( xhr.readyState === 4 ) {
				self.fireEvent('complete', xhr);
				clearTimeout(self.timer);
				self.feedback.stop();
				var status = xhr.status,
					statusOk = ( status >= 200 && status < 300 ) || status === 304 || 
					( status === undefined && browser.webkit );
				if ( statusOk ) { 
					self.fireEvent('success', xhr);
					if ( callback ) { 
						callback.call(self, xhr); 
					} 
				} 
				else {
					self.fireEvent('fail', xhr);
				}
				if ( self.cleanUp ) { 
					self.xhr = null; 
				}
				self.inProgress = false;
            }
        };
		
		for (var key in self.requestHeaders) { 
			xhr.setRequestHeader(key, self.requestHeaders[key]); 
		}
		xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 
		
		self.feedback.start();
		self.timer = setTimeout(function () {
					xhr.abort(); 
					self.fireEvent('timeout', xhr);				
					self.inProgress = false;
				}, 
				self.timeout);

		xhr.send(data);
		self.fireEvent('request', xhr);
		self.inProgress = true;
		
        return true;
    },
	post: function ( file, data, callback ) {
		return this.send( 'post', file + '?' + (data || 'empty'), callback );
	},
	get: function ( request, callback ) {
		return this.send( 'get', request, callback );
	},
    getXHR: function () {
        if ('XMLHttpRequest' in win) { 
			return function () { 
				return new XMLHttpRequest(); 
			}; 
		}
        return function () {
            var xhr = false;
            try {xhr = new ActiveXObject('Msxml2.XMLHTTP');} catch (ex) {
                try {xhr = new ActiveXObject('Microsoft.XMLHTTP');} catch (ex) {}}
            return xhr;
        };
    }()
});


/*! 
Animation Module. Credits: Moofx, Transition equations by Robert Penner. */

J.Transitions={linear:function(B,A,D,C){return D*B/C+A},quadIn:function(B,A,D,C){return D*(B/=C)*B+A},quadOut:function(B,A,D,C){return -D*(B/=C)*(B-2)+A},quadInOut:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B+A}return -D/2*((--B)*(B-2)-1)+A},cubicIn:function(B,A,D,C){return D*(B/=C)*B*B+A},cubicOut:function(B,A,D,C){return D*((B=B/C-1)*B*B+1)+A},cubicInOut:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B+A}return D/2*((B-=2)*B*B+2)+A},quartIn:function(B,A,D,C){return D*(B/=C)*B*B*B+A},quartOut:function(B,A,D,C){return -D*((B=B/C-1)*B*B*B-1)+A},quartInOut:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B*B+A}return -D/2*((B-=2)*B*B*B-2)+A},quintIn:function(B,A,D,C){return D*(B/=C)*B*B*B*B+A},quintOut:function(B,A,D,C){return D*((B=B/C-1)*B*B*B*B+1)+A},quintInOut:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B*B*B+A}return D/2*((B-=2)*B*B*B*B+2)+A},sineIn:function(B,A,D,C){return -D*Math.cos(B/C*(Math.PI/2))+D+A},sineOut:function(B,A,D,C){return D*Math.sin(B/C*(Math.PI/2))+A},sineInOut:function(B,A,D,C){return -D/2*(Math.cos(Math.PI*B/C)-1)+A},expoIn:function(B,A,D,C){return(B==0)?A:D*Math.pow(2,10*(B/C-1))+A},expoOut:function(B,A,D,C){return(B==C)?A+D:D*(-Math.pow(2,-10*B/C)+1)+A},expoInOut:function(B,A,D,C){if(B==0){return A}if(B==C){return A+D}if((B/=C/2)<1){return D/2*Math.pow(2,10*(B-1))+A}return D/2*(-Math.pow(2,-10*--B)+2)+A},circIn:function(B,A,D,C){return -D*(Math.sqrt(1-(B/=C)*B)-1)+A},circOut:function(B,A,D,C){return D*Math.sqrt(1-(B=B/C-1)*B)+A},circInOut:function(B,A,D,C){if((B/=C/2)<1){return -D/2*(Math.sqrt(1-B*B)-1)+A}return D/2*(Math.sqrt(1-(B-=2)*B)+1)+A},elasticIn:function(C,A,G,F,B,E){if(C==0){return A}if((C/=F)==1){return A+G}if(!E){E=F*0.3}if(!B){B=1}if(B<Math.abs(G)){B=G;var D=E/4}else{var D=E/(2*Math.PI)*Math.asin(G/B)}return -(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A},elasticOut:function(C,A,G,F,B,E){if(C==0){return A}if((C/=F)==1){return A+G}if(!E){E=F*0.3}if(!B){B=1}if(B<Math.abs(G)){B=G;var D=E/4}else{var D=E/(2*Math.PI)*Math.asin(G/B)}return B*Math.pow(2,-10*C)*Math.sin((C*F-D)*(2*Math.PI)/E)+G+A},elasticInOut:function(C,A,G,F,B,E){if(C==0){return A}if((C/=F/2)==2){return A+G}if(!E){E=F*(0.3*1.5)}if(!B){B=1}if(B<Math.abs(G)){B=G;var D=E/4}else{var D=E/(2*Math.PI)*Math.asin(G/B)}if(C<1){return -0.5*(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A}return B*Math.pow(2,-10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E)*0.5+G+A},backOffset:1.70158,backIn:function(B,A,E,D,C){if(!C){C=J.Transitions.backOffset}return E*(B/=D)*B*((C+1)*B-C)+A},backOut:function(B,A,E,D,C){if(!C){C=J.Transitions.backOffset}return E*((B=B/D-1)*B*((C+1)*B+C)+1)+A},backInOut:function(B,A,E,D,C){if(!C){C=J.Transitions.backOffset}if((B/=D/2)<1){return E/2*(B*B*(((C*=(1.525))+1)*B-C))+A}return E/2*((B-=2)*B*(((C*=(1.525))+1)*B+C)+2)+A},bounceIn:function(B,A,D,C){return D-J.Transitions.bounceOut(C-B,0,D,C)+A},bounceOut:function(B,A,D,C){if((B/=C)<(1/2.75)){return D*(7.5625*B*B)+A}else{if(B<(2/2.75)){return D*(7.5625*(B-=(1.5/2.75))*B+0.75)+A}else{if(B<(2.5/2.75)){return D*(7.5625*(B-=(2.25/2.75))*B+0.9375)+A}else{return D*(7.5625*(B-=(2.625/2.75))*B+0.984375)+A}}}},bounceInOut:function(B,A,D,C){if(B<C/2){return J.Transitions.bounceIn(B*2,0,D,C)*0.5+A}return J.Transitions.bounceOut(B*2-C,0,D,C)*0.5+D*0.5+A}};

J.Tween = defineClass({
	Constructor: function (el, opts) {
		this.el = J.getElement(el);
		extend(this, opts || {}); 
	},
	transition: J.Transitions.sineInOut,
	duration: 500,
	unit: 'px',
	timerSpeed: 20,
	onComplete: function () {},
	setDuration: function (val) {
		this.duration = val;
		return this;
	},
	setTransition: function (val) {
		this.transition = J.Transitions[val];
		return this;
	},
	setOpacity: function (val) {
		J.setOpacity(this.el, val);
		return this;
	},
	chain: function (fn) {
		this.chains = this.chains || [];
		this.chains.push(fn);
		return this;
	},
	stop: function () {
		clearInterval(this.timer);
		this.timer = null;
		return this;
	},
	start: function (props, values) {
		var t = this,
			isArray = J.isArray,
			parseColour = J.parseColour,
			getStyle = J.getStyle;
		if (t.timer) {
			clearInterval(t.timer);
		}
		if (isArray(props)) {
			t.props = props;
			t.vals = values;
		} 
		else {
			t.props = [props];
			t.vals = [values];
		}
		var i = t.vals.length - 1;
		do {
			t.props[i] = J.toCamelCase(t.props[i]);
			if (/color/i.test(t.props[i])) {
				if (!isArray(t.vals[i])) {
					t.vals[i] = [
						parseColour(getStyle(t.el, t.props[i]), 'rgb-array'), 
						parseColour(t.vals[i], 'rgb-array')];
				} 
				else {
					t.vals[i] = [
						parseColour(t.vals[i][0], 'rgb-array'), 
						parseColour(t.vals[i][1], 'rgb-array')];
				}
				t.vals[i].color = true;
			} 
			else if (/backgroundPosition/.test(t.props[i])) {
				if (!isArray(t.vals[i])) {
					t.vals[i] = [[0, t.vals[i]], [0, 0]];
				} 
				else if (!isArray(t.vals[i][0])) {
					t.vals[i] = [[0, t.vals[i][0]], [0, t.vals[i][1]]];
				} 
				t.vals[i].backgroundPosition = true;
			} 
			else {
				if (!isArray(t.vals[i])) {
					t.vals[i] = [getStyle(t.el, t.props[i], true), t.vals[i]]; 
				}
			}
		} while (i--)
		t.startTime = new Date().getTime();
		t.timer = setInterval(function () {t.step.call(t)}, t.timerSpeed);
		return t;
	},
	step: function () {
		var t = this, currentTime = new Date().getTime();
		if (currentTime < t.startTime + t.duration) {
			t.elapsedTime = currentTime - t.startTime;
		} 
		else {
			t.stop();
			t.tidyUp();
			t.onComplete();
			return t.callChain();
		}
		t.increase();
	},
	tidyUp: function () {
		var t = this, i = t.props.length - 1;
		do {
			if (t.vals[i].color) {t.el.style[t.props[i]] = 'rgb(' + t.vals[i][1].join(',') + ')';} 
			else if (t.vals[i].backgroundPosition) {
				t.el.style.backgroundPosition = 
					t.vals[i][0][1] + t.unit + ' ' + 
					t.vals[i][1][1] + t.unit;
			} 
			else {t.setStyle(t.props[i], t.vals[i][1]);}
		} while (i--)
	},
	increase: function () {
		var t = this, 
			i = t.props.length - 1,
			round = Math.round;
		do {
			if (t.vals[i].color) {
				t.el.style[t.props[i]] = 'rgb(' + 
					round(t.compute(t.vals[i][0][0], t.vals[i][1][0])) + ',' +
					round(t.compute(t.vals[i][0][1], t.vals[i][1][1])) + ',' +
					round(t.compute(t.vals[i][0][2], t.vals[i][1][2])) + ')';
			} 
			else if (t.vals[i].backgroundPosition) {
				t.el.style.backgroundPosition = 
					t.compute(t.vals[i][0][0], t.vals[i][0][1]) + t.unit + ' ' + 
					t.compute(t.vals[i][1][0], t.vals[i][1][1]) + t.unit;
			} 
			else {t.setStyle(t.props[i], t.compute(t.vals[i][0], t.vals[i][1]));}
		} while (i--)
	},
	compute: function (from, to) {
		return this.transition(this.elapsedTime, from, (to - from), this.duration);
	},
	setStyle: function (p, val) {
		if (p === 'opacity') {this.setOpacity(val);} 
		else {this.el.style[p] = val + this.unit;}
	},
	setBackgroundPosition: function (val) {
		this.el.style.backgroundPosition = val[0] + this.unit + ' 0';
	},
	callChain: function () {
		var t = this;
		if (t.chains && t.chains.length) {
			setTimeout(function () {(t.chains.shift()).call(t)}, 10);
		}
	}
});

/*! 
Scroll Class */

J.Scroll = defineClass({
	Extends: J.Tween,
	Constructor: function (el, opts) {
		this.el = J.getElement(el);
		extend(this, opts || {}); 
	},
	start: function (x, y) {
		var t = this, 
			el = t.el,	
			isArray = J.isArray;
		if (t.timer) {clearInterval(t.timer);}
		if (el === window) {
			var winpos = J.getWindowScroll();
			if (!isArray(x)) {x = [winpos[0], x];}
			if (!isArray(y)) {y = [winpos[1], y];}
			t.increase = function () {
				el.scrollTo(t.compute(t.vals[0][0], t.vals[0][1]), t.compute(t.vals[1][0], t.vals[1][1]));
			};
		} else {
			if (!isArray(x)) {x = [el.scrollLeft, x];}
			if (!isArray(y)) {y = [el.scrollTop, y];}
			t.increase = function () {
				el.scrollLeft = t.compute(t.vals[0][0], t.vals[0][1]); 
				el.scrollTop = t.compute(t.vals[1][0], t.vals[1][1]); 				
			};
		}
		t.vals = [x, y];
		t.startTime = new Date().getTime();
		t.timer = setInterval(function () {t.step.call(t)}, t.timerSpeed);
		return t;
	},
	tidyUp: function () {
		var t = this;
		if (t.el === window) {t.el.scrollTo(t.vals[0][1], t.vals[1][1]);} 
		else {
			t.el.scrollLeft = t.vals[0][1]; 
			t.el.scrollTop = t.vals[1][1]; 
		}
	} 
});


/*!
Dialog */
//
//	'Dialog' is a singleton for handling modal windows
//  
J.Dialog = {
	
	// Default values
	top: 40,
	width: 600,
	draggable: false,
	
	// For speeding up initial rendering
	cacheAssets: function (args) {
		args = isArray(args) ? args : toArray(arguments);
		this._cache = this._cache || [];
		for (var i = 0; i < args.length; i++) {
			var img = new Image();
			img.src = args[i];
			this._cache.push(img);
		}
	},
	
	// Hack for IE6 only: prevents select boxes from punching through the display
	iFrameShim: J.createElement('iframe#iframe-dialog-shim frameBorder:0, scrolling:no'),
	
	setTop: function (y, unit) {
		y = this.top = y || this.top;
		this.container.style.top = y + (unit || 'px'); 
		return this;
	},
	setWidth: function (w) {
		w = this._width = w || this.width;
		this.body.style.width = w + 'px'; 
		this.handle.style.width = (w - 54) + 'px';
		return this;
	},
	setContent: function (title, content) {
		if (content) { content = '<h2>' + title + '</h2>' + content; } 
		this.content.innerHTML = content || title || 'No content supplied';
		return this;
	},
	open: function (w) {
		if ( this.visible ) { return; } 
		this.setWidth(w);
		J.insertElement( this.overlay );
		if ( browser.ie6 ) { 
			J.insertElement( this.iFrameShim ); 
		}
		J.insertElement( this.container );
		this.container.style.top = this.top + J.getWindowScroll()[1] + 'px';
		this.visible = true;
	},

	close: function () {
		if (! this.visible ) { return; } 
		J.removeElement( this.overlay );
		if ( browser.ie6 ) { 
			J.removeElement( this.iFrameShim ); 
		}		
		J.removeElement( this.container ); 
		this.container.style.position = '';
		this.body.style.position = '';
		this.visible = false;
	},
	
	// Initializer
	init: function () {
		if (this.ready) { return; }
		var c = J.createElement,
			branch = J.createBranch,
			self = this,
			top = branch(
				'span.dialog-top',
					['span.dialog-top-1', 
					 'span.dialog-top-2']
				),
			btm = branch(
				'span.dialog-btm',
					['span.dialog-btm-1', 
					 'span.dialog-btm-2']
				),
			centre = branch(
				'.dialog-trim-1',
					['span.dialog-left', 
					 'div.dialog-trim-2']
				),
			wrap = branch(
				'.dialog-container',
					'.dialog-body'
				),
			centreDiv = self.centreDiv = centre.div[1]; 
			
		self.content = centreDiv.appendChild(c('div', {'class':'dialog-content', setText:'#'}));
		self.handle = centreDiv.appendChild(c('span', {'class':'dialog-handle'}));
		self.btn_close = centreDiv.appendChild(c('a', {
			'class':'dialog-close', 
			'href':'javascript:;', 
			setText: 'Close', 
			'title':'You can also press escape key to close' }));		
		
		wrap.div[1].appendChild(top.root);
		wrap.div[1].appendChild(centre.root);
		wrap.div[1].appendChild(btm.root);
		
		self.overlay = c('div', {'class': 'dialog-screen'});
		self.container = wrap.root;
		self.body = wrap.div[1];
	
		J.addEvent( self.btn_close, 'click', self.close.bind(self) );
		J.addEvent( doc, 'keypress', function (e) {
			if (e.keyCode && e.keyCode === 27 && self.visible) { self.close(); } 
		});
		
		if (arguments.length) { self.cacheAssets( toArray(arguments) ); } 
		self.tween = new J.Tween(self.container, {duration:100});
		
		var trace = function (msg) { if (0) { J.trace(msg); } },
			cancelDrag = function () {
				trace('cancel');
				trace('-------------------------');
				[self.onMouseMove, self.onMouseOut].each( J.removeEvent );
				self.container.style.cursor = '';
				dragStarted = false;
			},
			dragStarted = false;
		
		self.onMouseDown = J.addEvent( self.handle, 'mousedown', function (e) {
				trace('mousedown');
				if ( dragStarted ) { 
					cancelDrag(); 
					return;
				}
				e = J.stopEvent(e);
				var viewport = J.getViewport(),
					boundTolerence = [10, 25, 10, 10],
					dims,
					offsetX,
					offsetY,
					startX,
					startY,
					positionDialog = function (e) {
						J.setXY( self.body, e.pageX - offsetX, e.pageY - offsetY);
					};
								
				self.onMouseMove = J.addEvent( document, 'mousemove', function (e) {
					e = J.stopEvent(e);
					var bounds = {
						yMin: !(e.clientY < boundTolerence[0]),
						xMax: !(e.clientX > (viewport[0] - boundTolerence[1])),
						yMax: !(e.clientY > (viewport[1] - boundTolerence[2])),
						xMin: !(e.clientX < boundTolerence[3])
					};
					inbounds = bounds.xMin && bounds.xMax && bounds.yMin && bounds.yMax;
					if ( !inbounds ) {
						cancelDrag();
						var left = parseInt(self.body.style.left, 10);
						var top = parseInt(self.body.style.top, 10);
						if (!bounds.xMin) { self.body.style.left = (left+20) + 'px'; }
						if (!bounds.xMax) { self.body.style.left = (left-20) + 'px'; }
						if (!bounds.yMin) { self.body.style.top = (top+20) + 'px'; }
						if (!bounds.yMax) { self.body.style.top = (top-20) + 'px'; }
					} else if ( dragStarted ) {
						positionDialog(e);
					} else {
						trace('drag start');
						dragStarted = true;
						dims = J.getXY( self.body );
						containerDims = J.getXY( self.container );
						self.container.style.position = 'static';
						self.container.style.cursor = 'move';
						self.body.style.position = 'absolute';
						offsetX = e.pageX - dims[0];
						offsetY = e.pageY - dims[1];
						positionDialog(e);
					} 
				});
			});
		self.onMouseUp = J.addEvent( self.handle, 'mouseup', function () {
			trace('mouseup');
			cancelDrag();
		});
		
		self.ready = true;
		return this;
	}
};

/*!
Feedback */
//
//	'Feedback' is a singleton for handling ajax loading spinners
//  
//  Example (already initialized): 
//		FeedbackSolo.start(object, mode, offset);
//
J.FeedbackSolo = {

	setPosition: function () {},
	
	settings: {
		image: 'dark_on_light', 
		mode: 'right',
		offset: [10, 0]
	},
	
	initialized: false,
	
	init: function (path1, path2) {
		if (this.initialized) {return;}
		this.images = {
			dark_on_light: J.createElement('img', {src: path1}),
			light_on_dark: J.createElement('img', {src: path2})
		};
		this.img = J.createElement('img', {alt: 'Loading... please wait'});
		this.container = J.createElement('span', {'id':'ui-feedback-indicator'});
		this.container.appendChild(this.img);
		var that = this;
		this.onWindowUpdate = J.addEvent(window, 'resize', function () {that.setPosition();}); 
		this.initialized = true;
	},
	
	pause: 300,
	timeout: 10000,

	getPositioningHandler: function (datum, mode, offset) {
		var container = this.container;
		return function () {
			var coords = J.getXY(datum);
			var height = datum.offsetHeight;
			var width = datum.offsetWidth;
			var top = coords[1] + offset[1];
			var btm = top + height;
			var left = coords[0] + offset[0];
			var right = left + width;
			var moveTo = function (x, y) { J.setXY(container, x, y); };
			switch (mode) {
				case 'left': moveTo(left, top); break;
				case 'right': moveTo(right, top); break;
			}
		};
	},
	
	start: function (datum, mode, offset, image) {
		var that = this;
		this.setPosition = this.getPositioningHandler(
			J.getElement(datum), 
			mode || this.settings.mode, 
			offset || this.settings.offset);
			
		if (image) {
			this.img.src = this.images[image].src;
		} else {
			this.img.src = this.images[this.settings.image].src;
		}
		
		this.setPosition();
		this.pauseTimer = setTimeout(function () {
			J.insertElement( that.container );
			that.stopTimer = setTimeout( that.stop.bind(that), that.timeout );
			that.visible = true;
		}, this.pause );
	},
	
	stop: function () {
		clearTimeout(this.stopTimer);
		clearTimeout(this.pauseTimer);
		if ( this.visible ) { J.removeElement( this.container ); }
		this.visible = false;
	}
};


J.Feedback = {

	ready: false,
	
	init: function () {
		if ( this.ready ) return this;
		this.content = J.createElement('span', {'setText': 'Loading...'});
		this.container = J.createElement('div', {'id':'feedback-indicator'});
		this.container.appendChild(this.content);
		
		J.insertElement(this.container);
		var containerImg = J.getStyle(this.container, 'background-image');
		var contentImg = J.getStyle(this.content, 'background-image');
		J.removeElement(this.container);

		var patt = /url\(([\S\s]+)\)$/, m;
		if ( m = patt.exec(containerImg) ) {
			this.assets.push( J.createElement('img', {'src': m[1]}) );
		} 
		if ( m = patt.exec(contentImg) ) {
			this.assets.push( J.createElement('img', {'src': m[1]}) );
		} 
		this.ready = true;
		return this;
	},
	
	assets: [],
	pause: 400,
	timeout: 10000,
	holdQueue: [],
		
	start: function () {
		this.clearTimers();
		this.startTimers();
	},
	
	startTimers: function () {
		var self = this;
		this.pauseTimer = setTimeout(function () {
			if ( !self.visible ) {J.insertElement( self.container );}
			self.visible = true;
			self.stopTimer = setTimeout( self.stop.bind(self), self.timeout );
		}, self.pause );
	},
	
	clearTimers: function () {
		if (this.stopTimer) { clearTimeout(this.stopTimer); };
		if (this.pauseTimer) { clearTimeout(this.pauseTimer); };
	},
	
	stop: function () {
		this.clearTimers();
		if ( this.visible ) { 
			J.removeElement( this.container ); 
			this.visible = false;
		}
	}
		
};

/*!
Growl */
//
//	'Growl' is a singleton for notification boxes
//  
//
J.debug = true;
J.Growl = {
	showtime: 3000,
	setMessage: function (message) {
		this.container.innerHTML = this.message = message;
		return this;
	},
	queue: [],
	filterQueue: function () {
		var uniques = [];
		this.queue.each(function (o) {
			var flag = true;
			uniques.each(function (j) {	if (o === j) { flag = false; } });
			if (flag) {
				uniques.push(o);	
			} 
		}); 
		this.queue = uniques;
	},
	show: function (message) {
		if (this.visible) {
			// Stop multiple repeat messages
			if (message !== this.message) { this.queue.push(message); }
			this.filterQueue();
			return;
		} 
		this.setMessage(message);
		this.tween.setOpacity(0);
		if (!this.available) { 
			J.insertElement( this.container ); 
			this.available = true; 
		};		
		var that = this;
		
		// A micro delay while DOM gets aquainted with new node
		setTimeout( 
			function () { 
				that.tween.onComplete = function () {};
				that.tween.start('opacity', 1); 
			}, 10);
		this.timer = setTimeout( 
			function () { 
				that.tween.onComplete = function () { that.close();	};
				that.tween.start('opacity', 0); 
			}, this.showtime);
		this.visible = true;
	},
	close: function () {
		this.tween.stop().setOpacity(0);
		clearTimeout(this.timer);
		this.visible = false;
		if (this.queue.length > 0) {
			this.show( this.queue.pop() );
		} else {
			J.removeElement( this.container );
			this.available = false;
		}
	},
	init: function () {
		if (this.ready) { return; }
		var c = J.createElement;
		var branch = J.createBranch;
		this.container = c('div', {'id': 'growl-box'});
		J.addEvent( this.container, 'click', this.close.bind(this) );
		var that = this;
		this.ready = true;
		this.tween = new J.Tween(this.container, {duration:500});
		return this;
	}
};

/*!
Calendar */
//
//
// Calendar
//
J.Calendar = function (inputId, mode, opts) {
	var c = J.createElement,
		branch = J.createBranch(
			'.j-cal',
				'.j-cal-trim',
				['.j-cal-title',
				 '.j-cal-back title:"Previous Month", setHTML:&laquo;', 
				 '.j-cal-next title:"Next Month", setHTML:&raquo;', 
				 '.j-cal-table']
		);
		
	this.root = branch.root;
	this.table = branch.div[5];
	this.next = branch.div[4];
	this.back = branch.div[3];
	this.title = branch.div[2];
	this.calendar = branch.div[0];
	this.btn_close = this.calendar.appendChild( c('div', {'class':'j-cal-close', setHTML:'x Close'}) );
	this.mode = mode;
	this.visible = false;
	this.offset = opts.offset || [0,0];
	
	this.btn_open = J.createElement('img', {'class':'j-cal-open', 
		src:'_assets/images/skin/icons/calendar.png', alt:'Select start week', title:'Select start week'})
	this.input = J.getElement(inputId);
	J.insertAfter(this.btn_open, this.input);

	var that = this;
	this.btn_open.onmousedown = function (e) {
		var xy = J.getXY(this);
		that.calendar.style.position = "absolute";
		that.calendar.style.left = xy[0] + that.offset[0] + 'px'; 
		that.calendar.style.top = xy[1] + that.offset[1] + 'px';
		that.setDate();
		that.prepareTable();
		J.Calendar.closeAll();
		that.open();
	};
	
	this.btn_close.onmousedown = this.close.bind(this);
	
	this.btn_open.onclick =
	this.calendar.onclick = J.stopEvent;
	
	this.idPrefix = 'jcal-' + (++J.Calendar.guid);
	this.setDate();
	this.prepareTable();
	this.tween = new J.Tween(this.calendar, {duration: 100}); 
	
	this.next.onmousedown = function (e) {
		that.date.setMonth(that.date.getMonth() + 1);
		that.prepareTable();
	};
	this.back.onmousedown = function (e) {
		that.date.setMonth(that.date.getMonth() - 1);
		that.prepareTable();
	};
	
	J.Calendar.log.push(this);
};

J.Calendar.log = [];
J.Calendar.closeAll = function () {
	this.log.each(function (o) { o.close(); });
};

J.Calendar.prototype = {
	setDate: function () {
		this.values = this.getValue().split('-');
		this.year = parseInt(this.values[0], 10);
		this.month = parseInt(this.values[1], 10);
		this.day_number = parseInt(this.values[2], 10);
		this.date = new Date;
		this.date.setFullYear(this.year, this.month-1, this.day_number);
		if ( isNaN(this.date) || this.date.toString() === 'Invalid Date' ) {
			this.date = new Date;
		}
	},

	close: function () {
		if ( !this.visible ) { return; }
		J.removeElement( this.root );
		this.visible = false;
	},
	
	open: function () {
		document.body.appendChild( this.root );
		this.tween.setOpacity(0);
		this.tween.start('opacity', 1);
		this.visible = true;
	},
	
	getValue: function () {
		return this.input.value.split('-').reverse().join('-');
	},
	
	setValue: function (val) {
		this.input.value = val.split('-').reverse().join('-');
	},
	
	renderDate: function (date) {
		var daysInMonth = function (date) {
				return 32 - new Date(date.getFullYear(), date.getMonth(), 32).getDate();
			},
			firstDayInMonth = function (date) {
				var date = new Date(date.getFullYear(), date.getMonth());
				date.setDate(0);
				return date.getDay();
			},
			ifCurrent = function (str, className) {
				if (str.join('-') === this.input.value) {
					className.push("selected");
					selected_week = true;
				} 
			},
			addLeadingZero = function (n) { return n < 10 ? '0' + n : n; };
	
		var startDay = firstDayInMonth(date), 
			_daysInMonth = daysInMonth(date),
			_daysInPrevousMonth = daysInMonth(new Date(date.getFullYear(), date.getMonth() - 1)),
			counter_2 = 1,
			counter = 1, 
			str = '<table><tbody><tr>' +
				  '<th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>',
			selected_week = false;
				  
		for (var i = 0, j, k; i < 6; i++) {
			var tmp = '';
			
			if (i === 0) {
				for (j = 0, k = 1; j < 7; j++, k++) {
					var className = j === 5 || j === 6 ? ['weekend'] : [];
					var date_string, day, month, year, content = '?';
					
					if (k > startDay) {
						year = date.getFullYear();
						month = addLeadingZero(date.getMonth() + 1);
						day = addLeadingZero(counter);
						ifCurrent.call(this, [day, month, year], className);
						content = counter++;
					} else {
						className.push('otherMonth');
						content = (_daysInPrevousMonth++ - startDay + 1);
						year = date.getFullYear();
						month = addLeadingZero(date.getMonth());
						day = addLeadingZero(content);
						if ( month < 1 ) {
							month = '12';
							year--;
						} 
					}
					tmp += '<td id="' + [this.idPrefix, year, month, day].join('-') + '"';
					tmp += ' class="' + className.join(' ');
					tmp += '">';
					tmp += content;
					tmp += '</td>\n';
				}		
			
			} else {
			
				for (j = 0, k = counter; j < 7; j++, k++) {
					var className = j === 5 || j === 6 ? ['weekend'] : [];
					var date_string, day, month, year, content = '?';
					
					if (k < _daysInMonth + 1) {
						year = date.getFullYear();
						month =  addLeadingZero(date.getMonth() + 1);
						day = addLeadingZero(counter);
						ifCurrent.call(this, [day, month, year], className);
						content = counter++;
					} else {
						content = counter_2++;						
						month = addLeadingZero(date.getMonth() + 2),
						year = date.getFullYear(),
						day = addLeadingZero(content);
						if ( month > 12 ) {
							month = '01';
							year++;
						} 
						className.push('otherMonth');
					}
					tmp += '<td id="' + [this.idPrefix, year, month, day].join('-') + '"';
					tmp += ' class="' + className.join(' ');
					tmp += '">';
					tmp += content;
					tmp += '</td>\n';
				}		
			}
			str += (selected_week ? '<tr class="selected-week">' : '<tr>') + tmp + '</tr>\n';
			selected_week = false;
		}
		return str + '</tbody></table>';
	},

	setTitle: function (date) {
		var word = function () {
			switch (date.getMonth()) {
				case 0: return 'January';
				case 1: return 'February';
				case 2: return 'March';
				case 3: return 'April';
				case 4: return 'May';
				case 5: return 'June';
				case 6: return 'July';
				case 7: return 'August';
				case 8: return 'September';
				case 9: return 'October';
				case 10: return 'November';
				case 11: return 'December';
			}
		}();
		this.title.innerHTML = word + ' ' + date.getFullYear(); 
	}, 

	prepareTable: function () {
		this.table.innerHTML = this.renderDate(this.date);
		this.setTitle(this.date);
		var tds = this.table.getElementsByTagName('td'),
			trs = this.table.getElementsByTagName('tr'),
			clearClassNames = function (tds) {
				for (var i = 0; i < tds.length; i++) { 
					J.removeClass(tds[i], 'selected'); 
				}
			};
		var i = tds.length-1, that = this;
		do {
			if (tds[i].id) {
				tds[i].onclick = function () {
					that.setValue( that.mode === 1 ?
							J.getFirst(this.parentNode).id.replace(that.idPrefix + '-', '') :
							J.getLast(this.parentNode).id.replace(that.idPrefix + '-', '')
						);
					that.setDate();
					J.addClass(this.parentNode, 'selected'); 
					that.close();
				};
			}
		} while(i--);
	}
};



var pix = screen.width * screen.height;
var htmlClassName = 'res-' + ( pix<=800*600 ? 's' : (pix===1024*768 ? 'm' : 'l') );
if ( screen.height === 800) {
	htmlClassName = 'res-m';
}
J.addClass( rootElement, htmlClassName );


extend(J, {

	getFlashVersion: function () {
		var version = {major: null, build: null},
			description,
			versionString,
			aXflash;
		if (navigator.plugins && typeof navigator.plugins['Shockwave Flash'] === 'object') {
			description = navigator.plugins['Shockwave Flash'].description;
			if (description !== null) {
				versionString = description.replace(/^[^\d]+/, '');
				version.major = parseInt(versionString.replace(/^(.*)\..*$/, '$1'), 10);
				version.build = parseInt(versionString.replace(/^.*r(.*)$/, '$1'), 10);
			}
		} else if (JELLY.browser.ie) {
			try {
				aXflash = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
				description = aXflash.GetVariable('$version');
				if (description !== null) {
					versionString = description.replace(/^\S+\s+(.*)$/, '$1').split(',');
					version.major = parseInt(versionString[0], 10);
					version.build = parseInt(versionString[2], 10);
				}
			} catch(ex) {}
		}
		return version;
	},

	loadModule: function (namespace, path, callback) {
		namespace = namespace.split('.');
		if (namespace[0] === 'window') { namespace.shift(); } 
		var head = doc.getElementsByTagName('head')[0],
			script = doc.createElement('script'),
			timeout = 1000,
			polltotal = 0,
			polltime = 15,
			poller = function () {
				var _namespace = window, ready = true;
				for (var i = 0; i < namespace.length; i++) {
					_namespace = _namespace[namespace[i]];
					if ( !isDefined(_namespace) ) {
						ready = false;
						break;
					}
				} 
				if ( ready ) { 
					callback.call(_namespace, _namespace); 
				} else {
					if ( polltotal >= timeout ) { 
						callback.call(this, false); 
						return;
					}
					polltotal += polltime;
					setTimeout(poller, polltime);
				}
			};
		script.src = path;
		head.appendChild(script);
		poller();
	},
	
	loadModules: function () {
		var args = toArray(arguments), 
			callback = args.pop(),
			module,
			loader = function (result) {
				if ( isDefined(result) ) {
					if ( module = args.shift() ) {
						J.loadModule( module[0], module[1], loader )
					} 
					else { callback(true); }
				}
				else { callback(false); }
			};
		loader( true );
	},
	printPage: function ( message, tag ) {
		tag = tag || 'p';
		document.writeln( '<'+tag+'><a class="print-link" href="javascript:print();">' + 
			( message || "Print this page &raquo;" ) + '</a></'+tag+'>' );
	}
});


})(); // End closure