String.prototype.test = function(re){return re.test(this);};
String.prototype.trim = function(){return (this.replace(/\s+$/,"").replace(/^\s+/,""));};
Array.prototype.containsValue = function(v){for (var i=0;i<this.length;i++)if(this[i]==v) return true; return false;};

var $ = function(o)
{
	var obj = null;
	if(typeof o != 'string')
		obj = o;
	else if(o)
	{
		obj = document.getElementById(o);
		if (!obj && document.all)
			obj = document.all[o];
	}
	if(!obj) return obj;
	return $extend(obj, {
		selectOption : function(value)
		{
			value=parseInt(value);
			for(var i=0;i<this.options.length;i++)
				if(parseInt(this.options[i].value)==value)					
					this.selectedIndex=i;
			
		},
		addCSSClassName : function(cssName, pos)
		{
		    this.removeCSSClassName(cssName);
		    var list = this.className.split(' ');
		    if(pos == undefined)
		        pos = list.length;
		    list.splice(pos, 0, cssName);
		    this.className = list.join(' ');
		},

		removeCSSClassName : function(cssName)
		{
		    var list = this.className.split(' ');
		    var i = 0;
		    while(i < list.length)
		    {
		        if(list[i] == cssName || list[i] == '')
		            list.splice(i, 1);
		        else
		            i++;
		    }
		    this.className = list.join(' ');
		},
		getCSSClassName : function(i)
		{
			var l = this.className.split(' ');
			return i < l.length ? l[i] : '';
		},
		hasCSSClassName : function(cssName)
		{
		    var list = this.className.split(' ');
		    for(var i = 0; i < list.length; i++)
		        if(list[i] == cssName)
		            return true;
		    return false;
		}
	});
};

function $type(obj)
{
	if(obj == null)
		return "null";
	if(obj.constructor == Array)
		return "array";
	return typeof obj;
}

function $defined(obj){
	return (obj != undefined);
};
function $empty(){};

function $extend(original, extended){
	if(extended != undefined)
		for (var key in (extended || {})) original[key] = extended[key];
	return original;
};

function $chk(obj){return !!(obj || obj === 0);};

function $clearTimer(timer){clearTimeout(timer);clearInterval(timer);};

function $try(){for (var i = 0, l = arguments.length; i < l; i++) try {return arguments[i]();} catch(e){}};

function $unlink(object){
	var unlinked;
	switch ($type(object)){
		case 'object':
			unlinked = {};
			for (var p in object) unlinked[p] = $unlink(object[p]);
		break;
		case 'array':
			unlinked = [];
			for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
		break;
		default: return object;
	}
	return unlinked;
};

function $is_empty(o)
{
	for(var k in o)
		return true;
	return false;
}

function $merge(){
	var mix = {};
	for (var i = 0, l = arguments.length; i < l; i++){
		var object = arguments[i];
		if ( $type(object) != 'object') continue;
		for (var key in object){
			var op = object[key], mp = mix[key];
			mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
		}
	}
	return mix;
};

function $each(obj, fn, bind)
{
	switch($type(obj))
	{
		case 'object':
			for (var key in obj)
				if (obj.hasOwnProperty(key)) fn.call(bind, obj[key], key, obj);
			break;
		case 'array':
			for (var i = 0, l = obj.length; i < l; i++)
				fn.call(bind, obj[i], i, obj);
			break;
	}
}

var Browser = $merge({
	Engine: {name: 'unknown', version: 0},
	Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
	Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},
	Plugins: {},
	Engines: {
		presto: function(){
			return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
		},
		trident: function(){
			return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4);
		},
		webkit: function(){
			return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
		},
		gecko: function(){
			return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18);
		}
	}
}, Browser || {});

Browser.Platform[Browser.Platform.name] = true;
Browser.detect = function(){
	for (var engine in this.Engines){
		var version = this.Engines[engine]();
		if (version){
			this.Engine = {name: engine, version: version};
			this.Engine[engine] = this.Engine[engine + version] = true;
			break;
		}
	}
	return {name: engine, version: version};
};

Browser.detect();

Browser.Request = function(){
	return $try(function(){
		return new XMLHttpRequest();
	}, function(){
		return new ActiveXObject('MSXML2.XMLHTTP');
	});
};

Browser.Features.xhr = !!(Browser.Request());

