﻿(function(){
	var
		global = this,
		undefined,
		$,
		sj = global.sj = $ = function(t) {
			if (!t) return t;
			if (t.sjCompatablized !== true) {
				switch (typeof t) {
					case "string":
						if (arguments.length == 2) t;
						break;
					default:
						if ($.js.isArray(t) || Object.prototype.toString.call(t) == "[object NodeList]" || Object.prototype.toString.call(t) == "[object HTMLCollection]") {
							/*var l = t.length;
							for (var i = 0; i < l; i++) {
								$(t[i]);
							}*/
						} else {
							if (t.nodeType && t.nodeName.toLowerCase() != "script") $.compat.node(t);
							if (typeof t.innerHTML !== undefined && t.nodeName.toLowerCase() != "script") $.compat.element(t);
						}
						break;
				}
				t.sjCompatablized = true;
			}
			return t;
		};
	
	$.version = 0.75;
	$.env = {
		SITE_ROOT: "/",
		JSON_URL: "/static/js/json2.js",
		PROGRAM_ROOT: "/static/apps/",
		MODULE_ROOT: "/static/modules/",
		JSON_REQUIRED: false
	};
	
	$.browser = {
		init: function() {
			this.name = this.searchString(this.dataBrowser) || "An unknown browser";
			this.version = this.searchVersion(navigator.userAgent)
				|| this.searchVersion(navigator.appVersion)
				|| "an unknown version";
			this.OS = this.searchString(this.dataOS) || "an unknown OS";
			this.engine = {
				name: this.searchString(this.dataEngine),
				version: this.searchVersion(navigator.userAgent)
			}
		},
		searchString: function(data) {
			for (var i = 0, l = data.length; i < l; i++) {
				var dataString = data[i].string;
				var dataProp = data[i].prop;
				this.versionSearchString = data[i].versionSearch || new RegExp(data[i].identity);
				if (dataString) {
					if (dataString.indexOf(data[i].subString) != -1) return data[i].identity;
				} else if (dataProp) return data[i].identity;
			}
		},
		searchVersion: function(dataString) {
			var m = dataString.match(this.versionSearchString);
			if (!m) return;
			return m[1];
		},
		dataBrowser: [
			{
				string: navigator.userAgent,
				subString: "Chrome",
				identity: "Chrome",
				versionSearch: /Chrome\/([0-9.]+)/
			},
			{
				string: navigator.userAgent,
				subString: "OmniWeb",
				versionSearch: "OmniWeb/",
				identity: /OmniWeb.([0-9.]+)/
			},
			{
				string: navigator.vendor,
				subString: "Apple",
				identity: "Safari",
				versionSearch: /Version.([0-9.]+)/
			},
			{
				string: navigator.userAgent,
				subString: "Android",
				identity: "Android",
				versionSearch: /Version.([0-9.]+)/
			},
			{
				prop: window.opera,
				identity: "Opera"
			},
			{
				string: navigator.vendor,
				subString: "iCab",
				identity: "iCab"
			},
			{
				string: navigator.vendor,
				subString: "KDE",
				identity: "Konqueror"
			},
			{
				string: navigator.userAgent,
				subString: "Firefox",
				identity: "Firefox",
				versionSearch: /Firefox\/([0-9.]+)/
			},
			{
				string: navigator.vendor,
				subString: "Camino",
				identity: "Camino"
			},
			{		// for newer Netscapes (6+)
				string: navigator.userAgent,
				subString: "Netscape",
				identity: "Netscape"
			},
			{
				string: navigator.userAgent,
				subString: "MSIE",
				identity: "Explorer",
				versionSearch: /MSIE.([0-9.]+)/
			},
			{
				string: navigator.userAgent,
				subString: "Gecko",
				identity: "Mozilla",
				versionSearch: /rv:([0-9.]+)/
			},
			{ 		// for older Netscapes (4-)
				string: navigator.userAgent,
				subString: "Mozilla",
				identity: "Netscape",
				versionSearch: /Mozilla.([0-9.]+)/
			}
		],
		dataOS: [
			{
				string: navigator.platform,
				subString: "Win",
				identity: "Windows"
			},
			{
				string: navigator.platform,
				subString: "Mac",
				identity: "Mac"
			},
			{
				string: navigator.userAgent,
				subString: "iPhone",
				identity: "iPhone/iPod"
			},
			{
				string: navigator.userAgent,
				subString: "iPad",
				identity: "iPad"
			},
			{
				string: navigator.platform,
				subString: "Linux",
				identity: "Linux"
			}
		],
		dataEngine: [
			{
				string: navigator.userAgent,
				subString: "WebKit",
				identity: "WebKit",
				versionSearch: /AppleWebKit\/([0-9.]+)/
			},
			{
				string: navigator.userAgent,
				subString: "MSIE",
				identity: "Trident",
				versionSearch: /MSIE([0-9.]+)/
			},
			{
				string: navigator.userAgent,
				subString: "Opera",
				identity: "Presto",
				versionSearch: /Presto\/([0-9.]+)/
			},
			{
				string: navigator.userAgent,
				subString: "Gecko",
				identity: "Gecko",
				versionSearch: /rv:([0-9.]+)/
			}
		]
	};
	$.browser.init();
	
	var updatePointerInfo = function(e) {
		$.env.POINTER_DATA = {
			target: e.target,
			altKey: e.altKey,
			ctrlKey: e.ctrlKey,
			metaKey: e.metaKey,
			shiftKey: e.shiftKey,
			button: e.button,
			which: e.which,
			clientX: e.clientX,
			clientY: e.clientY,
			layerX: e.layerX,
			layerY: e.layerY,
			pageX: e.pageX,
			pageY: e.pageY,
			screenX: e.screenX,
			screenY: e.screenY
		};
	};
	
	var initCallbacks = [];
	$.isReady = false;
	$.init = function() {
		if ($.isReady) return;
		if (!document.body) document.body = document.getElementsByTagName("body")[0];
		if ($.env.JSON_REQUIRED && typeof JSON === "undefined") {
			$.html.addScript($.env.JSON_URL, $.init);
			return;
		}
		$.env.startup = new Date();
		if (!$.ui) $.ui = {};
		if (!$.ui.loader) $.ui.loader = new Image();
		$.ui.loader.src = [$.env.SITE_ROOT, "Images/Common/ajax-loader.gif"].join("");
		
		var i = $.dom.create("p", {style:"width:100%;height:200px"});
		var o = $.dom.create("div", {style:"position:absolute;top:0px;left:0px;visibility:hidden;width:200px;height:150px;overflow:hidden"});
		o.appendChild(i);
		document.body.appendChild(o);
		var w1 = i.offsetWidth;
		var h1 = i.offsetHeight;
		o.style.overflow = "scroll";
		var w2 = i.offsetWidth;
		var h2 = i.offsetHeight;
		if (w1 == w2) w2 = o.clientWidth;
		if (h1 == h2) h2 = o.clientWidth;
		document.body.removeChild(o);
		
		$.env.SCROLL_BAR_WIDTH = w1 - w2;
		$.env.SCROLL_BAR_HEIGHT = h1 - h2;
		
		$.isReady = true;
		document.addEventListener("mousemove", updatePointerInfo, false);
		updaterTimer.start();

		for (var i = 0, l = initCallbacks.length; i < l; i++) {
			initCallbacks[i].call(global);
		}
	};
	$.init.addCallback = function(cb) {
		initCallbacks.push(cb);
	}
	
	$.q = {
		c: function(t, s, u) {
			if (!t) t = document;
			else if (!t.getElementsByClassName) t.getElementsByClassName = $.compat.element.getElementsByClassName;
			var r = t.getElementsByClassName(s);
			if (u) {
				if (r.length == 0) return null;
				else return $(r[0]);
			}
			return r;
		},
		i: function(s) {
			return $(document.getElementById(s));
		},
		n: function(s, u) {
			var r = document.getElementsByName(s);
			if (u) {
				if (r.length == 0) return null;
				else return $(r[0]);
			}
			return r;
		},
		t: function(t, s, u) {
			if (!t) t = document;
			if (!t.getElementsByTagName) return [];
			var r = t.getElementsByTagName(s);
			if (u) {
				if (r.length == 0) return null;
				else return $(r[0]);
			}
			return r;
		}
	};
	
	$.compat = {
		fixPrototypes: function() {
			/*if (!Function.prototype.mixin) Function.prototype.mixin = function(parent, opts, wanted) {
				if (!parent) return;
				var p = new parent(opts);
				for (var i in p) {
					if ((!wanted || (wanted.length > 0 && wanted.indexOf(i) > -1)) && !(i in this.prototype) && p.hasOwnProperty(i)) this.prototype[i] = p[i];
				}
			};*/
			if (!Array.prototype.indexOf) {
				Array.prototype.indexOf = function(elt) {
					var len = this.length >>> 0;

					var from = Number(arguments[1]) || 0;
					from = (from < 0) ? Math.ceil(from) : Math.floor(from);
					if (from < 0) from += len;
					for (; from < len; from++) {
						if (from in this && this[from] === elt) return from;
					}
					return -1;
				};
			}
			if (!Array.prototype.contains) {
				Array.prototype.contains = function(obj) {
					if (this.indexOf(obj) != -1) return true;
					return false;
				};
			}
			if (!String.prototype.trim) {
				String.prototype.trim = function(t) {
					return (this || t || "").replace(/^\s+|\s+$/g, "");
				}
			}
		},
		window: function(t) {
			if (!t.addEventListener) $.js.objectMixin(t, $.compat.event.EventTarget);
		},
		document: function(t) {
			if (!t.addEventListener) $.js.objectMixin(t, $.compat.event.EventTarget);
			if (!t.createEvent) $.js.objectMixin(t, $.compat.event.DocumentEvent);
			if (!t.setUserData) t.setUserData = $.compat.node.setUserData;
			if (!t.getUserData) t.getUserData = $.compat.node.getUserData;
			//if (!t.querySelector) t.querySelector = $.compat.node.querySelector;
			//if (!t.querySelectorAll) t.querySelectorAll = $.compat.node.querySelectorAll;
			if (!t.getElementsByClassName) t.getElementsByClassName = $.compat.element.getElementsByClassName;
		},
		node: function(t) {
			if (!t.addEventListener) $.js.objectMixin(t, $.compat.event.EventTarget);
			if (!t.setUserData) t.setUserData = $.compat.node.setUserData;
			if (!t.getUserData) t.getUserData = $.compat.node.getUserData;
			//if (!t.querySelector) t.querySelector = $.compat.node.querySelector;
			//if (!t.querySelectorAll) t.querySelectorAll = $.compat.node.querySelectorAll;
			if (!t.hasAttribute) t.hasAttribute = $.compat.node.hasAttribute;
			//if (!t.hasAttributeNS) t.hasAttributeNS = $.compat.node.hasAttributeNS;
			//if (!t.getAttributeNS) t.getAttributeNS = $.compat.node.getAttributeNS;
			//if (!t.setAttributeNS) t.setAttributeNS = $.compat.node.setAttributeNS;
		},
		element: function(t) {
			if (!t.classList) t.classList = new $.compat.element.classList(t);
			if (!t.getElementsByClassName) t.getElementsByClassName = $.compat.element.getElementsByClassName;
		}
	};
	$.compat.fixPrototypes();
	$.compat.event = {};
	$.compat.event.eventList = {
		"": ["activate", "abort", "click", "dblclick", "focusin", "focusout", "keydown", "keypress", "keyup", "mousedown", "mouseenter", "mouseover", "mouseup", "mouseout", "mousemove", "mousewheel"],
		a: ["blur", "focus"],
		body: ["load", "unload"],
		button: ["blur", "focus"],
		form: ["reset", "submit"],
		input: ["blur", "focus", "change", "select"],
		label: ["blur", "focus"],
		select: ["blur", "focus", "change"],
		textarea: ["blur", "focus", "change", "select"]
	};
	$.compat.event.Event = function() {};
	$.compat.event.Event.prototype = {
		CAPTURING_PHASE: 1,
		AT_TARGET: 2,
		BUBBLING_PHASE: 3,
		type: "",
		target: null,
		currentTarget: null,
		eventPhase: 2,
		bubbles: true,
		cancelable: true,
		timeStamp: null,
		_propagationStopped: false,
		stopPropagation: function() {
			global.event.cancelBubble = true;
			this._propagationStopped = true;
		},
		preventDefault: function() {
			if (this.cancelable) {
				global.event.returnValue = false;
				this.defaultPrevented = true;
			}
		},
		initEvent: function(type, canBubble, cancelable) {
			this.type = type;
			this.bubbles = canBubble;
			this.cancelable = cancelable;
			this.timeStamp = new Date().getTime();
		},
		namespaceURI: null,
		_immediatePropagationStopped: false,
		stopImmediatePropagation: function() {
			global.event.cancelBubble = true;
			this._propagationStopped = true;
			this._immediatePropagationStopped = true;
		},
		defaultPrevented: false,
		initEventNS: function(namespace, type, canBubble, cancelable) {
			this.namespaceURI = namespace;
			this.initEvent(type, canBubble, cancelable);
		}
	};
	$.compat.event.CustomEvent = function() {};
	$.compat.event.CustomEvent.prototype = new $.compat.event.Event();
	$.compat.event.CustomEvent.prototype.detail = null;
	$.compat.event.CustomEvent.prototype.initCustomEvent = function(type, canBubble, cancelable, detail) {
		this.initEvent(type, canBubble, cancelable);
		this.detail = detail;
	};
	$.compat.event.CustomEvent.prototype.initCustomEventNS = function(namespace, type, canBubble, cancelable, detail) {
		this.initEventNS(namespace, type, canBubble, cancelable);
		this.detail = detail;
	};
	
	$.compat.event.UIEvent = function(){};
	$.compat.event.UIEvent.prototype = new $.compat.event.Event();
	$.compat.event.UIEvent.prototype.view = window;
	$.compat.event.UIEvent.prototype.detail = 0;
	$.compat.event.UIEvent.prototype.initUIEvent = function(type, canBubble, cancelable, view, detail) {
		this.initUIEventNS(null, type, canBubble, cancelable, view, detail);
	};
	$.compat.event.UIEvent.prototype.initUIEventNS = function(namespace, type, canBubble, cancelable, view, detail) {
		this.initEventNS(namespace, type, canBubble, cancelable);
		if (view) this.view = view;
		this.detail = detail;
	};
	
	$.compat.event.MouseEvent = function(){};
	$.compat.event.MouseEvent.prototype = new $.compat.event.UIEvent();
	$.compat.event.MouseEvent.prototype.screenX = 0;
	$.compat.event.MouseEvent.prototype.screenY = 0;
	$.compat.event.MouseEvent.prototype.clientX = 0;
	$.compat.event.MouseEvent.prototype.clientY = 0;
	$.compat.event.MouseEvent.prototype.ctrlKey = false;
	$.compat.event.MouseEvent.prototype.shiftKey = false;
	$.compat.event.MouseEvent.prototype.altKey = false;
	$.compat.event.MouseEvent.prototype.metaKey = false;
	$.compat.event.MouseEvent.prototype.button = 0;
	$.compat.event.MouseEvent.prototype.relatedTarget = null;
	$.compat.event.MouseEvent.prototype._modifiersList = null;
	$.compat.event.MouseEvent.prototype.initMouseEvent = function(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget) {
		this.initMouseEventNS(null, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
	};
	$.compat.event.MouseEvent.prototype.getModifierState = function(keyIdentifier) {
		if (this._modifiersList.split(/\s+/).indexOf(keyIdentifier) > -1) return true;
		return false;
	};
	$.compat.event.MouseEvent.prototype.initMouseEventNS = function(namespace, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList) {
		this.initUIEventNS(namespace, type, canBubble, cancelable, view, detail);
		this.screenX = screenX;
		this.screenY = screenY;
		this.clientX = clientX;
		this.clientY = clientY;
		this._modifiersList = modifiersList;
		var mods = modifiersList.split(/\s+/);
		if (mods.indexOf("Control") > -1) this.ctrlKey = true;
		if (mods.indexOf("Shift") > -1) this.shiftKey = true;
		if (mods.indexOf("Alt") > -1) this.altKey = true;
		if (mods.indexOf("Meta") > -1) this.metaKey = true;
		this.button = button;
		this.relatedTarget = relatedTarget;
	};
	
	$.compat.event.MouseWheelEvent = function(){};
	$.compat.event.MouseWheelEvent.prototype = new $.compat.event.MouseEvent();
	$.compat.event.MouseWheelEvent.prototype.wheelDelta = 0;
	$.compat.event.MouseWheelEvent.prototype.initMouseWheelEvent = function(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList, wheelDelta) {
		this.initMouseWheelEventNS(null, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList, wheelDelta);
	};
	$.compat.event.MouseWheelEvent.prototype.initMouseWheelEventNS = function(namespace, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList, wheelDelta) {
		this.initMouseEventNS(namespace, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList);
		this.wheelDelta = wheelDelta;
	};
	
	$.compat.event.WheelEvent = function(){};
	$.compat.event.WheelEvent.prototype = new $.compat.event.MouseEvent();
	$.compat.event.WheelEvent.prototype.DOM_DELTA_PIXEL = 0x00;
	$.compat.event.WheelEvent.prototype.DOM_DELTA_LINE = 0x01;
	$.compat.event.WheelEvent.prototype.DOM_DELTA_PAGE = 0x02;
	$.compat.event.WheelEvent.prototype.deltaX = 0;
	$.compat.event.WheelEvent.prototype.deltaY = 0;
	$.compat.event.WheelEvent.prototype.deltaZ = 0;
	$.compat.event.WheelEvent.prototype.deltaMode = 0x00;
	$.compat.event.WheelEvent.prototype.initWheelEvent = function(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList, deltaX, deltaY, deltaZ, deltaMode) {
		this.initWheelEventNS(null, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList, deltaX, deltaY, deltaZ, deltaMode);
	};
	$.compat.event.WheelEvent.prototype.initWheelEventNS = function(namespace, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList, deltaX, deltaY, deltaZ, deltaMode) {
		this.initMouseEventNS(namespace, type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, button, relatedTarget, modifiersList);
		if (typeof deltaX === "number") this.deltaX = deltaX;
		if (typeof deltaY === "number") this.deltaY = deltaY;
		if (typeof deltaZ === "number") this.deltaZ = deltaZ;
		if (typeof deltaMode === "number") this.deltaMode = deltaMode;
	};
	
	$.compat.event.TextEvent = function(){};
	$.compat.event.TextEvent.prototype = new $.compat.event.UIEvent();
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_UNKNOWN = 0x00;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_KEYBOARD = 0x01;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_PASTE = 0x02;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_DROP = 0x03;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_IME = 0x04;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_OPTION = 0x05;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_HANDWRITING = 0x06;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_VOICE = 0x07;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_MULTIMODAL = 0x08;
	$.compat.event.TextEvent.prototype.DOM_INPUT_METHOD_SCRIPT = 0x09;
	$.compat.event.TextEvent.prototype.data = null;
	$.compat.event.TextEvent.prototype.inputMode = 0x00;
	$.compat.event.TextEvent.prototype.initTextEvent = function(type, canBubble, cancelable, view, data, inputMode) {
		this.initTextEventNS(null, type, canBubble, cancelable, view, data, inputMode);
	};
	$.compat.event.TextEvent.prototype.initTextEventNS = function(namespace, type, canBubble, cancelable, view, data, inputMode) {
		this.initUIEventNS(namespace, type, canBubble, cancelable, view);
		this.detail = undefined;
		this.data = data;
		this.inputMode = inputMode;
	};
	
	$.compat.event.KeyboardEvent = function(){};
	$.compat.event.KeyboardEvent.prototype = new $.compat.event.UIEvent();
	$.compat.event.KeyboardEvent.prototype.DOM_KEY_LOCATION_STANDARD = 0x00;
	$.compat.event.KeyboardEvent.prototype.DOM_KEY_LOCATION_LEFT = 0x01;
	$.compat.event.KeyboardEvent.prototype.DOM_KEY_LOCATION_RIGHT = 0x02;
	$.compat.event.KeyboardEvent.prototype.DOM_KEY_LOCATION_NUMPAD = 0x03;
	$.compat.event.KeyboardEvent.prototype.DOM_KEY_LOCATION_MOBILE = 0x04;
	$.compat.event.KeyboardEvent.prototype.DOM_KEY_LOCATION_JOYSTICK = 0x05;
	$.compat.event.KeyboardEvent.prototype.keyIdentifier = null;
	$.compat.event.KeyboardEvent.prototype.keyLocation = 0x00;
	$.compat.event.KeyboardEvent.prototype.ctrlKey = false;
	$.compat.event.KeyboardEvent.prototype.shiftKey = false;
	$.compat.event.KeyboardEvent.prototype.altKey = false;
	$.compat.event.KeyboardEvent.prototype.metaKey = false;
	$.compat.event.KeyboardEvent.prototype.repeat = false;
	$.compat.event.KeyboardEvent.prototype.getModifierState = function(keyIdentifier) {
		if (this._modifiersList.split(/\s+/).indexOf(keyIdentifier) > -1) return true;
		return false;
	};
	$.compat.event.KeyboardEvent.prototype.initKeyboardEvent = function(type, canBubble, cancelable, view, keyIdentifier, keyLocation, modifiersList, repeat) {
		this.initKeyboardEventNS(null, type, canBubble, cancelable, view, keyIdentifier, keyLocation, modifiersList, repeat);
	};
	$.compat.event.KeyboardEvent.prototype.initKeyboardEventNS = function(namespace, type, canBubble, cancelable, view, keyIdentifier, keyLocation, modifiersList, repeat) {
		this.initUIEventNS(namespace, type, canBubble, cancelable, view);
		this.keyIdentifier = keyIdentifier;
		this.keyLocation = keyLocation;
		this.repeat = repeat;
		this._modifiersList = modifiersList;
		var mods = modifiersList.split(/\s+/);
		if (mods.indexOf("Control") > -1) this.ctrlKey = true;
		if (mods.indexOf("Shift") > -1) this.shiftKey = true;
		if (mods.indexOf("Alt") > -1) this.altKey = true;
		if (mods.indexOf("Meta") > -1) this.metaKey = true;
	};
	
	$.compat.event.CompositionEvent = function(){};
	$.compat.event.CompositionEvent.prototype = new $.compat.event.UIEvent();
	$.compat.event.CompositionEvent.prototype.data = null;
	$.compat.event.CompositionEvent.prototype.initCompositionEvent = function(type, canBubble, cancelable, view, data) {
		this.initCompositionEventNS(null, type, canBubble, cancelable, view, data);
	};
	$.compat.event.CompositionEvent.prototype.initCompositionEventNS = function(namespace, type, canBubble, cancelable, view, data) {
		this.initUIEventNS(namespace, type, canBubble, cancelable, view);
		this.data = data;
	};
	
	$.compat.event.MutationEvent = function(){};
	$.compat.event.MutationEvent.prototype = new $.compat.event.Event();
	$.compat.event.MutationEvent.prototype.MODIFICATION = 1;
	$.compat.event.MutationEvent.prototype.ADDITION = 2;
	$.compat.event.MutationEvent.prototype.REMOVAL = 3;
	$.compat.event.MutationEvent.prototype.relatedNode = null;
	$.compat.event.MutationEvent.prototype.prevValue = null;
	$.compat.event.MutationEvent.prototype.newValue = null;
	$.compat.event.MutationEvent.prototype.attrName = null;
	$.compat.event.MutationEvent.prototype.attrChange = 1;
	$.compat.event.MutationEvent.prototype.initMutationEvent = function(type, canBubble, cancelable, relatedNode, prevValue, newValue, attrName, attrChange) {
		this.initMutationEventNS(null, type, canBubble, cancelable, relatedNode, prevValue, newValue, attrName, attrChange);
	};
	$.compat.event.MutationEvent.prototype.initMutationEventNS = function(namespace, type, canBubble, cancelable, relatedNode, prevValue, newValue, attrName, attrChange) {
		this.initEventNS(namespace, type, canBubble, cancelable);
		this.relatedNode = relatedNode;
		this.prevValue = prevValue;
		this.newValue = newValue;
		this.attrName = attrName;
		this.attrChange = attrChange;
	};
	
	$.compat.event.MutationNameEvent = function(){};
	$.compat.event.MutationNameEvent.prototype = new $.compat.event.MutationEvent();
	$.compat.event.MutationNameEvent.prototype.prevNamespaceURI = null;
	$.compat.event.MutationNameEvent.prototype.prevNodeName = null;
	$.compat.event.MutationNameEvent.prototype.initMutationNameEvent = function(type, canBubble, cancelable, relatedNode, prevNamespaceURI, prevNodeName) {
		this.initMutationNameEventNS(null, type, canBubble, cancelable, relatedNode, prevNamespaceURI, prevNodeName);
	};
	$.compat.event.MutationNameEvent.prototype.initMutationNameEventNS = function(namespace, type, canBubble, cancelable, relatedNode, prevNamespaceURI, prevNodeName) {
		this.initMutationEventNS(namespace, type, canBubble, cancelable, relatedNode, null, null, null, null);
		this.prevNamespaceURI = prevNamespaceURI;
		this.prevNodeName = prevNodeName;
	};
	
	$.compat.event.EventException = function(code) {
		this.code = code;
	};
	$.compat.event.EventException.prototype = {
		UNSPECIFIED_EVENT_TYPE_ERR: 0,
		DISPATCH_REQUEST_ERR: 1,
		code: null
	};
	
	$.compat.event.EventTarget = function() {};
	$.compat.event.EventTarget.prototype = {
		addEventListener: function(type, listener, useCapture) {
			this.addEventListenerNS(null, type, listener, useCapture);
		},
		removeEventListener: function(type, listener, useCapture) {
			this.removeEventListenerNS(null, type, listener, useCapture);
		},
		dispatchEvent: function(evt) {
			if (!evt.type) throw new $.compat.event.EventException(0);
			if (evt._beingDispatched) throw new $.compat.event.EventException(1);
			evt._beingDispatched = true;
			var t = this;
			var isNatural = true;
			if (evt.namespace != null || !$.compat.event.isEventNatural(t.nodeName.toLowerCase(), evt.type)) isNatural = false;
			
			if (isNatural) {
				evt = sj.js.extend(document.createEventObject(), evt);
				this.fireEvent(['on', evt.type].join(""), evt);
			} else $.compat.event.handleEvent.call(t, evt);
			
			evt._beingDispatched = false;
		},
		addEventListenerNS: function(namespace, type, listener, useCapture) {
			if (useCapture === undefined) throw "Not Enough Arguments";
			var t = this;
			var isNatural = true;
			if (namespace != null || (typeof t.nodeName !== "undefined" && !$.compat.event.isEventNatural(t.nodeName.toLowerCase(), type))) isNatural = false;
			var re = $.compat.event.registeredEvents;
			if (!(type in re)) re[type] = [[], []];//first is captures, second is bubbles.
			var ret = re[type][useCapture ? 0 : 1];
			var l = ret.length;
			for (var i = 0; i < l; i++) {
				if (ret[i].namespace == namespace && ret[i].type == type && ret[i].target == t && ret[i].listener == listener) return;
			}
			ret.push({
				namespace: namespace,
				target: t,
				type: type,
				listener: listener
			});
			if (isNatural) t.attachEvent(["on", type].join(""), $.compat.event.handleEvent);
		},
		removeEventListenerNS: function(namespace, type, listener, useCapture) {
			if (useCapture === undefined) throw "Not Enough Arguments";
			var t = this;
			var isNatural = true;
			if (namespace != null || !$.compat.event.isEventNatural(t.nodeName.toLowerCase(), type)) isNatural = false;
			var re = $.compat.event.registeredEvents;
			if (!(type in re)) return;
			var ret = re[type][useCapture ? 0 : 1];
			var l = ret.length;
			var toRemove = -1;
			var numOfType = 0;
			for (var i = 0; i < l; i++) {
				if (ret[i].namespace == namespace && ret[i].type == type && ret[i].target == t && ret[i].listener == listener) toRemove = i;
				else if (ret[i].namespace == namespace && ret[i].type == type && ret[i].target == t) numOfType++;
			}
			if (toRemove > -1) ret.splice(toRemove, 1);
			if (numOfType == 0 && isNatural) t.detachEvent(["on", type].join(""), $.compat.event.handleEvent);
		}
	};
	
	$.compat.event.DocumentEvent = function() {};
	$.compat.event.DocumentEventMap = {
		Event: "Event",
		HTMLEvents: "Event",
		UIEvent: "UIEvent",
		UIEvents: "UIEvent",
		MouseEvent: "MouseEvent",
		MouseEvents: "MouseEvent",
		MutationEvent: "MutationEvent",
		MutationEvents: "MutationEvent",
		CompositionEvent: "CompositionEvent",
		MutationNameEvent: "MutationNameEvent",
		KeyboardEvent: "KeyboardEvent",
		MouseWheelEvent: "MouseWheelEvent",
		TextEvent: "TextEvent",
		WheelEvent: "WheelEvent",
		CustomEvent: "CustomEvent"
	};
	$.compat.event.DocumentEvent.prototype = {
		createEvent: function(type) {
			if (!(type in $.compat.event.DocumentEventMap)) throw new DOMException();
			return new $.compat.event[$.compat.event.DocumentEventMap[type]]();
		},
		canDispatch: function(namespace, type) {
			return true;
		}
	};
	
	$.compat.event.registeredEvents = {};
	$.compat.event.handleEvent = function(e) {
		if (global.event) {
			global.event.cancelBubble = true;
		}
		if (!e) e = global.event;
		var type = e.type;
		var target = e.srcElement || this;
		
		var ret = $.compat.event.registeredEvents;
		
		if (!("preventDefault" in e)) {
			var oe = e;
			if (type in $.compat.event.eventMap) type = $.compat.event.eventMap[type];
			var et = $.compat.event.eventTypes[type];
			var et3 = et[3];
			e = new et3();
			var ml = [];
			var to = target.ownerDocument;
			if (oe.ctrlKey) ml.push("Control");
			if (oe.altKey) ml.push("Alt");
			if (oe.shiftKey) ml.push("Shift");
			if (oe.metaKey) ml.push("Meta");
			if (et3 == $.compat.event.Event) {
				e.initEventNS(null, type, et[0], et[1]);
			} else if (et3 == $.compat.event.UIEvent) {
				e.initUIEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.data);
			} else if (et3 == $.compat.event.MouseEvent) {
				e.initMouseEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.data, oe.screenX, oe.screenY, oe.clientX, oe.clientY, oe.button, oe.fromElement, ml.join(" "));
			} else if (et3 == $.compat.event.CompositionEvent) {
				e.initCompositionEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.data);
			} else if (et3 == $.compat.event.MutationNameEvent) {
				e.initMutationNameEventNS(null, type, et[0], et[1]);
			} else if (et3 == $.compat.event.MutationEvent) {
				e.initMutationEventNS(null, type, et[0], et[1], target.getAttributeNode(oe.propertyName), null, target[oe.propertyName], oe.propertyName, 1);
			} else if (et3 == $.compat.event.KeyboardEvent) {
				e.initKeyboardEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.keyCode, 0x00, ml.join(" "), oe.repeat);
			} else if (et3 == $.compat.event.MouseWheelEvent) {
				e.initMouseWheelEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.data, oe.screenX, oe.screenY, oe.clientX, oe.clientY, oe.button, oe.fromElement, ml.join(" "), oe.wheelDelta);
			} else if (et3 == $.compat.event.TextEvent) {
				e.initTextEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.data, 0x00);
			} else if (et3 == $.compat.event.WheelEvent) {
				e.initWheelEventNS(null, type, et[0], et[1], (to ? to.parentWindow : null), oe.data, oe.screenX, oe.screenY, oe.clientX, oe.clientY, oe.button, oe.fromElement, ml.join(" "), 0, oe.wheelDelta, 0, 0);
			}
		}
		
		if (!(type in ret)) return true;
		
		e.target = target;
		var propagationPath = [];
		var p = target;
		while (p.parentNode && p.parentNode != p) {
			propagationPath.push(p.parentNode);
			p = p.parentNode;
		}
		var l = propagationPath.length;
		
		if (e._propagationStopped == false) {
			e.eventPhase = 1;
			for (var i = l - 1; i >= 0; i--) {
				var rett = ret[type][0];
				e.currentTarget = propagationPath[i];
				var listeners = [];
				var ll = rett.length;
				for (var j = 0; j < ll; j++) {
					if (rett[j].namespace == e.namespaceURI && rett[j].target == propagationPath[i]) {
						listeners.push(rett[j].listener);
					}
				}
				ll = listeners.length;
				for (var j = 0; j < ll; j++) {
					listeners[j].call(propagationPath[i], e);
					if (e._immediatePropagationStopped == true) break;
				}
				if (e._propagationStopped == true) break;
			}
			
			if (e._propagationStopped == false) {
				e.eventPhase = 2;
				e._immediatePropagationStopped = false;
				var rett = ret[type][0];
				e.currentTarget = target;
				var listeners = [];
				var ll = rett.length;
				for (var j = 0; j < ll; j++) {
					if (rett[j].namespace == e.namespaceURI && rett[j].target == target) {
						listeners.push(rett[j].listener);
					}
				}
				rett = ret[type][1];
				ll = rett.length;
				for (var j = 0; j < ll; j++) {
					if (rett[j].namespace == e.namespaceURI && rett[j].target == target) {
						listeners.push(rett[j].listener);
					}
				}
				ll = listeners.length;
				for (var j = 0; j < ll; j++) {
					listeners[j].call(target, e);
					if (e._immediatePropagationStopped == true) break;
				}
				
				if (e.bubbles == true && e._propagationStopped == false) {
					e.eventPhase = 3;
					e._immediatePropagationStopped = false;
					for (var i = 0; i < l; i++) {
						var rett = ret[type][1];
						e.currentTarget = propagationPath[i];
						var listeners = [];
						var ll = rett.length;
						for (var j = 0; j < ll; j++) {
							if (rett[j].namespace == e.namespaceURI && rett[j].target == propagationPath[i]) {
								listeners.push(rett[j].listener);
							}
						}
						ll = listeners.length;
						for (var j = 0; j < ll; j++) {
							listeners[j].call(propagationPath[i], e);
							if (e._immediatePropagationStopped == true) break;
						}
						if (e._propagationStopped == true) break;
					}
				}
			}
		}
		
		e._immediatePropagationStopped = false;
		e._propagationStopped = false;
		
		if (e.cancelable && e.defaultPrevented) {
			global.event.returnValue = false;
			e.defaultPrevented = false;
			return false;
		}
		
		e.defaultPrevented = false;
		
		return true;
	};
	
	$.compat.event.eventTypes = {
		abort: [true, false, [], $.compat.event.Event],
		blur: [false, false, [], $.compat.event.UIEvent],
		change: [true, false, [], $.compat.event.Event],
		click: [true, true, [], $.compat.event.MouseEvent],
		compositionstart: [true, true, [], $.compat.event.CompositionEvent],
		compositionupdate: [true, true, [], $.compat.event.CompositionEvent],
		compositionend: [true, true, [], $.compat.event.CompositionEvent],
		dblclick: [true, true, [], $.compat.event.MouseEvent],
		DOMActivate: [true, true, [], $.compat.event.UIEvent],
		DOMAttributeNameChanged: [true, false, [], $.compat.event.MutationNameEvent],
		DOMAttrModified: [true, false, [], $.compat.event.MutationEvent],
		DOMCharacterDataModified: [true, false, [], $.compat.event.MutationEvent],
		DOMElementNameChanged: [true, false, [], $.compat.event.MutationNameEvent],
		DOMFocusIn: [true, false, [], $.compat.event.UIEvent],
		DOMFocusOut: [true, false, [], $.compat.event.UIEvent],
		DOMNodeInserted: [true, false, [], $.compat.event.MutationEvent],
		DOMNodeInsertedIntoDocument: [false, false, [], $.compat.event.MutationEvent],
		DOMNodeRemoved: [true, false, [], $.compat.event.MutationEvent],
		DOMNodeRemovedFromDocument: [false, false, [], $.compat.event.MutationEvent],
		DOMSubtreeModified: [true, false, [], $.compat.event.MutationEvent],
		error: [true, false, [], $.compat.event.Event],
		focus: [false, false, [], $.compat.event.UIEvent],
		focusin: [true, false, [], $.compat.event.UIEvent],
		focusout: [true, false, [], $.compat.event.UIEvent],
		keydown: [true, true, [], $.compat.event.KeyboardEvent],
		keypress: [true, true, [], $.compat.event.KeyboardEvent],
		keyup: [true, true, [], $.compat.event.KeyboardEvent],
		load: [false, false, [], $.compat.event.Event],
		mousedown: [true, true, [], $.compat.event.MouseEvent],
		mouseenter: [false, true, [], $.compat.event.MouseEvent],
		mouseleave: [false, true, [], $.compat.event.MouseEvent],
		mousemove: [true, true, [], $.compat.event.MouseEvent],
		mouseout: [true, true, [], $.compat.event.MouseEvent],
		mouseover: [true, true, [], $.compat.event.MouseEvent],
		mouseup: [true, true, [], $.compat.event.MouseEvent],
		mousewheel: [true, true, [], $.compat.event.MouseWheelEvent],
		reset: [true, true, [], $.compat.event.Event],
		resize: [true, false, [], $.compat.event.UIEvent],
		scroll: [false, false, [], $.compat.event.UIEvent],
		select: [true, false, [], $.compat.event.Event],
		submit: [true, true, [], $.compat.event.Event],
		textInput: [true, true, [], $.compat.event.TextEvent],
		unload: [false, false, [], $.compat.event.Event],
		wheel: [true, true, [], $.compat.event.WheelEvent]
	};
	$.compat.event.eventMap = {
		activate: "DOMActivate",
		propertychange: "DOMAttrModified"
	};
	
	$.compat.event.isEventNatural = function(nodeName, type) {
		if (!nodeName) nodeName = "";
		nodeName = nodeName.toLowerCase();
		type = type.toLowerCase();
		if (nodeName in $.compat.event.eventList && $.compat.event.eventList[nodeName].indexOf(type) > -1) return true;
		if ($.compat.event.eventList[""].indexOf(type) > -1) return true;
		return false;
	};
	
	var nodeUserData = [];
	$.compat.node.setUserData = function(k, v) {
		var data = this.__userdata__;
		if (data === undefined) {
			var obj = {};
			obj[k] = v;
			this.__userdata__ = nodeUserData.push(obj) - 1;
			return null;
		} else {
			var datad = nodeUserData[data];
			var r = datad[k] || null;
			datad[k] = v;
			return r;
		}
	};
	$.compat.node.getUserData = function(k) {
		var data = this.__userdata__;
		if (data === undefined) return null;
		var nudd = nodeUserData[data];
		return (k in nudd ? nudd[k] : null);
	};
	$.compat.node.hasAttribute = function(attr) {
		//attribute = Element._attributeTranslations.has[attribute] || attribute;
		var node = this.getAttributeNode(attr);
		return !!(node && node.specified);
	};
	$.compat.node.hasAttributeNS = function(ns, attr) {
		return this.hasAttribute(attr);
	};
	$.compat.node.setAttributeNS = function(ns, attr, value) {
		return this.setAttribute(attr, value);
	};
	$.compat.node.getAttributeNS = function(ns, attr) {
		return this.getAttribute(attr);
	};
	// For IE and its silly memory leaks. We're saving a recursive leak.
	var classListElements = [];
	$.compat.element.classList = function(e) {
		this._element = classListElements.push(e) - 1;
		this._arr = [];
	};
	$.compat.element.classListPrototype = function() {
		this._fake = true;
		this._dirty = true;
		this._refresh = function() {
			this._dirty = false;
			var clss = classListElements[this._element].className;
			if (!clss) return this;
			var classes = clss.split(/\s+/);
			var cl = classes.length;
			if (cl && classes[0] == "") classes.shift();
			if (cl && classes[cl - 1] == "") classes.pop();
			var arr = this._arr;
			arr.length = cl;
			this.length = cl;
			if (cl == 0) return this;
			for (var i = 0; i < cl; ++i) {
				arr[i] = classes[i];
			}
			return this;
		};
		this.item = function(i) {
			return this._arr[i] || null;
		};
		this.contains = function(token) {
			check(token);
			if (this._dirty) this._refresh();
			var arr = this._arr;
			for (var i = 0, l = this.length; i < l; ++i) {
				if (arr[i] == token) return true;
			}
			return false;
		};
		this.add = function(token) {
			check(token);
			if (this._dirty) this._refresh();
			var arr = this._arr;
			for (var i = 0, l = this.length; i < l; ++i) {
				if (arr[i] == token) return;
			}
			arr.push(token);
			this.length = arr.length;
			classListElements[this._element].className = arr.join(" ");
		};
		this.remove = function(token) {
			check(token);
			if (this._dirty) this._refresh();
			var arr = this._arr;
			for (var i = 0, l = this.length; i < l; ++i) {
				if (arr[i] == token) {
					arr.splice(i, 1);
					this.length = arr.length;
					classListElements[this._element].className = arr.join(" ");
				}
			}
		};
		this.toggle = function(token) {
			check(token);
			if (this._dirty) this._refresh();
			var arr = this._arr;
			for (var i = 0, l = this.length; i < l; ++i) {
				if (arr[i] == token) {
					this.remove(token);
					return;
				}
			}
			this.add(token);
		};
		function check(token) {
			if (token == "") {
				throw "SYNTAX_ERR";
			}
			if (token.indexOf(/\s/) != -1) {
				throw "INVALID_CHARACTER_ERR";
			}
		}
	};
	$.compat.element.classList.prototype = new $.compat.element.classListPrototype();
	$.compat.element.getElementsByClassName = function(s) {
		var sp = $.compat.element.getElementsByClassName.space;
		var r = [];
		var ci = this.childNodes.length > 0 ? this.childNodes[0] : null;
		while (ci != null) {
			if (ci.nodeType == 1) {
				if (ci.scopeName && ci.scopeName == "g_vml_") continue;// Stop from searching excanvas elements
				if (ci.className.split(sp).indexOf(s) > -1) r.push(ci);
				if (ci.childNodes.length > 0) ci = ci.childNodes[0];
				else if (ci.nextSibling) ci = ci.nextSibling;
				else {
					while (ci.parentNode != this) {
						if (ci.parentNode.nextSibling) {
							ci = ci.parentNode.nextSibling;
							break;
						} else ci = ci.parentNode;
					}
					if (ci.parentNode == this) break;
				}
			} else {
				if (ci.nextSibling) ci = ci.nextSibling;
				else {
					while (ci.parentNode != this) {
						if (ci.parentNode.nextSibling) {
							ci = ci.parentNode.nextSibling;
							break;
						} else ci = ci.parentNode;
					}
					if (ci.parentNode == this) break;
				}
			}
		}
		return r;
	};
	$.compat.element.getElementsByClassName.space = /\s+/;
	$.compat.element.canvas = function(t) {
		if (typeof global.G_vmlCanvasManager !== "undefined") G_vmlCanvasManager.initElement(t);
	};
	
	$.js = {
		objectMixin: function(t, parent, opts) {
			if (!t || !parent) return;
			var p = new parent(opts);
			if (arguments.length <= 3) {
				for (var i in p) {
					t[i] = p[i];
				}
			} else {
				for (var i = 3, l = arguments.length; i < l; i++) {
					var ai = arguments[i];
					if (ai in p) t[ai] = p[ai];
				}
			}
		},
		each: function(obj, func) {
			var r = [];
			for (var i = 0, l = obj.length; i < l; i++) {
				var a = func.call(obj[i], i);
				if (a === false) break;
				var nl = obj.length;
				if (nl < l) {
					i -= l - nl;
					l = nl;
				}
				if (a) r.push(a);
			}
			return r;
		},
		roughlyEquals: function(a, b) {
			if (typeof a === "object" && typeof b === "object") {
				for (var i in a) {
					if (a.hasOwnProperty(i) && i in b && b.hasOwnProperty(i)) {
						var ta = typeof a[i];
						if (ta === typeof b[i]) {
							if (ta !== "object" && a[i] != b[i]) return false; 
						} else return false;
					} else if (a.hasOwnProperty(i) && !(i in b)) {
						return false;
					}
				}
				for (var i in a) {
					if (b.hasOwnProperty(i) && i in a && a.hasOwnProperty(i)) {
						var tb = typeof b[i];
						if (tb === typeof a[i]) {
							if (tb !== "object" && b[i] != a[i]) return false; 
						} else return false;
					} else if (b.hasOwnProperty(i) && !(i in a)) {
						return false;
					}
				}
				return true;
			} else return a == b;
		},
		globalEval: function(s) {
			if (global.execScript) global.execScript(s);
			else global.eval ? global.eval.call(global, s) : eval.call(global, s);
		},
		getObjectPropertyCount: function(obj) {
			var count = 0;
			for (k in obj) if (obj.hasOwnProperty(k)) count++;
			return count;
		},
		extend: function() {
			var target = arguments[0] || {},
				i = 1,
				length = arguments.length,
				deep = false,
				options;
			if (typeof target === "boolean") {
				deep = target;
				target = arguments[1] || {};
				i = 2;
			}
			if (typeof target !== "object" && !$.js.isFunction(target)) target = {};

			for (; i < length; i++)
				if ((options = arguments[i]) != null)
					for (var name in options) {
						var src = target[name], copy = options[name];
						if (target === copy) continue;
						if (deep && copy && typeof copy === "object" && !copy.nodeType)
							target[name] = $.js.extend(
								deep, 
								src || {},
								copy
							);
						else if (copy !== undefined) target[name] = copy;
					}
			return target;
		},
		isFunction: function(obj) {
			return typeof obj === "function";
		},
		isArray: function(obj) {
			return (Object.prototype.toString.call(obj) === "[object Array]") || (obj && (obj.push && obj.splice && obj.length !== undefined) || ($.browser.engine.name == "Trident" && "item" in obj));
		},
		iso8601DateFromDate: function(date) {
			function f(n) {
				if (n < 10) return ["0", n].join("");
				return n;
			}
			return [
				f(date.getUTCFullYear()),
				"-",
				f(date.getUTCMonth() + 1),
				"-",
				f(date.getUTCDate()),
				"T",
				f(date.getUTCHours()),
				":",
				f(date.getUTCMinutes()),
				":",
				f(date.getUTCSeconds()),
				".",
				f(date.getUTCMilliseconds()),
				"Z"
			].join("");
		},
		iso8601DateFromString: function(dateString) {
			var m = iso8601DateRegEx.exec(dateString);
			if (m) {
				var year = parseInt(m[1], 10);
				var month = (m[2] ? parseInt(m[2], 10) : 1);
				var day = (m[3] ? parseInt(m[3], 10) : 1);
				var hour = (m[4] ? parseInt(m[4], 10) : 0);
				var minute = (m[5] ? parseInt(m[5], 10) : 0);
				var second = (m[6] ? parseInt(m[6], 10) : 0);
				var millisecond = (m[7] ? parseInt(m[7], 10) : 0);
				var TDZ = m[8];
				var date = new Date();
				
				if (TDZ) {
					date.setUTCFullYear(year);
					date.setUTCMonth(month - 1);
					date.setUTCDate(day);
					date.setUTCHours(hour);
					date.setUTCMinutes(minute);
					date.setUTCSeconds(second);
					date.setUTCMilliseconds(millisecond);
					if (TDZ != "Z") {
						m = iso8601TDZRegEx.exec(TDZ);
						var mod = (m[1] == "+" ? -1 : 1);
						date.setUTCMinutes(date.getUTCMinutes() + (parseInt(m[3], 10) * mod));
						date.setUTCHours(date.getUTCHours() + (parseInt(m[2], 10) * mod));
					}
				} else {
					date.setFullYear(year);
					date.setMonth(month - 1);
					date.setDate(day);
					date.setHours(hour);
					date.setMinutes(minute);
					date.setSeconds(second);
					date.setMilliseconds(millisecond);
				}
				
				return date;
			}
			return null;
		}
	};
	
	var iso8601DateRegEx = /^([0-9]{4})(?:-([01][0-9])(?:-([0-3][0-9])(?:T([0-2][0-9]):([0-6][0-9])(?::([0-6][0-9])(?:\.([0-9]+))?)?(Z|[-+][0-2][0-9]:[0-6][0-9]))?)?)?$/;
	var iso8601TDZRegEx = /^([-+])([0-2][0-9]):([0-6][0-9])$/;
	
	$.compat.window(global);
	$.compat.document(document);
	
	$.events = {
		signal: function(name, data) {
			var e = document.createEvent("Event");
			e.initEvent(name, true, false);
			e.signalData = data;
			document.dispatchEvent(e);
		},
		addSignalListener: function(n, f) {
			document.addEventListener(n, f, false);
		},
		removeSignalListener: function(n, f) {
			document.removeEventListener(n, f, false);
		},
		EventTarget: function() {
			var t = this;
			t.__sjEvents__ = {};
			var te = t.__sjEvents__;

			t.addEventListener = function(type, callback, pass) {
				var tte = te;
				if (!(type in tte)) tte[type] = [];
				var tet = tte[type];
				var i = tet.length;
				while (i--) {
					if (callback == tet[i].callback) return this;
				}
				tet.push({callback: callback, pass: pass});
				return this;
			};
			t.removeEventListener = function(type, callback) {
				var tte = te;
				if (!(type in tte)) return this;
				var tet = tte[type];
				var i = tet.length;
				while (i--) {
					if (callback == tet[i].callback) {
						tet.splice(i, 1);
						if (tet.length == 0) delete tte[type];
						return this;
					}
				}
				return this;
			};
			t.dispatchEvent = function(event) {
				if (typeof event !== "object") return this;
				var tte = te;
				var type = event.type;
				if (!type || !(type in tte)) return this;
				var tet = tte[type];
				for (var i = 0, l = tet.length; i < l; i++) {
					var teti = tet[i];
					teti.callback.call(t, event, teti.pass);
				}
				return this;
			};
		}
	};
	
	var boxSizeVars = {
		"height": [
			"paddingTop",
			"paddingBottom",
			"borderTop",
			"borderBottom",
			"marginTop",
			"marginBottom"
		],
		"width": [
			"paddingLeft",
			"paddingRight",
			"borderLeft",
			"borderRight",
			"marginLeft",
			"marginRight"
		]
	};
	$.dom = {
		children: function(t) {
			if (!t) return null;
			if (t.children) return t.children;
			var c = [];
			var tc = t.childNodes;
			for (var i = 0, l = tc.length; i < l; i++) {
				var tci = tc[i];
				if (tci.nodeType != 1) {
					continue;
				}
				c.push(tci);
			}
			return c;
		},
		next: function(t) {
			if (!t) return null;
			if (t && t.nextElementSibling !== undefined) return t.nextElementSibling;
			if (t.nextSibling) {
				if (t.nextSibling.nodeType != 1) {
					return $.dom.next(t.nextSibling);
				} else {
					return t.nextSibling;
				}
			}
			return null;
		},
		previous: function(t) {
			if (!t) return null;
			if (t && t.previousElementSibling !== undefined) return t.previousElementSibling;
			if (t.previousSibling) {
				if (t.previousSibling.nodeType != 1) {
					return $.dom.previous(t.previousSibling);
				} else {
					return t.previousSibling;
				}
			}
			return null;
		},
		prependChild: (function(){
			if ($.browser.engine.name == "Trident") return (function(p, t){p.insertBefore(t)});
			else return (function(p, t){p.insertBefore(t, null)});
		})(),
		emptyNode: function(n) {
			if (!n) return null;
			while (n.childNodes[0]) {
				n.removeChild(n.childNodes[0]);
			}
		},
		isAncestor: function(p, c) {
			var pp = c.parentNode;
			while (pp && pp != p) {
				pp = pp.parentNode;
			}
			if (pp == p) return true;
			return false;
		},
		isDecendent: function(c, p) {
			var cl = $.dom.children(p);
			for (var i = 0, l = cl.length; i < l; i++) {
				var cli = cl[i];
				if (cli == c) return true;
				if ($.dom.isDecendent(c, cli)) return true;
			}
			return false;
		},
		text: function(t, v) {
			if (t.textContent !== undefined) {
				if (v !== undefined) return t.textContent = v;
				return t.textContent;
			}
			if (t.text !== undefined) {
				if (v !== undefined) return t.text = v;
				return t.text;
			}
			if (t.innerText !== undefined) {
				if (v !== undefined) return t.innerText = v;
				return t.innerText;
			}
		},
		dataset: {
			set: function(t, k, v) {
				if (t.dataset) {
					return t.dataset[k] = v;
				}
				var a = t.getAttribute(["data-", k].join(""));
				t.setAttribute(["data-", k].join(""), "" + v);
				return a;
			},
			get: function(t, k) {
				if (t.dataset) {
					return t.dataset[k];
				}
				var a = t.getAttribute(["data-", k].join(""));
				if (!a) return null;
				return a;
			},
			del: function(t, k) {
				if (t.dataset) {
					delete t.dataset[k];
				}
				t.removeAttribute(["data-", k].join(""));
			}
		},
		create: function(name, attrs, children, properties, xmlns) {
			var r = (xmlns && document.createElementNS ? document.createElementNS(xmlns, name) : document.createElement(name));
			if (attrs) {
				for (var i in attrs) {
					var curAttr = attrs[i];
					var ns = i.split(/:/);
					var ns0 = ns[0];
					if (ns.length == 1) {
						if (ns0 == "class") r.className = curAttr;
						else r.setAttribute(ns0, curAttr);
					} else {
						if (ns0 == "svg") {
							ns0 = "http://www.w3.org/2000/svg";
						} else if (ns0 == "xlink") {
							ns0 = "http://www.w3.org/1999/xlink";
						} else if (ns0 == "xhtml") {
							ns0 = "http://www.w3.org/1999/xhtml";
						}
						if (r.setAttributeNS) r.setAttributeNS(ns0, ns[1], curAttr);
						else r.setAttribute(i, curAttr);
					}
				}
			}
			if (children) {
				for (var i = 0, l = children.length; i < l; i++) {
					r.appendChild(children[i]);
				}
			}
			if (properties) {
				for (var i in properties) {
					r[i] = properties[i];
				}
			}
			if (r.nodeName.toLowerCase() == "canvas") $.compat.element.canvas(r);
			return $(r);
		},
		computedStyle: function(element) {
			return (typeof element.currentStyle !== "undefined" ? element.currentStyle : document.defaultView.getComputedStyle(element, null));
		},
		/**
		 * start and end values:
		 *   0 = base (width or height)
		 *   1 = padding
		 *   2 = border
		 *   3 = margin
		 * default is equivalent to element.offset{Width,Height}
		 * EXCEPT that is will still give values when not displayed:
		 *   start = 0
		 *   end = 2
		 */
		getBoxSize: function(element, wh, start, end) {
			if (typeof start === "undefined") start = 0;
			if (typeof end === "undefined") end = 2;
			var cs = sj.dom.computedStyle(element);
			var r = 0;
			var vars = [];
			var bsv = boxSizeVars[wh];
			for (var i = 0, l = bsv.length; i < l; i += 2) {
				var a = 0;
				try {
					a = parseFloat(cs[bsv[i]]);
					if (isNaN(a)) a = 0;
				} catch (e) {
					a = 0;
				}
				var b = 0;
				try {
					b = parseFloat(cs[bsv[i + 1]]);
					if (isNaN(b)) b = 0;
				} catch (e) {
					b = 0;
				}
				vars[i / 2] = a + b;
			}
			for (var i = start; i <= end; i++) {
				if (i == 0) {
					var a = (wh == "width" ? element.offsetWidth : element.offsetHeight);
					a -= vars[0] - vars[1];
					if (a > 0) r += a;
				} else {
					r += vars[i - 1];
				}
			}
			return r;
		},
		fullOffset: function(element, mod) {
			var r = 0;
			mod = ["offset", mod].join("");
			while (element.offsetParent) {
				r += element[mod];
				element = element.offsetParent;
			}
			return r;
		}
	};
	$.xml = {
		getSelection: function() {
			return typeof(document.selection) === "undefined" ? (global.getSelection || document.getSelection)() : document.selection;
		},
		getRange: function() {
			var s = $.xml.getSelection();
			return typeof(s.createRange) === "undefined" ? s.getRangeAt(0) : s.createRange();
		},
		parseXML: function(s, d) {
			try {
				var x = new ActiveXObject("Microsoft.XMLDOM");
				x.async = "false";
				x.loadXML(s);
				x = d.importNode(x.documentElement, true);
				$.xml.addScriptFromXml(x);
				return x; 
			} catch(e) {
				parser = new DOMParser();
				var x = parser.parseFromString(s, "text/xml");
				x = d.importNode(x.documentElement, true);
				$.xml.addScriptFromXml(x);
				return x;
			}
		},
		addScriptFromXml: function(t) {
			for (var i = 0; i < t.childNodes.length; i++) {
				if (t.childNodes[i].nodeType != 1) {
					continue;
				}
				if (t.childNodes[i].nodeName.toLowerCase() == "script") {
					var an = t.childNodes[i].getAttributeNode("src");
					if (an && an.specified) {
						var s = document.createElement("script");
						s.type = "text/javascript";
						s.src = t.childNodes[i].getAttribute("src");
						document.getElementsByTagName("head")[0].appendChild(s);
					} else $.js.globalEval($.dom.text(t.childNodes[i]));
				} else {
					$.xml.addScriptFromXml(t.childNodes[i]);
				}
			}
		},
		toHTML: function(d) {
			var r = null;
			if (d.nodeType == 1) {
				if ($.browser.name == "Explorer") {
					if (d.nodeName.toLowerCase() == "style") {
						r = document.createStyleSheet();
					} else r = document.createElement(d.nodeName);
				} else {
					r = document.createElement(d.nodeName);
				}
				var l = d.attributes.length;
				for (var i = 0; i < l; i++) {
					var a = d.attributes[i];
					if ($.browser.name == "Explorer") {
						if (d.nodeName.toLowerCase() == "style") {
							if (a.nodeName.toLowerCase() == "href") r.href = a.nodeValue;
						} else r.setAttribute(a.nodeName, a.nodeValue);
					} else r.setAttribute(a.nodeName, a.nodeValue);
				}
			} else if (d.nodeType == 3) {
				r = document.createTextNode(d.data);
			}
			l = d.childNodes.length;
			for (var i = 0; i < l; i++) {
				var n = d.childNodes[i];
				if (n.nodeType == 1 || n.nodeType == 3) {
					var v = $.xml.toHTML(n);
					if ($.browser.name == "Explorer") {
						if ("nodeType" in v) {
							if ("cssText" in r && v.nodeType == 3) {
								r.cssText = v.nodeValue;
							} else if (r.nodeName.toLowerCase() == "script" && v.nodeType == 3) {
								r.text = v.nodeValue;
							} else r.appendChild(v);
						}
					} else r.appendChild(v);
				}
			}
			if ($.browser.name == "Explorer" && "nodeName" in r && r.nodeName.toLowerCase() == "canvas") $.compat.element.canvas(r);
			return r;
		}
	};
	$.http = {
		param: function(a) {
			var s = [];
			var add = function(k, v){
				s.push([encodeURIComponent(k), '=', encodeURIComponent(v)].join(""));
			};
			if ($.js.isArray(a)) {
				for (var ak in a) {
					add(a[ak].name, a[ak].value);
				}
			} else {
				for (var j in a) {
					if ($.js.isArray(a[j])) {
						var l = a[j].length;
						for (var i = 0; i < l; i++) {
							add(j, a[j][i]);
						}
					} else add(j, $.js.isFunction(a[j]) ? a[j]() : a[j]);
				}
			}
			return s.join("&").replace(/%20/g, "+");
		},
		unparam: function(q) {
			var query_string = {};
			var vars = q.split("&");
			var len = vars.length;
			for (var i = 0; i < len; i++) {
				var pair = vars[i].split("=");
				pair[0] = decodeURIComponent(pair[0]);
				pair[1] = decodeURIComponent(pair[1]);
				if (typeof(query_string[pair[0]]) === "undefined") {
					query_string[pair[0]] = pair[1];
				} else if (typeof(query_string[pair[0]]) === "string") {
					var arr = [query_string[pair[0]], pair[1]];
					query_string[pair[0]] = arr;
				} else {
					query_string[pair[0]].push(pair[1]);
				}
			} 
			return query_string;
		},
		httpSuccess: function(xhr) {
			try {
				return !xhr.status && location.protocol == "file:" ||
					(xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || xhr.status == 1223;
			} catch(e){}
			return false;
		},
		httpData: function(xhr, ct) {
			if (typeof ct !== "string") {
				try {
					ct = xhr.getResponseHeader("content-type");
				} catch (e){};
			}
			var d = null;
			if (ct.match(/html/)) {
				var nd = document.createElement("div");
				var text = xhr.responseText.trim();
				text = $.html.appendStyles(text);
				nd.innerHTML = text;
				if (nd.childNodes.length > 1) {
					d = nd;
				} else if (nd.childNodes.length == 1) {
					d = nd.childNodes[0];
				}
				$.xml.addScriptFromXml(d);
			} else if (ct.match(/json/)) {
				d = JSON.parse(xhr.responseText);
			} else if (ct.match(/xml/)) {
				d = xhr.responseXML.documentElement;
				$.xml.addScriptFromXml(d);
				if ($.browser.name == "Explorer") d = $.xml.toHTML(d);
			} else {
				d = xhr.responseText;
			}
			return d;
		},
		createXMLHttpRequest: function() {
			var r = null;
			try {
				r = new XMLHttpRequest();
			} catch (e) {
				r = new ActiveXObject("Microsoft.XMLHTTP");
			}
			return r;
		},
		send: function(o) {
			o = $.js.extend({}, {
				method: "GET",
				url: "",
				async: true,
				user: "",
				password: "",
				timeout: 30000,
				cache: true,
				contentType: "",
				responseContentType: null,
				headers: {},
				data: null,
				processData: true,
				queryData: {},
				withCredentials: true
			}, o);
			
			var r = null;
			if (o.async) r = o.sjhttpsenddelay = new $.delay.Delay();
			
			if (o.url === "") {
				if (o.async) r.error("No URL specified");
				return r;
			}
			if (!o.headers["Content-Type"]) {
				switch (o.contentType) {
					case "text":
						o.headers["Content-Type"] = "text/plain;charset=UTF-8";
						break;
					case "xml":
						o.headers["Content-Type"] = "text/xml;charset=UTF-8";
						break;
					case "json":
						o.headers["Content-Type"] = "application/json;charset=UTF-8";
						break;
					default:
						if (o.contentType == "") {
							if (o.method == "POST") {
								o.headers["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8";
							}
						} else {
							o.headers["Content-Type"] = o.contentType;
						}
						break;
				}
			}
			if (!o.headers["Accept"]) {
				o.headers["Accept"] = "text/html,application/xhtml+xml,application/xml,application/json,*/*";
			}
			
			if (typeof o.queryData !== "string") o.queryData = $.http.param(o.queryData);
			if (o.queryData != "") o.url += (o.url.match(/\?/) ? "&" : "?") + o.queryData;
			if (!o.cache) o.url += (o.url.match(/\?/) == null ? "?" : "&") + (new Date()).getTime();
			if (o.headers["Content-Type"] && o.data && o.processData && typeof o.data !== "string") {
				if (typeof o.data === "object" && o.headers["Content-Type"].match(/^application\/json/)) {
					o.data = JSON.stringify(o.data);
				} else if (typeof o.data === "object" && o.headers["Content-Type"].match(/^application\/x-www-form-urlencoded/)) {
					o.data = $.http.param(o.data);
				}
			}
			
			var xhr = $.http.createXMLHttpRequest();
			
			if (!("abort" in xhr)) {
				xhr.abort = function() {
					xhr.onreadystatechange = null;
					if (r) r.error({xhr: xhr, options: o, status: 0, statusText: "Aborted"});
				};
			}
			
			if (r) r.setData("xhr", xhr);
			
			if ("addEventListener" in xhr) {
				if (r) {
					try {
						xhr.addEventListener("progress", function(e) {
							if (e.lengthComputable) r.progress({data: e.loaded / e.total, options: o, xhr: this});
							else r.progress({data: "progress", options: o, xhr: this});
						}, false);
					} catch(e) {};
					try {
						xhr.addEventListener("abort", function(e) {
							r.error({xhr: this, options: o, status: 0, statusText: "Aborted"});
						}, false);
					} catch(e) {};
					try {
						xhr.addEventListener("error", function(e) {
							r.error({xhr: this, options: o, status: 0, statusText: "Error"});
						}, false);
					} catch(e) {};
					try {
						xhr.addEventListener("stalled", function(e) {
							r.progress({data: "stalled", options: o, xhr: this});
						}, false);
					} catch(e) {};
					try {
						xhr.addEventListener("suspend", function(e) {
							r.progress({data: "suspend", options: o, xhr: this});
						}, false);
					} catch(e) {};
					try {
						xhr.addEventListener("load", function(e) {
							if ($.http.httpSuccess(this)) {
								d = $.http.httpData(this, o.responseContentType);
								r.resolve({data: d, xhr: this, options: o});
							} else {
								r.error({xhr: this, options: o, status: this.status, statusText: this.statusText});
							}
						}, false);
					} catch(e) {};
				}
			} else {
				xhr.onreadystatechange = function() {
					$.http._xhr_rsc.call(xhr, o);
				};
			}
			
			xhr.open(o.method, o.url, o.async, o.user, o.password);
			if (typeof xhr.withCredentials !== "undefined") xhr.withCredentials = o.withCredentials;
			xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
			for (var h in o.headers) {
				xhr.setRequestHeader(h, o.headers[h]);
			}
			
			xhr.send(o.data);
			if (!o.async) return $.http._xhr_rsc.call(xhr, o);
			else return r;
		},
		_xhr_rsc: function(o) {
			if (this.readyState == 4) {
				if ($.http.httpSuccess(this)) {
					var d = $.http.httpData(this, o.responseContentType);
					if (o.sjhttpsenddelay) o.sjhttpsenddelay.resolve({data: d, xhr: this, options: o});
					else return d;
				} else {
					if (o.sjhttpsenddelay) o.sjhttpsenddelay.error({xhr: this, options: o, status: this.status, statusText: this.statusText});
					else return null;
				}
			} else {
				if (o.sjhttpsenddelay) o.sjhttpsenddelay.progress({data: "progress", options: o, xhr: this});
			}
		},
		get: function(url, data, pass, responseContentType, async) {
			var async = true;
			if (typeof async === "boolean") async = async;
			return $.http.send({
				url: url,
				method: "GET",
				queryData: data,
				timeout: 15000,
				responseContentType: responseContentType,
				async: async,
				pass: pass
			});
		},
		post: function(url, data, pass, contentType, responseContentType, async) {
			var async = true;
			if (typeof async === "boolean") async = async;
			return $.http.send({
				url: url,
				method: "POST",
				data: data,
				timeout: 30000,
				cache: false,
				contentType: contentType,
				responseContentType: responseContentType,
				async: async,
				pass: pass
			});
		},
		submit: function(url, form, pass) {
			var options = {
				form: form,
				timeout: false,
				cache: false,
				pass: pass,
				iframe: true,
				data: {wrapwith: "textarea"}
			};
			if (!options || !options.form) return null;
			var form = $(options.form);
			var url = form.getAttribute('action').trim();
			if (url) url = (url.match(/^([^#]+)/)||[])[1];
			url = url || global.location.href || ''
			options = $.js.extend({
				url:  url,
				method: form.getAttribute('method') || 'GET'
			}, options || {});
			var veto = {};
			if (veto.veto) {
				return false;
			}
			var a = $.html.formData(form);
			if (options.data) {
				options.extraData = options.data;
				for (var n in options.data) {
					if ($.js.isArray(options.data[n])) {
						for (var k in options.data[n])
							if (n in a) {
								if ($.js.isArray(a[n])) a[n].push(options.data[n][k]); else a[n] = [a[n], options.data[n][k]];
							} else a[n] = options.data[n][k];
						}
					else {
						if (n in a) {
							if ($.js.isArray(a[n])) a[n].push(options.data[n]); else a[n] = [a[n], options.data[n]];
						} else a[n] = options.data[n];
					}
				}
			}
			if (veto.veto) {
				return this;
			}
			var q = $.http.param(a);
			if (options.method.toUpperCase() == 'GET') {
				options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
				options.data = null;
			} else options.data = q;
			var callbacks = [];
			if (options.success)
				callbacks.push(options.success);
			options.success = function(data, status) {
				for (var i = 0, max = callbacks.length; i < max; i++)
					callbacks[i].apply(options, [data, status, form]);
			};
			var ifiles = $.q.t(form, "input");
			var found = false;
			$.js.each(ifiles, function() {
				if (this.type == "file" && this.value) found = true;
			});
			
			var delay = null;
			var multipart = false;
			if (options.iframe || found || multipart) {
				delay = fileUpload();
			} else delay = $.http.send(options);
			
			return delay;
			function fileUpload() {
				var delay = new $.delay.Delay();
				var opts = $.js.extend({}, options);
				var s = $.js.extend({}, opts);
				var id = ['sjFormIO', Math.random(), (new Date().getTime())].join("");
				var io = sj.dom.create("iframe", {
					id: id,
					name: id,
					src: "about:blank",
					style: "position:absolute;top:-1000px;left:-1000px"
				});
				var xhr = {
					aborted: 0,
					responseText: null,
					responseXML: null,
					status: 0,
					statusText: 'n/a',
					getAllResponseHeaders: function() {},
					getResponseHeader: function() {},
					setRequestHeader: function() {},
					abort: function() {
						this.aborted = 1;
						io.setAttribute('src', 'about:blank');
					}
				};
				delay.setData("xhr", xhr);
				if (xhr.aborted) return delay;
				var cbInvoked = 0;
				var timedOut = 0;
				setTimeout(function() {
					var t = form.getAttribute('target'), a = form.getAttribute('action');
					form.setAttribute('target', id);
					var m = form.getAttribute('method');
					if (m != 'POST' && m != 'PUT') form.setAttribute('method', 'POST');
					if (form.getAttribute('action') != opts.url) form.setAttribute('action', opts.url);
					if (!options.skipEncodingOverride) {
						form.setAttribute("encoding", "multipart/form-data");
						form.setAttribute("enctype", "multipart/form-data");
					}
					if (opts.timeout) setTimeout(function() {timedOut = true; cb();}, opts.timeout);
					var extraInputs = [];
					try {
						if (options.extraData)
							for (var n in options.extraData) {
								var ed = options.extraData[n];
								if (!$.js.isArray(ed)) {
									ed = [ed];
								}
								for (var z = 0, len = ed.length; z < len; z++) {
									var ih = $.dom.create("input", {type:"hidden",name:n,value:ed[z]});
									form.appendChild(ih);
									extraInputs.push(ih);
								}
							}
						document.body.appendChild(io);
						io.addEventListener("load", cb, false);
						form.submit();
					}
					finally {
						form.setAttribute('action', a);
						t ? form.setAttribute('target', t) : form.removeAttribute('target');
						$.js.each(extraInputs, function() {
							this.parentNode.removeChild(this);
						});
					}
				}, 10);
				var nullCheckFlag = 0;
				function cb() {
					if (cbInvoked++) return;
					io.removeEventListener("load", cb, false);
					var ok = true;
					try {
						if (timedOut) throw 'timeout';
						var data, doc;
						doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
						if ((doc.body == null || doc.body.innerHTML == '') && !nullCheckFlag) {
							nullCheckFlag = 1;
							cbInvoked--;
							setTimeout(cb, 100);
							return;
						}
						if (xhr.aborted) {
							setTimeout(function() {
								io.parentNode.removeChild(io);
								xhr.responseXML = null;
							}, 100);
							delay.error({xhr: xhr, options: opts, status: 0, statusText: "Aborted"});
							return;
						}
						xhr.responseText = doc.body ? doc.body.innerHTML : null;
						xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
						xhr.getResponseHeader = function(header){
							var headers = {'content-type': "application/json"};
							return headers[header];
						};
						//if (opts.dataType == 'application/json' || opts.dataType == 'script') {
							var ta = doc.getElementsByTagName('textarea')[0];
							xhr.responseText = ta ? ta.value : xhr.responseText;
						//} else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
						//	xhr.responseXML = toXml(xhr.responseText);
						//}
						data = $.http.httpData(xhr);
					} catch(e) {
						ok = false;
						delay.error({options:opts,xhr:xhr,status:0,statusText:"Error",exception:e});
					}
					if (ok) delay.resolve({data: data, options: opts});
					setTimeout(function() {
						io.parentNode.removeChild(io);
						xhr.responseXML = null;
					}, 100);
				};
				function toXml(s, doc) {
					if (global.ActiveXObject) {
						doc = new ActiveXObject('Microsoft.XMLDOM');
						doc.async = 'false';
						doc.loadXML(s);
					}
					else
						doc = (new DOMParser()).parseFromString(s, 'text/xml');
					return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
				};
				return delay;
			};
			return false;
		}
	};
	var urlcacheOsdHandler = null;
	var urlcacheOsdCounter = 0;
	$.urlcache = {
		__cache: {},
		has: function(url) {
			if ($.urlcache.__cache[url]) {
				return true;
			}
			return false;
		},
		get: function(piece, options, params) {
			var url = piece;
			options.piece = piece;
			if (!url.match(/^[\/.]/)) url = [sj.env.SITE_ROOT, url].join("")
			if (params && typeof params == "object") {
				url = [url, "?", $.http.param(params)].join("");
			}
			var r = new $.delay.Delay();
			if (url in $.urlcache.__cache) {
				r.resolve({data: $.urlcache._get_cache(url), piece: piece, options: options});
			} else {
				if ($.ui.osd) {
					if (urlcacheOsdHandler == null) urlcacheOsdHandler = $.ui.osd.add(document.createTextNode($.locale("Downloading. Please wait...")));
					urlcacheOsdCounter++;
				}
				$.http.send($.js.extend({
					url: url,
					method: "GET",
					timeout: 15000
				}, options, {delay: r, piece: piece}))
				.addEventListener("success", $.urlcache._get_success, piece)
				.addEventListener("progress", $.urlcache._get_progress, piece)
				.addEventListener("error", $.urlcache._get_failure, piece);
			}
			return r;
		},
		_get_success: function(d, piece) {
			$.urlcache.__cache[d.options.url] = d.data;
			if (urlcacheOsdHandler != null && --urlcacheOsdCounter == 0) {
				$.ui.osd.remove(urlcacheOsdHandler);
				urlcacheOsdHandler = null;
			}
			if (d.options.delay) d.options.delay.resolve({data: $.urlcache._get_cache(d.options.url), piece: piece, options: d.options, piece: d.options.piece});
		},
		_get_failure: function(d, piece) {
			if (urlcacheOsdHandler != null && --urlcacheOsdCounter == 0) {
				$.ui.osd.remove(urlcacheOsdHandler);
				urlcacheOsdHandler = null;
			}
			if (d.options.delay) d.options.delay.error(d);
		},
		_get_progress: function(d, piece) {
			if (d.options.delay) d.options.delay.progress(d);
		},
		_get_cache: function(i) {
			var d = $.urlcache.__cache[i];
			if ($.js.isArray(d)) {
				var c = [];
				for (var i = 0; i < d.length; i++) {
					c.push(d[i].cloneNode(true));
				}
				return c;
			} else if ("cloneNode" in d) {
				return d.cloneNode(true);
			}
			return d;
		}
	};
	$.html = {
		addScript: function(url, onload) {
			var sc = document.getElementsByTagName("script");
			for (var i = 0, l = sc.length; i < l; i++) {
				var sci = sc[i];
				if (sci.getAttribute("src") == url) {
					if (onload) onload.call(sci);
					return sci;
				}
			}
			var s = document.createElement("script");
			var h = document.getElementsByTagName("head")[0];
			s.type = "text/javascript";
			s.src = url;
			if (onload) {
				s.onload = function() {
					s.onreadystatechange = null;
					s.onload = null;
					onload.call(s);
				};
				s.onreadystatechange = function() {
					if (s.readyState == "complete" || s.readyState == "loaded") {
						s.onreadystatechange = null;
						s.onload = null;
						onload.call(s);
					}
				}
			}
			h.appendChild(s);
			return s;
		},
		addStyle: function(url, onload) {
			var sc = $.q.t(document, "link");
			for (var i = 0; i < sc.length; i++) {
				if (sc[i].getAttribute("href") == url) return sc[i];
			}
			var s = document.createElement("link");
			var h = document.getElementsByTagName("head")[0];
			s.rel = "stylesheet";
			s.type = "text/css";
			s.href = url;
			/* TODO: Make load detection for css.
			 * s.onload = onload;
			s.onreadystatechange = function() {
				if (this.readyState == 'complete') {
					onload(this);
				}
			}*/
			h.appendChild(s);
			return s;
		},
		htmlStyleRegExpAll: /<style[^>]*>[\u0001-\uFFFF]*?<\/style>/img,
		htmlStyleRegExp: /<style[^>]*>([\u0001-\uFFFF]*?)<\/style>/im,
		appendStyles: function(text) {
			var sheet = document.getElementById("sjStyleSheetDynamicAppender");
			if (!sheet) {
				sheet = document.createElement("style");
				sheet.id = "sjStyleSheetDynamicAppender";
				sheet.type = "text/css";
				document.getElementsByTagName("head")[0].appendChild(sheet);
			}
			var styles = (text.match($.html.htmlStyleRegExpAll) || []);
			for (var i = 0, l = styles.length; i < l; i++) {
				if ($.browser.name == "Explorer") sheet.styleSheet.cssText += (styles[i].match($.html.htmlStyleRegExp) || [", ", ""])[1];
				else sheet.appendChild(document.createTextNode((styles[i].match($.html.htmlStyleRegExp) || [", ", ""])[1]));
			}
			return text.replace($.html.htmlStyleRegExpAll, "");
		},
		formData: function(form) {
			var r = {};
			var add = function(n, v) {
				if (n in r) {
					if ($.js.isArray(r[n])) r[n].push(v); else r[n] = [r[n], v];
				} else r[n] = v;
			}
			for (var i in {"input":1,"select":1,"textarea":1}) {
				$.js.each($.q.t(form, i), function() {
					var t = this;
					if (t.name && t.name != "" && !t.disabled) {
						switch (i) {
							case "input":
								if (this.type == "radio" || this.type == "checkbox") {
									if (this.checked !== undefined && this.checked) add(t.name, t.value);
								} else if (this.value != undefined && t.value != null) {
									add(t.name, t.value);
								}
								break;
							case "select":
								if (this.selectedIndex != -1) {
									add(t.name, t.value);
								}
								break;
							case "textarea":
								if (this.value != undefined && t.value != null) {
									add(t.name, t.value);
								}
								break;
						}
					}
				});
			}
			return r;
		},
		htmlTranslationTable: function(table, quote_style) {
			var entities = {}, hash_map = {}, decimal = 0, symbol = '';
			var constMappingTable = {}, constMappingQuoteStyle = {};
			var useTable = {}, useQuoteStyle = {};
			
			constMappingTable[0] = 'HTML_SPECIALCHARS';
			constMappingTable[1] = 'HTML_ENTITIES';
			constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
			constMappingQuoteStyle[2] = 'ENT_COMPAT';
			constMappingQuoteStyle[3] = 'ENT_QUOTES';

			useTable = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
			useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

			if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
				throw new Error("Table: "+useTable+' not supported');
			}

			entities['38'] = '&amp;';
			if (useTable === 'HTML_ENTITIES') {
				entities['160'] = '&nbsp;';
				entities['161'] = '&iexcl;';
				entities['162'] = '&cent;';
				entities['163'] = '&pound;';
				entities['164'] = '&curren;';
				entities['165'] = '&yen;';
				entities['166'] = '&brvbar;';
				entities['167'] = '&sect;';
				entities['168'] = '&uml;';
				entities['169'] = '&copy;';
				entities['170'] = '&ordf;';
				entities['171'] = '&laquo;';
				entities['172'] = '&not;';
				entities['173'] = '&shy;';
				entities['174'] = '&reg;';
				entities['175'] = '&macr;';
				entities['176'] = '&deg;';
				entities['177'] = '&plusmn;';
				entities['178'] = '&sup2;';
				entities['179'] = '&sup3;';
				entities['180'] = '&acute;';
				entities['181'] = '&micro;';
				entities['182'] = '&para;';
				entities['183'] = '&middot;';
				entities['184'] = '&cedil;';
				entities['185'] = '&sup1;';
				entities['186'] = '&ordm;';
				entities['187'] = '&raquo;';
				entities['188'] = '&frac14;';
				entities['189'] = '&frac12;';
				entities['190'] = '&frac34;';
				entities['191'] = '&iquest;';
				entities['192'] = '&Agrave;';
				entities['193'] = '&Aacute;';
				entities['194'] = '&Acirc;';
				entities['195'] = '&Atilde;';
				entities['196'] = '&Auml;';
				entities['197'] = '&Aring;';
				entities['198'] = '&AElig;';
				entities['199'] = '&Ccedil;';
				entities['200'] = '&Egrave;';
				entities['201'] = '&Eacute;';
				entities['202'] = '&Ecirc;';
				entities['203'] = '&Euml;';
				entities['204'] = '&Igrave;';
				entities['205'] = '&Iacute;';
				entities['206'] = '&Icirc;';
				entities['207'] = '&Iuml;';
				entities['208'] = '&ETH;';
				entities['209'] = '&Ntilde;';
				entities['210'] = '&Ograve;';
				entities['211'] = '&Oacute;';
				entities['212'] = '&Ocirc;';
				entities['213'] = '&Otilde;';
				entities['214'] = '&Ouml;';
				entities['215'] = '&times;';
				entities['216'] = '&Oslash;';
				entities['217'] = '&Ugrave;';
				entities['218'] = '&Uacute;';
				entities['219'] = '&Ucirc;';
				entities['220'] = '&Uuml;';
				entities['221'] = '&Yacute;';
				entities['222'] = '&THORN;';
				entities['223'] = '&szlig;';
				entities['224'] = '&agrave;';
				entities['225'] = '&aacute;';
				entities['226'] = '&acirc;';
				entities['227'] = '&atilde;';
				entities['228'] = '&auml;';
				entities['229'] = '&aring;';
				entities['230'] = '&aelig;';
				entities['231'] = '&ccedil;';
				entities['232'] = '&egrave;';
				entities['233'] = '&eacute;';
				entities['234'] = '&ecirc;';
				entities['235'] = '&euml;';
				entities['236'] = '&igrave;';
				entities['237'] = '&iacute;';
				entities['238'] = '&icirc;';
				entities['239'] = '&iuml;';
				entities['240'] = '&eth;';
				entities['241'] = '&ntilde;';
				entities['242'] = '&ograve;';
				entities['243'] = '&oacute;';
				entities['244'] = '&ocirc;';
				entities['245'] = '&otilde;';
				entities['246'] = '&ouml;';
				entities['247'] = '&divide;';
				entities['248'] = '&oslash;';
				entities['249'] = '&ugrave;';
				entities['250'] = '&uacute;';
				entities['251'] = '&ucirc;';
				entities['252'] = '&uuml;';
				entities['253'] = '&yacute;';
				entities['254'] = '&thorn;';
				entities['255'] = '&yuml;';
			}

			if (useQuoteStyle !== 'ENT_NOQUOTES') {
				entities['34'] = '&quot;';
			}
			if (useQuoteStyle === 'ENT_QUOTES') {
				entities['39'] = '&#39;';
			}
			entities['60'] = '&lt;';
			entities['62'] = '&gt;';

			for (decimal in entities) {
				symbol = String.fromCharCode(decimal);
				hash_map[symbol] = entities[decimal];
			}
			
			return hash_map;
		},
		htmlspecialchars: function(string, quote_style) {
			if (!string) return string;
			var hash_map = {}, symbol = '', tmp_str = '', entity = '';
			tmp_str = string.toString();
			
			if (false === (hash_map = $.html.htmlTranslationTable('HTML_SPECIALCHARS', quote_style))) {
				return false;
			}
			
			hash_map["'"] = '&#039;';
			for (symbol in hash_map) {
				entity = hash_map[symbol];
				tmp_str = tmp_str.split(symbol).join(entity);
			}
			
			return tmp_str;
		},
		htmlspecialcharsDecode: function(string, quote_style) {
			string = string.toString();

			string = string.replace(/&amp;/g, '&');
			string = string.replace(/&lt;/g, '<');
			string = string.replace(/&gt;/g, '>');

			if (quote_style == 'ENT_QUOTES') {
				string = string.replace(/&quot;/g, '"');
				string = string.replace(/&#039;/g, '\'');
			} else if (quote_style != 'ENT_NOQUOTES') {
				string = string.replace(/&quot;/g, '"');
			}

			return string;
		},
		window: {
			innerHeight: (function(){
				if (typeof window.innerHeight === "undefined") return (function(){return document.body.parentNode.clientHeight})
				else return (function(){return window.innerHeight});
			})(),
			innerWidth: (function(){
				if (typeof window.innerWidth === "undefined") return (function(){return document.body.parentNode.clientWidth})
				else return (function(){return window.innerWidth});
			})(),
			pageXOffset: (function(){
				if (typeof window.pageXOffset === "undefined") return (function(){return document.body.scrollLeft})
				else return (function(){return window.pageXOffset});
			})(),
			pageYOffset: (function(){
				if (typeof window.pageYOffset === "undefined") return (function(){return document.body.scrollTop})
				else return (function(){return window.pageYOffset});
			})(),
			screenX: (function(){
				if (typeof window.screenX === "undefined") return (function(){return window.screenLeft})
				else return (function(){return window.screenX});
			})(),
			screenY: (function(){
				if (typeof window.screenY === "undefined") return (function(){return window.screenTop})
				else return (function(){return window.screenY});
			})()
		},
		Animation: function(elements, properties, duration) {
			if (!sj.js.isArray(elements)) elements = [elements];
			var t = this;
			t.elements = elements;
			t.properties = {};
			t.duration = duration;
			t._listeners = [];
			for (var i in properties) {
				t.addProperty(i, properties[i]);
			}
		}
	};
	var htmlAnimationFinishListener = function(event) {
		var updater = event.target;
		var animation = updater.htmlAnimation;
		var ap = animation.properties;
		var counter = 0;
		for (var i in ap) {
			var api = ap[i];
			if (api.updater == updater) {
				api.state = "finish";
			} else if (api.state != "finish") counter++;
		}
		this.started = false;
		this.stopped = false;
		this.finished = true;
		this.paused = false;
		if (counter == 0) {
			var lt = animation._listeners;
			for (var i = 0, l = lt.length; i < l; i++) {
				var lti = lt[i];
				lti.callback.call(animation, lti.pass);
			}
		}
	};
	var htmlAnimationResetListener = function(event) {
		var updater = event.target;
		var ap = updater.htmlAnimation.properties;
		for (var i in ap) {
			var api = ap[i];
			if (api.updater == updater) {
				api.state = "reset";
				break;
			}
		}
		this.started = false;
		this.stopped = true;
		this.finished = false;
		this.paused = false;
	};
	$.html.Animation.prototype = {
		started: false,
		paused: false,
		stopped: true,
		finished: false,
		addElement: function(element) {
			if (this.elements.indexOf(element) > -1) return; 
			this.elements.push(element);
			return this;
		},
		removeElement: function(element) {
			if (this.elements.indexOf(element) > -1) this.elements.splice(this.elements.indexOf(element), 1);
			return this;
		},
		clearElements: function() {
			this.elements = [];
			return this;
		},
		addProperty: function(name, options) {
			var t = this;
			if (name in t.properties) return t;
			if (typeof options !== "object") {
				options = {
					from: null,
					to: options,
					dur: t.duration,
					finish: "freeze"
				};
			}
			options = sj.js.extend({}, {
				from: null,
				to: null,
				dur: t.duration,
				finish: "freeze"
			}, options, {htmlAnimation: t, skipReset: true});
			t.properties[name] = {
				updater: (new $.updater.Updater(options)).addValueListener(function(v){
					for (var i = 0, l = t.elements.length; i < l; i++) {
						t.elements[i].style[name] = v;
					}
				}).addEventListener("finish", htmlAnimationFinishListener)
				.addEventListener("reset", htmlAnimationResetListener),
				status: "reset"
			};
			return this;
		},
		removeProperty: function(name) {
			if (!(name in this.properties)) return this;
			this.properties[name].updater.stop();
			delete this.properties[name];
			return this;
		},
		reset: function() {
			for (var i in this.properties) {
				var updater = this.properties[i].updater;
				if (this.elements.length > 0) {
					if (updater.from == null) updater.from = $.dom.computedStyle(this.elements[0])[i] || 0;
					if (updater.by == null && updater.to == null) updater.to = $.dom.computedStyle(this.elements[0])[i] || 1;
				}
				updater.reset();
			}
			return this;
		},
		start: function() {
			if (!this.paused) this.reset();
			for (var i in this.properties) {
				this.properties[i].updater.start();
			}
			this.started = true;
			this.stopped = false;
			this.finished = false;
			this.paused = false;
			return this;
		},
		pause: function() {
			for (var i in this.properties) {
				this.properties[i].updater.pause();
			}
			this.started = false;
			this.stopped = false;
			this.finished = false;
			this.paused = true;
			return this;
		},
		stop: function() {
			for (var i in this.properties) {
				this.properties[i].updater.stop();
			}
			this.started = false;
			this.stopped = true;
			this.finished = false;
			this.paused = false;
			return this;
		},
		reverse: function() {
			for (var i in this.properties) {
				this.properties[i].updater.reverse();
			}
			return this;
		},
		addFinishListener: function(callback, pass) {
			var lt = this._listeners;
			for (var i = 0, l = lt.length; i < l; i++) {
				if (lt[i].callback == callback) return this;
			}
			lt.push({callback: callback, pass: pass});
			return this;
		},
		removeFinishListener: function(callback) {
			var lt = this._listeners;
			for (var i = 0, l = lt.length; i < l; i++) {
				if (lt[i].callback == callback) {
					lt.splice(i, 1);
					break;
				}
			}
			return this;
		}
	};
	
	$.css = {
		center: function(element, h, v) {
			var cs = $.dom.computedStyle(element);
			if (typeof h === "undefined" || h) {
				if (cs.position == "static") {
					element.style.marginLeft = "auto";
					element.style.marginRight = "auto";
				} else {
					element.style.left = [(cs.position == "absolute" ? element.parentNode.offsetWidth / 2 : window.innerWidth / 2) - (element.offsetWidth / 2), "px"].join("");
				}
			}
			if (typeof v === "undefined" || v) {
				if (cs.position == "static") {
					// TODO
				} else {
					element.style.top = [(cs.position == "absolute" ? element.parentNode.offsetHeight / 2 : window.innerHeight / 2) - (element.offsetHeight / 2), "px"].join("");
				}
			}
		},
		applyBorderRadius: function(element, style) {
			if (!style) return;
			if ($.browser.engine.name == "Gecko") {
				if ($.browser.engine.version >= "1.9.1") element.style.MozBorderRadius = style;
				else element.style.MozBorderRadius = style.split(/\//)[0].trim();
			} else if ($.browser.engine.name == "WebKit") {
				var ellipse = style.split(/\//);
				ellipse[0] = (ellipse[0] ? ellipse[0].trim() : "");
				ellipse[1] = (ellipse[1] ? ellipse[1].trim() : "");
				var rad = [];
				for (var i = 0; i < 2; i++) {
					var radi = rad[i] = [];
					var parts = ellipse[i].split(/\s+/);
					for (var j = 0; j < 4; j++) {
						radi[j] = (j in parts ? parts[j] : null);
					}
					if (radi[2] == null && radi[0] != null) radi[2] = radi[0];
					if (radi[3] == null && radi[1] != null) radi[3] = radi[1];
					if (i == 1) {
						var rad0 = rad[0];
						for (var j = 0; j < 4; j++) {
							if (rad0[j] != null && !radi[j]) radi[j] = rad0[j];
						}
					}
				}
				element.style.webkitBorderTopLeftRadius = [rad[0][0], " ", rad[1][0]].join("");
				element.style.webkitBorderTopRightRadius = [rad[0][1], " ", rad[1][1]].join("");
				element.style.webkitBorderBottomRightRadius = [rad[0][2], " ", rad[1][2]].join("");
				element.style.webkitBorderBottomLeftRadius = [rad[0][3], " ", rad[1][3]].join("");
			} else element.style.borderRadius = style;
		}
	};
	
	$.hash = {
		_binds: {},
		currentHash: null,
		watcher: null,
		checkHash: function() {
			if (global.location.hash != $.hash.currentHash) {
				$.hash.currentHash = global.location.hash;
				$.hash.call();
			}
			if (!("onhashchange" in global)) $.hash.watcher = setTimeout($.hash.checkHash, 40);
		},
		startWatcher: function() {
			if ("onhashchange" in global) global.addEventListener("hashchange", $.hash.checkHash, false);
			else $.hash.watcher = setTimeout($.hash.checkHash, 40);
		},
		stopWatcher: function() {
			if ("onhashchange" in global) global.removeEventListener("hashchange", $.hash.checkHash, false);
			else if ($.hash.__watcher != null) clearTimeout($.hash.__watcher);
		},
		bind: function(h, f) {
			$.hash._binds[h] = f;
		},
		call: function(h, d) {
			if (typeof h !== "string") {
				h = global.location.hash.substring(1);
			}
			var c = false;
			for (var b in $.hash._binds) {
				var r = new RegExp(b);
				var m = r.exec(h);
				if (m) {
					c = true;
					$.hash._binds[b](m);
				}
			}
			if (c == false) {
				var m = h.match(/^([a-zA-Z]+)(?:[\/\?]+(.*))?/);
				if (m && m.length >= 2) {
					$.sys.process.exec(m[1], {hashURL: m[2]});
				}
			}
			return false;
		},
		set: function(h, doAction) {
			if (doAction === undefined) doAction = true;
			var nh = ["#", h].join("");
			if (global.location.hash != nh) {
				$.hash.currentHash = nh;
				global.location.hash = nh;
			}
			if (doAction) {
				$.hash.call();
			}
		},
		link: function(t, url) {
			if (!url && $(t).nodeName.toLowerCase() == "a") url = t.href;
			var b = [global.location.protocol, "//", global.location.host, $.env.SITE_ROOT].join("");
			url = url.replace(b, "");
			t.setUserData("sj.hash.link", url, null);
			t.addEventListener("click", $.hash.linkOnClick, false);
		},
		linkOnClick: function(e) {
			e.preventDefault();
			$.hash.set(this.getUserData("sj.hash.link"));
			return false;
		}
	};
	$.util = {
		basename: function(path, suffix) {
			var b = path.replace(/\/$/, '').replace(/^.*[\/\\]/g, '');
			if (typeof(suffix) == 'string' && b.substr(b.length - suffix.length) == suffix) {
				b = b.substr(0, b.length - suffix.length);
			}
			return b;
		}
	};
	$.timer = {
		Timer: function(options) {
			sj.js.extend(this, options);
			$.js.objectMixin(this, $.events.EventTarget);
			this._time = this.startTime;
			this.lastTime = this._time;
		}
	};
	var TimerPrototype = function() {
		this.interval = 20;
		this.currentInterval = 0;
		this._time = 0;
		this._inTick = false;
		this.status = 0;
		this.onEndTime = "pause";
		this.startTime = 0;
		this.endTime = Infinity;
		this.lastTime = 0;
		
		this.isTicking = function() {
			if (this.status == 1) return true;
			return false;
		};
		this.isPaused = function() {
			if (this.status == 2) return true;
			return false;
		};
		
		this.setTime = function(time) {
			this._time = time;
			this.dispatchEvent({type: "settime", time: this._time});
			return this;
		};
		this.getTime = function() {
			return this._time;
		};
		this.tick = function() {
			if (this._inTick) {
				this.currentInterval += this.interval;
				return;
			}
			this._inTick = true;
			this.lastTime = this._time;
			this._time += this.currentInterval;
			this.currentInterval = this.interval;
			if ((this.interval > 0 && 
					(this.startTime < this.endTime && this._time >= this.endTime) || 
					(this.startTime > this.endTime && this._time >= this.startTime)
				) ||
				(this.interval < 0 &&	
					(this.startTime < this.endTime && this._time <= this.endTime) || 
					(this.startTime > this.endTime && this._time <= this.startTime)
				)) {
				this._time = this.endTime;
				this.dispatchEvent({type: "tick", time: this._time, span: this._time - this.lastTime});
				this.dispatchEvent({type: "endtime", time: this._time});
				switch (this.onEndTime) {
					case "pause":
						this.pause();
						break;
					case "stop":
						this.stop();
						break;
					case "repeat":
						this._time = this.startTime;
						break;
					case "reverse":
						this.interval = -this.interval;
						break;
					default:
						this.pause();
						break;
				}
			} else {
				this.dispatchEvent({type: "tick", time: this._time, span: this._time - this.lastTime});
			}
			this._inTick = false;
			return this;
		};
		this.start = function() {
			var t = this;
			if (typeof t.ticker === "number") return t;
			t.status = 1;
			t.dispatchEvent({type: "start", time: t._time});
			t.currentInterval = t.interval;
			t.ticker = global.setInterval(function(late) {
				if (late) t.currentInterval += late;
				t.tick();
			}, t.interval);
			return t;
		};
		this.stop = function() {
			if (typeof this.ticker === "number") global.clearInterval(this.ticker);
			this.ticker = null;
			this.status = 0;
			this._time = this.startTime;
			this.dispatchEvent({type: "stop", time: this._time});
			return this;
		};
		this.pause = function() {
			if (typeof this.ticker === "number") global.clearInterval(this.ticker);
			this.ticker = null;
			this.status = 2;
			this.dispatchEvent({type: "pause", time: this._time});
			return this;
		};
	};
	$.timer.Timer.prototype = new TimerPrototype();
	
	var updaterActives = [];
	var updaterTick = function(e) {
		var t = e.span;
		var ua = updaterActives.slice();
		var l = ua.length;
		for (var i = 0; i < l; i++) {
			var uai = ua[i];
			uai.update(uai.time + (t * uai.multiplier));
		}
	};
	var updaterTimer = (new $.timer.Timer({interval:20})).addEventListener("tick", updaterTick);
	$.updater = {
		Updater: function(options) {
			this._valueListeners = [];
			$.js.objectMixin(this, $.events.EventTarget);
			sj.js.extend(this, {
				dur: Infinity,
				from: null,
				to: null,
				by: null,
				begin: 0,
				end: Infinity,
				delay: 0,
				max: null,
				min: null,
				values: null,
				keyTimes: null,
				keySplines: null,
				calcMode: "linear",
				repeatCount: null,
				finish: "freeze",
				multiplier: 1,
				skipReset: false
			}, options);
			if (!this.skipReset) this.reset();
		},
		UpdaterStatus: function(dur, calcMode, finish) {
			this.values = [];
			this.keyTimes = [];
			this.keySplines = [];
			this.dur = dur;
			this.calcMode = calcMode;
			this.finish = finish;
		}
	};
	
	var updaterRemoveActive = function(u) {
		var l = updaterActives.length;
		for (var i = 0; i < l; i++) {
			if (updaterActives[i] == u) {
				updaterActives.splice(i, 1);
				break;
			}
		}
	};
	
	var UpdaterPrototype = function() {
		this._added = false;
		this.addValueListener = function(callback) {
			if (!(callback in this._valueListeners)) this._valueListeners.push(callback);
			return this;
		};
		this.start = function() {
			if (this._added == false) {
				updaterActives.push(this);
				this._added = true;
			}
			this.dispatchEvent({type:"start",target:this});
			return this;
		};
		this.pause = function() {
			if (this._added == true) {
				updaterRemoveActive(this);
				this._added = false;
			}
			this.dispatchEvent({type:"pause",target:this});
			return this;
		};
		this.stop = function() {
			if (this._added == true) {
				updaterRemoveActive(this);
				this._added = false;
			}
			this.dispatchEvent({type:"stop",target:this});
			this.reset();
			return this;
		};
		this.reverse = function() {
			this.multiplier = -this.multiplier;
			this.dispatchEvent({type:"reverse",target:this});
			return this;
		};
		this.setTime = function(time) {
			this.time = time;
			this.dispatchEvent({type:"settime",target:this,time:time});
			return this;
		};
		this.getTime = function() {
			return time;
		};
		this.getValue = function() {
			return this.value;
		};
		this.reset = function() {
			this.time = this.begin;
			this.currentRepeat = 0;
			this.value = this.from;
			var status = new $.updater.UpdaterStatus(this.dur, this.calcMode, this.finish);
			var statusValues = status.values;
			var statusKeyTimes = status.keyTimes;
			
			if (typeof this.values === "string") {
				statusValues = status.values = this.values.split(/;/);
				var l = statusValues.length;
				for (var i = 0; i < l; i++) {
					statusValues[i] = statusValues[i].trim();
				}
			} else {
				if (!this.by && (this.to === null || this.to === undefined)) {
					throw "Invalid Updater Parameters";
				}
				if (this.from === null) {
					throw "Invalid Updater Parameters";
				}
				else statusValues[0] = "" + this.from;
				
				if (this.to !== null && this.to !== undefined) {
					statusValues.push("" + this.to);
				} else {
					var v = parseFloat(statusValues[0]);
					var v1 = parseFloat(this.by);
					if (isNaN(v) || isNaN(v1)) {
						throw "Invalid Updater Parameters";
					}
					var v1u = ("" + this.by).replace("" + v1, "");
					statusValues.push([(v + v1), v1u].join(""));
				}
			}
			if (this.dur !== Infinity && this.calcMode != "paced") {
				if (this.delay >= this.dur) throw "Invalid Updater Paramaters";
				if (typeof this.keyTimes === "string") {
					statusKeyTimes = status.keyTimes = this.keyTimes.split(/;/);
					for (var i = 0, l = statusKeyTimes.length; i < l; i++) {
						statusKeyTimes[i] = parseFloat(statusKeyTimes[i].trim());
						var statusKeyTimesi = statusKeyTimes[i];
						if ((statusKeyTimesi < 0 || statusKeyTimesi > 1) || (i > 0 && statusKeyTimesi <= statusKeyTimes[i - 1])) {
							throw "Invalid Updater Parameters";
						}
					}
					if (statusKeyTimes.length != statusValues.length) {
						throw "Invalid Updater Parameters";
					}
					if (statusKeyTimes[0] != 0) {
						throw "Invalid Updater Parameters";
					}
					if ((this.calcMode == "linear" || this.calcMode == "spline") && statusKeyTimes[statusKeyTimes.length - 1] != 1) {
						throw "Invalid Updater Parameters";
					}
				} else {
					var l = statusValues.length;
					for (var i = 0; i < l; i++) {
						if (l == 1) {
							statusKeyTimes[0] = 0;
						} else {
							statusKeyTimes[i] = i / (l - 1);
						}
					}
				}
			}
			this.status = status;
			this.dispatchEvent({type:"reset",target:this});
			return this;
		};
		this.update = function(time) {
			this.time = time;
			var delay = this.delay;
			if (time < delay) return;
			var status = this.status;
			var dur = status.dur;
			var values = status.values;
			var calcMode = status.calcMode;
			var keyTimes = status.keyTimes;
			var finish = status.finish;
			
			var percent = null;
			
			if (dur === Infinity) {
				var v1 = parseFloat(this.by);
				if (!isNaN(v1)) {
					this.value = Math.ceil(((time - delay) / this.interval) * v1);
				} else {
					this.value = "" + values[0];
				}
			} else {
				percent = (time - delay) / (dur - delay);
				var l = keyTimes.length;
				for (var i = 0; i < l; i++) {
					var keyTimesi = keyTimes[i];
					var valuesi = values[i];
					if  (i + 1 < l) {
						var keyTimesi1 = keyTimes[i + 1];
						var valuesi1 = values[i + 1];
						if (keyTimesi <= percent && keyTimesi1 > percent) {
							var ktp = (percent - keyTimesi) / (keyTimesi1 - keyTimesi);
							var v0 = parseFloat(valuesi);
							var v1 = parseFloat(valuesi1);
							var v0u = valuesi.replace("" + v0, "");
							var v1u = valuesi1.replace("" + v1, "");
							if (isNaN(v0) || isNaN(v1) || (v0u != v1u)) calcMode = "discrete";
							if (calcMode == "discrete") this.value = (ktp >= 1 ? v1u : v0u);
							else if (calcMode == "linear") this.value = [v0 + ((v1 - v0) * ktp), v1u].join("");
							else if (calcMode == "paced") {
								// This makes an even pace between the this.values (all numbers).
							} else if (calcMode == "spline") {
								// beziers...
							}
							break;
						}
					} else {
						if (keyTimesi <= percent) {
							this.value = valuesi;
							break;
						}
					}
				}
			}
			
			for (var i = 0, l = this._valueListeners.length; i < l; i++) {
				this._valueListeners[i].call(this, this.value);
			}
			
			var floatVal = parseFloat(this.value);
			var finishType = null;
			if (
				(percent != null && (percent >= 1 || percent < 0) && (finishType = "percent")) || 
				(this.max != null && floatVal >= this.max && (finishType = "max")) || 
				(this.min != null && floatVal <= this.min && (finishType = "min"))
				) {
				this.dispatchEvent({type:"finish",target:this,finish:finish,finishType:finishType});
				switch (finish) {
					case "reset":
						this.value = this.from;
						this.stop();
						break;
					case "freeze":
						this.pause();
						break;
					case "repeat":
						this.value = this.from;
						this.time = this.begin;
						break;
					case "reverse":
						this.reverse();
						break;
				}
			}
		}
	};
	$.updater.Updater.prototype = new UpdaterPrototype();
	
	$.locale = function(id, r) {
		var s = id;
		if ($.locale.catalog[id]) {
			s = $.locale.catalog[id];
		}
		if (typeof(r) == "object") {
			for (p in r) {
				s = s.replace(["%(", p, ")s"].join(""), r[p]);
			}
		}
		return s;
	};
	$.locale.currentLocale = "en";
	$.locale.catalog = {};
	$.locale.getCatalog = function(url) {
		$.html.addScript(
			[url, "locale/", $.locale.currentLocale, "/LC_MESSAGES/messages.js"].join("")
		);
	};
	var modules = {};
	$.modules = {
		defined: function(name) {
			if (name in modules) return true;
			return false;
		},
		get: function(name) {
			return modules[name];
		},
		define: function(name, exports) {
			if (!$.modules.defined(name)) modules[name] = exports;
		}
	};
	var requireOsdHandle = null;
	var requireOsdCount = 0;
	$.require = function(name) {
		var delay = new $.delay.Delay();
		if ($.modules.defined(name)) delay.resolve({name: name, exports: modules[name]});
		else {
			if ($.ui.osd) {
				if (requireOsdHandle == null) requireOsdHandle = $.ui.osd.add(document.createTextNode(sj.locale("Downloading Components...")));
				requireOsdCount++;
			}
			$.html.addScript([$.env.MODULE_ROOT, [($.require.main ? [$.require.main, "."].join("") : ""), name].join("").replace(/\./g, "/"), ".js"].join(""), function() {
				if (requireOsdHandle != null && --requireOsdCount == 0) {
					$.ui.osd.remove(requireOsdHandle);
					requireOsdHandle = null;
				}
				if ($.modules.defined(name)) delay.resolve({name: name, exports: modules[name]});
				else delay.error(["Failed to load module '", name, "'"].join(""));
			});
		}
		return delay;
	};
	$.requireReturn = function(name) {
		if ($.modules.defined(name)) return modules[name];
		throw "Module does not exist";
	};
	$.requireAll = function() {
		var delay = new $.delay.Delay();
		var args = arguments;
		var l = args.length;
		var mods = {};
		for (var i = 0; i < l; i++) {
			$.require(arguments[i])
			.addEventListener("success", function(data) {
				mods[data.name] = data.exports;
				delay.progress(data.name);
				var counter = 0;
				for (var m in mods) {
					for (var i = 0; i < l; i++) {
						if (m == args[i]) counter++;
					}
				}
				if (counter == l) delay.resolve(mods);
			}).addEventListener("error", function(reason) {
				delay.error(reason);
			});
		}
		return delay;
	};
	$.require.main = "";
	var System = function() {
		var pid = 0;
		var procs = [];
		var programs = {};
		var loading = {};
		var programProcessMap = {};
		
		var killProcess = function() {
			var pid = this.pid;
			if (pid in programProcessMap) {
				delete programProcessMap[pid];
			}
			for (var i = 0, l = procs.length; i < l; i++) {
				if (procs[i] == this) {
					procs.splice(i, 1);
					return;
				}
			}
		};
		
		this.process = {
			Process: function() {
				var program = null;
				var ecb = {};
				var terminating = false;
				
				this.pid = ++pid;
				
				this.terminate = function() {
					if (terminating === true) return;
					terminating = true;
					this.dispatchEvent({type:"TERM"});
					this.dispatchEvent({type:"KILL"});
					program = null;
					ecb = null;
				};
				this.addEventListener = function(name, cb) {
					if (!(name in ecb)) ecb[name] = [];
					var ecbn = ecb[name];
					for (var i = 0, l = ecbn.length; i < l; i++) {
						if (ecbn[i] == cb) return this;
					}
					ecbn.push(cb);
				};
				this.removeEventListener = function(name, cb) {
					if (!(name in ecb)) return;
					var ecbn = ecb[name];
					for (var i = 0, l = ecbn.length; i < l; i++) {
						if (ecbn[i] == cb) {
							ecbn.splice(i, 1);
							if (ecbn.length == 0) delete ecb[name];
							break;
						}
					}
					return this;
				};
				this.dispatchEvent = function(event) {
					if (typeof event !== "object" || !event.type) return false;
					var et = event.type;
					if (!(et in ecb)) return true;
					var ecbet = ecb[et];
					for (var i = 0, l = ecbet.length; i < l; i++) {
						ecbet[i].call(this, event);
					}
					return true;
				};
				
				this.getProgram = function() {
					return program;
				};
				this.startProgram = function(name, options) {
					var t = this;
					$.sys.process.loadProgram(name).addEventListener("success", function(data) {
						program = new data(options);
						programProcessMap[t.pid] = {name: data.about.name, program: program};
						if ($.js.isFunction(program.exec)) {
							if (program.exec(options) === false) t.terminate();
							else $.events.signal(["sj.sys.process.program.", data.about.name, ".start"].join(""), program);
						}
					}).addEventListener("error", function(reason) {
						$.console.error(reason);
					});
					return t;
				};
				
				this.addEventListener("KILL", killProcess);
				
				procs.push(this);
			},
			getAllProcesses: function() {
				return procs.slice();
			},
			getProcess: function(pid) {
				var l = procs.length;
				for (var i = 0; i < l; i++) {
					if (procs[i].pid == parseInt(pid)) return procs[i];
				}
				return null;
			},
			getProgramProcess: function(program) {
				for (var i in programProcessMap) {
					if (programProcessMap[i].program == program) {
						return $.sys.process.getProcess(i);
					}
				}
			},
			getProgramProcesses: function(name) {
				var r = [];
				for (var i in programProcessMap) {
					if (programProcessMap[i].name == name) {
						r.push($.sys.process.getProcess(i));
					}
				}
				return r;
			},
			getUniqueProgram: function(name) {
				for (var i in programProcessMap) {
					if (programProcessMap[i].name == name) return programProcessMap[i].program;
				}
			},
			registerProgram: function(program) {
				if (program && program.about && program.about.name) {
					var name = program.about.name;
					if (!(name in programs)) {
						programs[name] = program;
						if (name in loading) {
							var l = loading[name].length;
							for (var i = 0; i < l; i++) {
								loading[name][i].call(program);
							}
							delete loading[name];
						}
						sj.events.signal("sj.sys.process.program.load", program);
					}
				}
			},
			loadProgram: function(name) {
				var delay = new $.delay.Delay();
				if (name in programs) {
					delay.resolve(programs[name]);
				} else {
					var osd = null;
					if ($.ui.osd) {
						osd = $.ui.osd.add(document.createTextNode(sj.locale("Downloading %(name)s. Please wait...", {name: name})));
					}
					if (!(name in loading)) loading[name] = [];
					loading[name].push(function() {
						if (osd != null) $.ui.osd.remove(osd);
						delay.resolve(this);
					});
					$.html.addScript([$.env.PROGRAM_ROOT, name, "/", name, ".js"].join(""));
				}
				return delay;
			},
			exec: function(name, options) {
				return (new $.sys.process.Process()).startProgram(name, options);
			},
			uniqueExec: function(name, options, cb) {
				if (name in programs) {
					var p = $.sys.process.getProgramProcesses(name);
					var l = p.length;
					if (l == 0) return $.sys.process.exec(name, options);
					if ($.js.isFunction(cb)) {
						for (var i = 0; i < l; i++) {
							cb.call(p[i]);
						}
					}
				} else return $.sys.process.exec(name, options);
			}
		};
	};
	$.sys = new System();
	
	var DelayPrototype = function() {
		/* States:
		 * 	0: Waiting
		 * 	1: Resolved
		 *	2: Error
		 */
		this._state = 0;
		this._result = undefined;
		this._reason = "Unknown";
		this.addEventListener = function(type, cb, pass) {
			switch(type.toLowerCase()) {
				case "success":
					this._scb.push([cb, pass]);
					if (this._state == 1) cb.call(global, this._result, pass);
					break;
				case "error":
					this._ecb.push([cb, pass]);
					if (this._state == 2) cb.call(global, this._reason, pass);
					break;
				case "progress":
					this._pcb.push([cb, pass]);
					break;
				case "finish":
					this._fcb.push([cb, pass]);
					break;
			}
			return this;
		};
		this.removeEventListener = function(type, cb) {
			var m = null;
			switch(type.toLowerCase()) {
				case "success":
					m = this._scb;
					break;
				case "error":
					m = this._ecb;
					break;
				case "progress":
					m = this._pcb;
					break;
				case "finish":
					m = this._fcb;
					break;
			}
			if (m) {
				for (var i = 0, l = m.length; i < l; i++) {
					if (m[i][0] == cb) {
						m.splice(i, 1);
						break;
					}
				}
			}
			return this;
		};
		this.cancel = function() {
			if ($.js.isFunction(this._ccb)) this._ccb();
			this.error("Canceled");
			return this;
		};
		this.resolve = function(value) {
			this._result = value;
			this._state = 1;
			var s = this._scb;
			for (var i = 0, l = s.length; i < l; i++) {
				var si = s[i];
				si[0].call(global, value, si[1], this.data);
			}
			return this.finish();
		};
		this.finish = function() {
			var s = this._fcb;
			for (var i = 0, l = s.length; i < l; i++) {
				var si = s[i];
				si[0].call(global, this, si[1], this.data);
			}
			return this;
		};
		this.error = function(reason) {
			this._result = undefined;
			this._state = 2;
			this._reason = reason;
			var s = this._ecb;
			for (var i = 0, l = s.length; i < l; i++) {
				var si = s[i];
				si[0].call(global, reason, si[1], this.data);
			}
			return this.finish();
		};
		this.progress = function(data) {
			this._result = undefined;
			this._state = 0;
			var s = this._pcb;
			for (var i = 0, l = s.length; i < l; i++) {
				var si = s[i];
				si[0].call(global, data, si[1], this.data);
			}
			return this;
		};
		this.get = function() {
			if (this._state == 1) {
				return this._result;
			} else {
				if (this._state == 2) throw "In Error State";
				else throw "Not Resolved";
			}
		};
		this.isResolved = function() {
			if (this._state == 1) return true;
			return false;
		};
		this.setData = function(key, value) {
			this.data[key] = value;
			return this;
		};
		this.getData = function(key) {
			return this.data[key];
		};
	};
	$.delay = {
		Delay: function(cancelCallback) {
			this._scb = [];
			this._ecb = [];
			this._pcb = [];
			this._fcb = [];
			this._ccb = cancelCallback;
			this.data = {};
		}
	};
	$.delay.Delay.prototype = new DelayPrototype();
	
	$.console = global.console || {
		logBuffer: [],
		log: function() {
			var l = arguments.length;
			for (var i = 0; i < l; i++) {
				$.console.logBuffer.push(arguments[i].toString());
			}
		},
		debugBuffer: [],
		debug: function() {
			var l = arguments.length;
			for (var i = 0; i < l; i++) {
				$.console.debugBuffer.push(arguments[i].toString());
			}
		},
		warnBuffer: [],
		warn: function() {
			var l = arguments.length;
			for (var i = 0; i < l; i++) {
				$.console.warnBuffer.push(arguments[i].toString());
			}
		},
		errorBuffer: [],
		error: function() {
			var l = arguments.length;
			for (var i = 0; i < l; i++) {
				$.console.errorBuffer.push(arguments[i].toString());
			}
		}
	};

	var iecheck = function() {
		if ($.isReady) return;
		try {
			document.documentElement.doScroll("left");
		} catch (error) {
			setTimeout(iecheck, 1);
			return;
		}
		$.init();
	};

	if ($.browser.engine.name == "Trident") {
		document.attachEvent("onreadystatechange", $.init);
		global.addEventListener("load", $.init, false);
		var toplevel = false;
		try {
			toplevel = window.frameElement == null;
		} catch(e) {}

		if (document.documentElement.doScroll && toplevel) {
			iecheck();
		}
	} else {
		document.addEventListener("DOMContentLoaded", $.init, false);
		global.addEventListener("load", $.init, false);
	}
})();

(function(){
	var $ = sj;
	if (!$.ui) $.ui = {};
	var k = {
		IndividualList: function(options) {
			options = $.js.extend({}, {
				timeout: null,
				parent: document.body,
				container: null,
				itemContainer: null,
				showAnimation: null,
				hideAnimation: null,
				addAnimation: null,
				removeAnimation: null
			}, options);
			var t = this;
			t.style = options.style;
			t.timeout = options.timeout;
			t.container = options.container;
			t.itemContainer = options.itemContainer || $.dom.create("div");
			t.parent = options.parent;
			t.showAnimation = options.showAnimation || null;
			t.hideAnimation = options.hideAnimation || null;
			if (t.hideAnimation) t.hideAnimation.addFinishListener(function() {
				t.container.parentNode.removeChild(t.container);
			});
			t.addAnimation = options.addAnimation || null;
			t.removeAnimation = options.removeAnimation || null;
		}
	};
	var IndividualListPrototype = function() {
		this.add = function(content, options) {
			options = $.js.extend({timeout: this.timeout}, options);
			var t = this;
			var style = t.style;
			var container = t.container;
			var parent = t.parent;
			var itemContainer = t.itemContainer;
			if (!container || !parent) return;
			
			var first = false;
			if (!container.parentNode) {
				first = true;
				$.js.extend(container.style, style);
				$.css.applyBorderRadius(container, style.borderRadius);
			}
			
			var id = t.idCounter++;
			if (typeof content === "string") content = document.createTextNode(content);
			var cc = $(itemContainer.cloneNode(true));
			cc.setUserData("ui.individuallist.contentId", id, null);
			if (cc.style) $.js.extend(cc.style, options.style);
			cc.appendChild(content);
			
			if (first) parent.appendChild(container);
			container.insertBefore(cc, container.childNodes[0] || null);
			if (style.left == "center") $.css.center(container, true, false);
			else container.style.left = style.left;
			if (style.top == "center") $.css.center(container, false, true);
			else container.style.top = style.top;
			if (first) {
				if (t.hideAnimation && t.hideAnimation.started) t.hideAnimation.stop();
				if (t.showAnimation) t.showAnimation.clearElements().addElement(container).start();
			}
			if (t.addAnimation) cc.setUserData("ui.individuallist.addanimation", (new $.html.Animation([cc], t.addAnimation)).start(), null);
			
			if (options.timeout) {
				(new $.timer.Timer({endTime: options.timeout})).addEventListener("endtime", function() {
					t.remove(id);
				}).start();
			}
			
			return id;
		};
		this.remove = function(id) {
			var t = this;
			var container = t.container;
			var style = t.style;
			if (!container) return;
			var c = $.dom.children(container);
			for (var i = 0, l = c.length; i < l; i++) {
				var ci = c[i];
				if (ci.getUserData("ui.individuallist.contentId") == id) {
					if (t.removeAnimation) {
						var aa = ci.getUserData("ui.individuallist.addanimation");
						if (aa && aa.started) aa.stop();
						(new $.html.Animation([ci], t.removeAnimation)).addFinishListener(function() {
							var rem = this.elements[0];
							rem.parentNode.removeChild(rem);
							if ($.dom.children(container).length == 0) {
								if (t.hideAnimation) {
									if (t.hideAnimation.started) t.hideAnimation.stop();
									t.hideAnimation.clearElements().addElement(container).start();
								} else container.parentNode.removeChild(container);
							} else {
								var style = t.style;
								if (style.left == "center") $.css.center(container, true, false);
								else container.style.left = style.left;
								if (style.top == "center") $.css.center(container, false, true);
								else container.style.top = style.top;
							}
						}).start();
					} else {
						ci.parentNode.removeChild(ci);
						if (l == 1) {
							if (t.hideAnimation) {
								if (t.hideAnimation.started) t.hideAnimation.stop();
								this.hideAnimation.clearElements().addElement(container).start();
							} else container.parentNode.removeChild(container);
						} else {
							var style = t.style;
							if (style.left == "center") $.css.center(container, true, false);
							else container.style.left = style.left;
							if (style.top == "center") $.css.center(container, false, true);
							else container.style.top = style.top;
						}
					}
					break;
				}
			}
		};
		this.length = 0;
		this.idCounter = 1;
		this.getContent = function(id) {
			var t = this;
			var container = t.container;
			if (!container) return;
			var c = $.dom.children(container);
			for (var i = 0, l = c.length; i < l; i++) {
				var ci = c[i];
				if (ci.getUserData("ui.individuallist.contentId") == id) return ci;
			}
			return null;
		};
	};
	k.IndividualList.prototype = new IndividualListPrototype();
	
	$.modules.define("ui.individuallist", k);
	sj.ui.individuallist = k;
})();
	
(function($){
	var k = {
		defaultStyle: {
			position: "absolute",
			zIndex: 999999
		},
		Tooltip: function(options) {
			var t = this;
			t.options = options = $.js.extend({
				timeout: null,
				x: 0,
				y: -20,
				baseX: "mouse",
				baseY: "mouse",
				followMouse: true,
				content: null,
				parent: document,
				showAnimation: {
					"opacity": {
						from: 0,
						to: 1,
						dur: 200
					},
					"padding": {
						from: "0px",
						dur: 200
					}
				},
				hideAnimation: {
					"opacity": {
						from: 1,
						to: 0,
						dur: 200
					},
					"padding": {
						to: "0px",
						dur: 200
					}
				}
			}, options);
			t.style = $.js.extend({}, k.defaultStyle, options.style);
			$.js.objectMixin(t, $.events.EventTarget);
			var content = options.content;
			if (content && options.showAnimation) {
				t.showAnimation = new $.html.Animation([content], options.showAnimation);
			}
			if (content && options.hideAnimation) {
				t.hideAnimation = new $.html.Animation([content], options.hideAnimation);
			}
			var showTrigger = options.showTrigger;
			if (showTrigger) {
				for (var i in showTrigger) {
					var sti = showTrigger[i];
					if (typeof i === "string") i = options.parent;
					$(i).addEventListener(sti, function(e){t.show(e)}, false);
				}
			}
			var hideTrigger = options.hideTrigger;
			if (hideTrigger) {
				for (var i in hideTrigger) {
					var hti = hideTrigger[i];
					if (typeof i === "string") i = options.parent;
					$(i).addEventListener(hti, function(e){t.hide(e)}, false);
				}
			}
		}
	};
	var TooltipPrototype = function() {
		this.show = function(e) {
			var t = this;
			var o = t.options;
			var content = o.content;
			if (typeof e === "string") content = document.createTextNode(e);
			if (!content) return t;
			t.dispatchEvent({type: "show", triggerEvent: e, target: t});
			t.position();
			$.js.extend(content.style, t.style);
			if (!content.parentNode || content.parentNode.nodeName == "#document-fragment") document.body.appendChild(content);
			if (!t.showAnimation && o.showAnimation) t.showAnimation = new $.html.Animation([content], o.showAnimation);
			if (o.followMouse) {
				t.followMouseHandler = function() {
					t.position();
				};
				document.addEventListener("mousemove", t.followMouseHandler, false);
			}
			if (t.hideAnimation && t.hideAnimation.started) t.hideAnimation.pause();
			if (t.showAnimation) t.showAnimation.reset().start();
			if (o.timeout) {
				(new $.timer.Timer({
					endTime: o.timeout
				})).addEventListener("endtime", function(e, pass) {
					pass.hide();
				}, t).start();
			}
			return t;
		};
		var removeTooltip = function(t) {
			var content = t.options.content;
			if (!content || !content.parentNode) return;
			content.parentNode.removeChild(content);
		};
		this.hide = function(e) {
			var t = this;
			var o = t.options;
			if (t.followMouseHandler) document.removeEventListener("mousemove", t.followMouseHandler, false);
			var content = o.content;
			if (!content) return t;
			t.dispatchEvent({type: "hide", triggerEvent: e, target: t});
			if (!t.hideAnimation && o.hideAnimation) t.hideAnimation = new $.html.Animation([content], o.hideAnimation);
			if (t.showAnimation && t.showAnimation.started) t.showAnimation.pause();
			if (t.hideAnimation) t.hideAnimation.addFinishListener(removeTooltip, t).reset().start();
			else removeTooltip(t);
			return t;
		};
		this.position = function() {
			var o = this.options;
			var content = o.content;
			if (!content) return this;
			var pd = $.env.POINTER_DATA;
			if (!pd) return this;
			var baseX = o.baseX;
			var baseY = o.baseY;
			if (baseX == "mouse") baseX = pd.clientX;
			else if (baseX == "parent") baseX = $.dom.fullOffset(o.parent, "Left");
			else if (typeof baseX !== "number") baseX = 0;
			if (baseY == "mouse") baseY = pd.clientY;
			else if (baseY == "parent") baseY = $.dom.fullOffset(o.parent, "Top");
			else if (typeof baseY !== "number") baseY = 0;
			
			if (baseX < 0) baseX = 0;
			else if (content.offsetWidth + baseX > sj.html.window.innerWidth() + sj.html.window.pageXOffset()) baseX = sj.html.window.innerWidth() + sj.html.window.pageXOffset() - content.offsetWidth;
			if (baseY < 0) baseY = 0;
			else if (content.offsetHeight + baseY > sj.html.window.innerHeight() + sj.html.window.pageYOffset()) baseY = sj.html.window.innerHeight() + sj.html.window.pageYOffset() - content.offsetHeight;
			
			content.style.left = [baseX + o.x, "px"].join("");
			content.style.top = [baseY + o.y, "px"].join("");
		};
	};
	k.Tooltip.prototype = new TooltipPrototype();
	$.modules.define("ui.tooltip", k);
	$.ui.tooltip = k;
})(sj);