function addEventHandlerByDelegate(obj, evType, fn)
{
	var evTypeRef = '__' + evType;
	if (!obj[evTypeRef])
	{
		obj[evTypeRef] = [];
		var orgEvent = obj['on'+evType];
		if (orgEvent) obj[evTypeRef][0] = orgEvent;
		obj['on'+evType] = EventHandlerDelegate;
	}
	else
	{
		for (var ref in obj[evTypeRef])
			if (obj[evTypeRef][ref] === fn)
				return;
	}
	obj[evTypeRef][obj[evTypeRef].length] = fn;
}
function addEventHandler(obj, evType, fn, useCapture)
{
	if(!obj) return;
	if (!useCapture) useCapture = false;
	if(navigator.isFirefox && obj == window && (evType == 'scroll' || evType == 'resize'))
	{
		if(evType == 'scroll')
			obj = document;
		if(evType == 'resize')
			obj = document.body;
		addEventHandlerByDelegate(obj, evType, fn);
		return;
	}
	if(evType == 'domready')
		DOMReadyEvent.add(fn); //Event.domReady.add(fn); //addEventHandlerByDelegate(window, evType, fn);
	else if (obj.addEventListener)
		obj.addEventListener(evType, fn, useCapture);
	else if (useCapture)
		alert('This browser does not support event capturing!');
	else if((obj.attachEvent))
		obj.attachEvent("on"+evType, fn);
	else
		addEventHandlerByDelegate(obj, evType, fn);
}

function removeEventHandlerByDelegate(obj, evType, fn)
{
	var evTypeRef = '__' + evType;

	if (obj[evTypeRef])
	{
		for (var ref in obj[evTypeRef])
		{if (obj[evTypeRef][ref] === fn){
			try{delete obj[evTypeRef][ref];}
			catch(e){obj[evTypeRef][ref] = null;}
			return;
			}
		}
	}
}
function removeEventHandler(obj, evType, fn, useCapture)
{
	if(!obj) return;
	if (!useCapture) useCapture = false;
	if (obj.removeEventListener)
		obj.removeEventListener(evType, fn, useCapture);
	else if((obj.detachEvent))
		obj.detachEvent("on"+evType, fn);
	removeEventHandlerByDelegate(obj, evType, fn);
}

function stopEvent(ev)
{
	if(ev.preventDefault)
	{
		ev.stopPropagation();
		ev.preventDefault ();
	}
	return false;
}

function EventHandlerDelegate(e)
{
	e = e || window.event;
	var evTypeRef = '__' + e.type;

	if (this[evTypeRef])
		for (var ref in this[evTypeRef])
			this[evTypeRef][ref].call(this, e);
}
function confirmLink(o, m)
{
	if(confirm(m))
	{
		tg = o.target || '_self';
		w = eval('window.'+tg.substr(1));
		w.location.href = o.rel;
	}
}

//DOM scripting by brothercake -- http://www.brothercake.com/
var DOMReadyEvent = {
	loaded : false,
	add : function(fn)
	{
		if(!this.loaded)
			addEventHandlerByDelegate(window, 'domready', fn);
		else
			fn();
	},
	domReadyWatcher : function()
	{
		this.n = typeof this.n == 'undefined' ? 0 : this.n + 1;
		if( typeof document.getElementsByTagName != 'undefined' 
			&& (document.getElementsByTagName('body')[0] != null || document.body != null)
			/* && document.getElementById('something') != null */  )
		{
			this.loaded = true;
			EventHandlerDelegate.call(window, {type:'domready'});
		}
		else if(this.n < 60)
			setTimeout('DOMReadyEvent.domReadyWatcher()', 250);
	}
};
DOMReadyEvent.domReadyWatcher();
getMouseAbsloutePosition = function(ev)
{
	if(ev.pageX || ev.pageY)
		return {x:ev.pageX, y:ev.pageY};
	return {
		x:ev.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
		y:ev.clientY + document.body.scrollTop + document.documentElement.scrollTop
	};
};


var Tips = {
	onMouseMove : function(tip, ev)
	{
		pos = getMouseAbsloutePosition(ev);
		tip.style.left = pos.x + "px";
		tip.style.top = (pos.y + 24) + "px";
		tip.style.display = "block";
	},
	onMouseLeave : function(tip, ev)
	{
		tip.style.display = "none";
	},
	
	attach : function(objs, parentLevel)
	{
		if(!parentLevel) parentLevel=0;
		for(var i = 0; i < objs.length; i++)
		{
			(function(){
			var obj = $(objs[i]);
			var parent = obj.parentNode;
			for(var j=parentLevel; j; j--)
				parent = parent.parentNode
			addEventHandler(parent, 'mousemove', function(ev){
				Tips.onMouseMove(obj, ev); });
			addEventHandler(parent, 'mouseout', function(ev){
				Tips.onMouseLeave(obj, ev); });
			})();
		}
	}
};

var JSON = {
	map: function(fn, bind){
		var results = [];
		for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
		return results;
	},
	filter: function(fn, bind){
		var results = [];
		for (var i = 0, l = this.length; i < l; i++){
			if (fn.call(bind, this[i], i, this)) results.push(this[i]);
		}
		return results;
	},

	$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},

	$replaceChars: function(chr){
		return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
	},

	encode: function(obj){
		switch ($type(obj)){
			case 'string':
				return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
			case 'array':
				return '[' + String(this.filter.call(this.map.call(obj, JSON.encode), $defined)) + ']';
			case 'object':
				var string = [];
				$each(obj, function(value, key){
					var json = JSON.encode(value);
					if (json) string.push(JSON.encode(key) + ':' + json);
				});
				return '{' + string + '}';
			case 'number': case 'boolean': return String(obj);
			case false: return 'null';
		}
		return null;
	},

	decode: function(string, secure){
		if ($type(string) != 'string' || !string.length) return null;
		if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
		return eval('(' + string + ')');
	}
};

var getInputCheckedValue = function(name, def)
{
	var es = document.getElementsByName(name);
	for(var i=0;i<es.length;i++)if(es[i].checked)return es[i].value;
	return def;
};

var Form = {
	toQueryString : function(frm)
	{
		frm = $(frm) || this; q = [];
		for( var i=0; i < frm.elements.length; i++)
		{
			var elm = frm.elements[i];
			if (!elm.name || elm.disabled) continue;
			if (elm.type && (elm.type == 'radio' || elm.type == 'checkbox') && !elm.checked) continue;
			if(elm.type == 'select-multiple')
			{
				for (var j = 0; j < elm.length; j++)
					if (elm.options[j].selected)
						q.push(elm.name+"="+encodeURIComponent(elm.options[j].value));
			}
			else
				q.push(elm.name+"="+encodeURIComponent(elm.value));
		}
		return q.join('&');
	}
};

var Request = function(options)
{
	var object = {
		xhr : new Browser.Request(),
		options : {method: 'post', url : window.location.toString(), async : true, onComplete : null, onError : $empty },
	
		onStateChange : function()
		{
			
		},
		send : function(data)
		{
			var xhr = this.xhr;
			var options = this.options;
			xhr.open(options.method.toUpperCase(), options.url, options.async);
			if(options.method.toUpperCase() == 'POST')
			{
				xhr.setRequestHeader("Method", "POST " + options.url + " HTTP/1.1");
				xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			}
			xhr.onreadystatechange = function()
			{
				if (xhr.readyState != 4)
					return;				
				if (xhr.status==200)
				{
					if(options.onComplete)
						options.onComplete({text: xhr.responseText, xml: xhr.responseXML});
					else
						eval(xhr.responseText);
				}
				else
					options.onError();
			};
			xhr.send(data);
		}
	}; 
	
	object.options = $merge(object.options, options);
	return object;
};
/*
function input_OnFocus(ev)
{
	obj = $(ev.srcElement || ev.target);
	obj.focused = true;
	input_SetSelected(ev);
}
function input_OnBlur(ev)
{
	obj = $(ev.srcElement || ev.target);
	obj.focused = false;
	input_SetDeselected(ev);
}
function input_SetSelected(ev)
{
	obj = $(ev.srcElement || ev.target);
	s = obj.getCSSClassName(0);
	if(!s)return;
	obj.addCSSClassName(s + "_selected");
}
function input_SetDeselected(ev)
{
	obj = $(ev.srcElement || ev.target);
	if(obj.focused != undefined && obj.focused)
		return;
	s = obj.getCSSClassName(0);
	if(!s)return;
	obj.removeCSSClassName(s + "_selected");	
}
addEventHandler(document, 'domready', function(){
	a = document.getElementsByTagName("input");
	for(var i =0;i<a.length;i++)
	{
		if(a[i].type=='text'||a[i].type=='password')
		{
			addEventHandler(a[i], 'focus', input_OnFocus);
			addEventHandler(a[i], 'blur', input_OnBlur);
			addEventHandler(a[i], 'mousemove', input_SetSelected);
			addEventHandler(a[i], 'mouseout', input_SetDeselected);
		}
	}
});
*/