/* core.js */
/* base */
if (!Function.prototype.apply){
	Function.prototype.apply = function(object, parameters){
		var parameterStrings = [];
		if (!object)	object = window;
		if (!parameters)	parameters = [];   
		for (var i=0; i<parameters.length; i++)
			parameterStrings[i] = "parameters[" + i + "]";   
		object.__apply__ = this;
		var result = eval("object.__apply__(" + parameterStrings.join(", ") + ")");
		object.__apply__ = null;
   
		return result;
	}
}

var Class = {
	create: function(){
		return function(){
			this.initialize.apply(this, arguments);
		}
	},
	
	extend: function(destination, source){
		for (property in source) {
    		destination[property] = source[property];
  		}	
		return destination;
	}
}

var Delegate = {
	create: function (obj, func){
		var f = function()	{
			var target = arguments.callee.target;
			var func = arguments.callee.func;
			return func.apply(target, arguments);
		}
		f.target = obj;
		f.func = func;
		return f;
	}
};

var isFunction = function(a){ return typeof a == "function"; };
var isNull     = function(a){ return typeof a == "object" && !a; };
var isNumber   = function(a){ return typeof a == "number" && isFinite(a);};
var isObject   = function(a){ return (a && typeof a == "object") || isFunction(a);};
var isString   = function(a){ return typeof a == "string";};
var isArray    = function(a){ return isObject(a) && a.constructor == Array; };
var isUndef    = function(a){ return typeof a == "undefined";};
var DoUnchanged= function(a){ return a;}
var DoNothing  = function(){};

var $ = function(){
	var elements = [];
	for (var i = 0; i < arguments.length; i++){
    	var element = arguments[i];
		if (isString(element))
			element = document.getElementById(element);
		
    	if (arguments.length == 1)
			return element;
    	elements.push(element);
  	}
  	return elements;
};

var $E = function(){
	var elements = [];
	for (var i=0; i<arguments.length; i++){
    	var element = arguments[i];
		if (isString(element))
			element = document.getElementsByName(element);
		
		if (arguments.length == 1)
			return element;
    	elements.push(element);
	}
	return elements;
}

var $P = function(parameter, url){
	url = url || window.location.href;
	return URL.getParameter(parameter, url);
};

/* browser */
var Browser = {
	getCookie: function(label){
		return isNull(document.cookie.match(new RegExp("(^"+label+"| "+label+")=([^;]*)"))) ? "" : decodeURIComponent(RegExp.$2);
	},
	
	setCookie: function(label, value, expireTime){
		var cookie = label + "=" + encodeURIComponent(value) +"; domain=xunlei.com; path=/;";
		if (isUndef(expireTime))
			document.cookie = cookie;
		else{
			var expires = new Date();
			expires.setTime(expires.getTime() + expireTime*1000);
			document.cookie = label + "=" + encodeURIComponent(value) +"; domain=xunlei.com; path=/; expires=" + expires.toGMTString() + ";";
		}
	},
	
	clearCookie: function(label){
		Browser.setCookie(label, "");
	}
};

Browser.isFireFox = (window.navigator.appName == "Netscape");
Browser.isOpera = (window.navigator.userAgent.indexOf("opera") != -1);
Browser.isSaf = ((window.navigator.userAgent.indexOf("applewebkit") != -1) || (navigator.vendor == 'Apple Computer, Inc.'));
Browser.isMSIE = ((window.navigator.userAgent.toLowerCase().indexOf("msie") != -1) && (!Browser.isOpera) && (!Browser.isSaf));	/* enumerable */
var $break    = new Object();
var $continue = new Object();

var Enumerable = {
	each: function(iterator){
		var index = 0;
		try {
			this._each(function(value){
				try {
					iterator(value, index++);
				}catch (e){
					if (e != $continue) throw e;
				}
			});
		}catch (e){
			if (e != $break) throw e;
		}
	},
	
	all: function(iterator){
		var result = true;
		this.each(function(value, index){
			result = result && !!(iterator || DoUnchanged)(value, index);
			if (!result)
				throw $break;
		});
		return result;
	},
	
	any: function(iterator){
		var result = true;
		this.each(function(value, index){
			if (result = !!(iterator || DoUnchanged)(value, index)) 
				throw $break;
		});
		return result;
	},
	
	map: function(iterator){
		var results = [];
		this.each(function(value, index){
			results.push(iterator(value, index));
		});
		return results;
	},
	
	find: function(iterator){
		var result;
		this.each(function(value, index){
			if (iterator(value, index)){
				result = value;
				throw $break;
			}
		});
		return result;
	},
	
	select: function(iterator){
		var results = [];
		this.each(function(value, index){
			if (iterator(value, index))
				results.push(value);
    	});
    	return results;
	},
	
	grep: function(pattern, iterator){
		var results = [];
		this.each(function(value, index){
			var stringValue = value.toString();
			if (stringValue.match(pattern))
				results.push((iterator || DoUnchanged)(value, index));
		});
    	return results;
	},
	
	include: function(element){
		var found = false;
		this.each(function(value){
			if (value == element){
				found = true;
				throw $break;
			}
		});
		return found;
	},
	
	pluck: function(property){
		var results = [];
		this.each(function(value, index){
			results.push(value[property]);
		});
		return results;
	},
	
	max: function(iterator){
		var result;
		this.each(function(value, index){
			value = (iterator || DoUnchanged)(value, index);
			if (value >= (result || value))
				result = value;
		});
		return result;
	},
	
	min: function(iterator){
		var result;
		this.each(function(value, index){
			value = (iterator || DoUnchanged)(value, index);
			if (value <= (result || value))
				result = value;
		});
		return result;
	},  
	
	toArray: function(){
		return this.map(DoUnchanged);
	}
}
/* array */
var $A = function(iterable){
	if (!iterable) 
		return [];
	if (iterable.toArray)
    	return iterable.toArray();
	if (isString(iterable) || isUndef(iterable.length))
		return [iterable];
		
	var results = [];
	for (var i=0; i<iterable.length; i++)
		results.push(iterable[i]);
	return results;
}

if (!Array.prototype.push){
	Array.prototype.push = function(){
		var len = this.length; 
		for (var i=0; i<arguments.length; i++) { 
			this[len + i] = arguments[i]; 
		} 
		return this.length; 
	}
}

if (!Array.prototype.pop){
	Array.prototype.pop = function(){
		var returnValue = this[this.length - 1]; 
		this.length--; 
		return returnValue; 
	}
}

if (!Array.prototype.splice){
	Array.prototype.splice = function(start, deleteCount){
		var len = arguments.length - 2; 
		var returnValue = this.slice(start); 
		for (var i = 0; i < len; i++) { 
			this[start + i] = arguments[i + 2]; 
		} 
		for (var i = 0; i < returnValue.length - deleteCount; i++) { 
			this[start + len + i] = returnValue[deleteCount + i]; 
		} 
		this.length = start + len + returnValue.length - deleteCount; 
		returnValue.length = deleteCount; 
		return returnValue; 	
	}
}

Class.extend(Array.prototype, Enumerable);
Class.extend(Array.prototype, {
	_each: function(iterator){
		for (var i=0; i<this.length; i++)
			iterator(this[i]);
	},

	indexOf: function(element){
		var index = -1;
		this.each(Delegate.create(this, function(value, i){
			if (this[i] == element){
				index = i;
				throw $break;
			}
		}));
		return index;
	},
	
	contain: function(element){
		return this.indexOf(element) != -1;
	},
	
	clear: function(){
		this.length = 0;
	},
	
	insert: function(position){
		for (var i=arguments.length-1; i>0; i--)
			this.splice(position, 0, arguments[i]);
	},
	
	remove: function(position, count){
		count = isUndef(count) ? 1 : count;
		this.splice(position, count);
	},
	
	exclude: function(element){
		var position = this.indexOf(element);
		if (position == -1)
			return;
		this.remove(position);
	},
	
	empty: function(){
		return this.length == 0;
	},
	
	first: function(){
		return this[0];
	},
	
	last: function(){
		return this[this.length - 1];
	},
	
	clone: function(){
		return this.slice(0);
	},
	
	shuffle: function(){
		var result = [];
		var source = this.clone();
		var index;
		this.each(function(){
			index = Math.floor(Math.random()*source.length);
			result.push(source[index]);
			source.remove(index);
		});
		return result;
	}	
});

/* string */
Class.extend(String.prototype, {
	trim: function(){
		return this.replace(/(^\s+)|(\s+$)/g, "");	
	},
	
	bytes: function(){
		return this.replace(/[^\x00-\xff]/g, "  ").length;
	},
	
	truncate: function(bytes, tail){
		tail = tail || "";
		var result;
		for (var i=0; i<this.length; i++){
			if ((result=this.substr(0, i)).bytes() >= bytes)
				return result + tail;
		}
		return this.substr(0);
	},
	
	strip: function(){
		var temp = this;
		temp = temp.replace(/&/ig, "&amp;"); 
		temp = temp.replace(/</ig, "&lt;");
		temp = temp.replace(/>/ig, "&gt;");
		temp = temp.replace(/\"/ig, "&quot;");
		temp = temp.replace(/\'/ig, "&#39;");
		temp = temp.replace(/ /ig, "&nbsp;");
		temp = temp.replace(/(\r?\n)|\r/ig, "<br />");
		return temp;
	},
	
	revert: function(){
		var temp = this;
		temp = temp.replace(/&apos;/ig, "\'");
		temp = temp.replace(/&quot;/ig, "\"");
		temp = temp.replace(/&gt;/ig, ">");
		temp = temp.replace(/&lt;/ig, "<");
		temp = temp.replace(/&nbsp;/ig, " ");
		temp = temp.replace(/&amp;/ig, "&");
		temp = temp.replace(/<br.*?>|<\/p><p(\s*|\s+.+?)>/ig, "\n").replace(/<\/?p(\s*|\s+.+?)>/ig,"");
		return temp;
	},
		
	camelize: function(){
		var result = this.replace(new RegExp("(\\W)+", "g"), "");
		return result.charAt(0).toLowerCase() + result.substr(1);
	}
})/* event */
var Events = function(){};
Events.prototype = {
	addEventListener: function(evt, handler){
		if (isUndef(this.__listeners__[evt]))
			this.__listeners__[evt] = [];
		else
			this.removeEventListener(evt, handler);
		this.__listeners__[evt].push(handler);		
	},
	
	removeEventListener: function(evt, handler){
		if (!isUndef(this.__listeners__[evt]))
			this.__listeners__[evt].exclude(handler);
	},
	
	dispatchEvent: function(evtObj){
		if (isString(evtObj))
			evtObj = {type:evtObj, target:this};
		if (!evtObj.type)	return;
		if (isUndef(evtObj.target))
			evtObj.target = this;
		//usage 1 : e.g. function clickHandler(evt){}
		(this[evtObj.type+"Handler"] || DoNothing)(evtObj);
		var queue = this.__listeners__[evtObj.type];
		if (!isUndef(queue)){
			for (var i=0; i<queue.length; i++){
				//usage 2 : e.g. this.addEventListener("click", function(evt){});
				if (isFunction(queue[i]))
					queue[i](evtObj);
				else if (isObject(queue[i])){
					var o = queue[i];
					//usage 3 : e.g. this.addEventListener("click", listener);
					//listener.handleEvent = function(evt){}
					(o.handleEvent || DoNothing)(evtObj);	
					//usage 4 : e.g. this.addEventListener("click", listener);
					//listener.click = function(evt){}
					(o[evtObj.type] || DoNothing)(evtObj);	
				}else{
					//error!	
				}
			}
		}
	}
};

Class.extend(Events, {
	initialize: function(object){
		if (isUndef(this._dispatcher))
			this._dispatcher = new Events();
		object.addEventListener    = this._dispatcher.addEventListener;
		object.removeEventListener = this._dispatcher.removeEventListener;
		object.dispatchEvent       = this._dispatcher.dispatchEvent;
		object.__listeners__ = {};
	},
	
	KEY_BACKSPACE: 8,
	KEY_TAB:       9,
	KEY_RETURN:   13,
	KEY_ESC:      27,
	KEY_LEFT:     37,
	KEY_UP:       38,
	KEY_RIGHT:    39,
	KEY_DOWN:     40,
	KEY_DELETE:   46,
	
	element: function(event){
		return event.target || event.srcElement;
	},
	
	isLeftClick: function(event){
		return (((event.which) && (event.which == 1)) || ((event.button) && (event.button == 1)));
	},
	
	pointerX: function(event){
		return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
	},

	pointerY: function(event){
		return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
	},
	
	stop: function(event){
		if (event.preventDefault){ 
			event.preventDefault(); 
			event.stopPropagation(); 
		}else{
			event.returnValue = false;
			event.cancelBubble = true;
		}
	},
	
	findElement: function(event, tagName){
		var element = Events.element(event);
		while (element.parentNode && (!element.tagName || (element.tagName.toUpperCase() != tagName.toUpperCase())))
			element = element.parentNode;
		return element;
	},
	
	__listeners__: [],
	
	addListener: function(obj, evt, handler, useCapture){
		if (evt == "keypress" && (obj.attachEvent || navigator.appVersion.match(/Konqueror|Safari|KHTML/)))
			evt = "keydown";
		useCapture = useCapture || false;
		Events.__listeners__.push([obj, evt, handler, useCapture]);
		if (obj.addEventListener)
			obj.addEventListener(evt, handler, useCapture);
		else if (obj.attachEvent)
			obj.attachEvent("on"+evt, handler);
	},
	
	removeListener: function(obj, evt, handler, useCapture){
		if (evt == "keypress" && (obj.attachEvent || navigator.appVersion.match(/Konqueror|Safari|KHTML/)))
			evt = "keydown";
		useCapture = useCapture || false;
		if (obj.removeEventListener)
			obj.removeEventListener(evt, handler, useCapture);
		else if (obj.detachEvent)
			obj.detachEvent("on"+evt, handler);
	},
	
	unloadListeners: function(){
		var listeners = Events.__listeners__;
		if (listeners.empty()) return;
		listeners.each(function(l){
			Events.removeListener.apply(this, l);
			l[2] = null;
		});
		listeners.clear();
	}
});

Events.addListener(window, "unload", Events.unloadListeners);

/* dom */
var Element = {
	visible: function(element){
		return $(element).style.display != "none";
	},
	
	toggle: function(){
		for (var i=0; i<arguments.length; i++){
			var element = $(arguments[i]);
			Element[Element.visible(element) ? "hide" : "show"](element);
		}
 	},
	
	hide: function(){
		for (var i=0; i<arguments.length; i++){
			$(arguments[i]).style.display = "none";
		}
	},
	
	show: function(){
		for (var i=0; i<arguments.length; i++){
			$(arguments[i]).style.display = "";
		}
	},
	
	remove: function(element){
		element = $(element);
		element.parentNode.removeChild(element);
	},
	
	classNames: function(element){
		return new Element.ClassNames(element);
	},
	
	hasClassName: function(element, className){
		if (!(element = $(element)))
			return;
		return Element.classNames(element).include(className);
	},
	
	addClassName: function(element, className){
		if (!(element = $(element))) 
			return;
		return Element.classNames(element).add(className);
	},

	removeClassName: function(element, className){
		if (!(element = $(element))) 
			return;
		return Element.classNames(element).remove(className);
	},
	
	replaceClassName: function(element, classNameSrc, classNameDest){
		if (!(element = $(element))) 
			return;
		return Element.classNames(element).replace(classNameSrc, classNameDest);
	},
	
	getStyle: function(element, style){
		return $(element).style[style];
	},
	
	setStyle: function(element, style){
		element = $(element);
		for (name in style) 
			element.style[name] = style[name];
	}
};


Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
	initialize: function(element){
		this.element = $(element);
	},
	
	_each: function(iterator){
		this.element.className.split(/\s+/).select(function(name){
			return name.length > 0;
		})._each(iterator);
	},
	
	set: function(className){
		this.element.className = className;
	},
  
	add: function(classNameToAdd){
		if (this.include(classNameToAdd)) 
			return;
		this.set(this.toArray().concat(classNameToAdd).join(" "));
	},
  
	remove: function(classNameToRemove){
		if (!this.include(classNameToRemove)) 
			return;
		this.set(this.select(function(className){
			return className != classNameToRemove;
		}).join(" "));
	},
	
	replace: function(classNameSrc, classNameDest){
		this.set(this.select(function(className){
			return className != classNameSrc && className != classNameDest;
		}).concat(classNameDest).join(" "));
	},
	
	toString: function(){
		return this.toArray().join(" ");
	}
}

Class.extend(Element.ClassNames.prototype, Enumerable);

if (window.HTMLElement){	
	if (!window.HTMLElement.prototype.insertAdjacentElement){
		window.HTMLElement.prototype.insertAdjacentElement = function(where, element){
			switch (where){
				case "beforeBegin":
					this.parentNode.insertBefore(element, this);
					break;
				case "afterBegin":
					this.insertBefore(element, this.firstChild);
					break;
				case "beforeEnd":
					this.appendChild(element);
					break;
				case "afterEnd":
					if(this.nextSibling)
						this.parentNode.insertBefore(element, this.nextSibling);
					else
						this.parentNode.appendChild(element);
					break;
            }
		}
	}
	
	if (!window.HTMLElement.prototype.insertAdjacentHTML){
		window.HTMLElement.prototype.insertAdjacentHTML = function(where, htmlText){
			var rng = this.ownerDocument.createRange();
			rng.setStartBefore(this);
			this.insertAdjacentElement(where, rng.createContextualFragment(htmlText));
		}
	}
}

var Insertion = {
	_insertContent: function(element, content, where){
		element = $(element);
		if (isString(content)){
			element.insertAdjacentHTML(where, content);
			return;
		}
		if (isObject(content)){
			element.insertAdjacentElement(where, content);
			return;
		}
	},
	
	before: function(element, content){
		Insertion._insertContent(element, content, "beforeBegin");
	},
	
	top: function(element, content){
		Insertion._insertContent(element, content, "afterBegin");
	},
	
	bottom: function(element, content){
		Insertion._insertContent(element, content, "beforeEnd");
	},
	
	after: function(element, content){
		Insertion._insertContent(element, content, "afterEnd");
	}	
};


/* form */
var Field = {
	clear: function(){
		for (var i=0; i<arguments.length; i++)
    		$(arguments[i]).value = "";
	},
	
	focus: function(element){
    	$(element).focus();
  	},
  
  	present: function(){
    	for (var i=0; i<arguments.length; i++)
      		if ($(arguments[i]).value == "") return false;
    	return true;
  	},
  
  	select: function(element){
    	$(element).select();
  	},
   
  	activate: function(element) {
    	element = $(element);
    	element.focus();
    	if (element.select)
      		element.select();
  	}
}

var Form = {	
	serialize: function(form){
		var elements = Form.getElements($(form));
		var query = [];
		var q;
		for (var i = 0; i < elements.length; i++) {
			if (!isUndef(q = Form.Element.serialize(elements[i])))
				query.push(q);
    	}    
    	return query.join('&');
	},

	getElements: function(form){
		form = $(form);
		var elements = [];
		for (var tagName in Form.Element.Serializers){
		  	var tagElements = form.getElementsByTagName(tagName);
		  	for (var j = 0; j < tagElements.length; j++)
				elements.push(tagElements[j]);
		}
		return elements;
	},
	
	getInputs: function(form, typeName, name){
		form = $(form);
		var inputs = form.getElementsByTagName("input");
		if (isUndef(typeName) && isUndef(name))
			return inputs;
			
		var matchingInputs = [];
		for (var i=0; i<inputs.length; i++){
			var input = inputs[i];
			if ((typeName && input.type != typeName) || (name && input.name != name)) 
				continue;
			matchingInputs.push(input);
		}
    	return matchingInputs;		
	},
	
	disable: function(form){
    	var elements = Form.getElements(form);
    	for (var i=0; i<elements.length; i++){
      		var element = elements[i];
      		element.blur();
      		element.disabled = true;
    	}
  	},

  	enable: function(form){
    	var elements = Form.getElements(form);
    	for (var i=0; i<elements.length; i++){
      		var element = elements[i];
	      	element.disabled = false;
    	}
  	},
	
	reset: function(form){
    	$(form).reset();
  	}
};

Form.Element = {
	serialize: function(element){
		element = $(element);
		var method = element.tagName.toLowerCase();
    	var parameter = Form.Element.Serializers[method](element);
		if (!isNull(parameter)){
			var key = encodeURIComponent(parameter[0]);
			if (key.length == 0) 
				return;
			if (!isArray(parameter[1]))
        		parameter[1] = [parameter[1]];
			return parameter[1].map(function(value) {
				return key + '=' + encodeURIComponent(value);
		  	}).join("&");
		}
	},
	
	getValue: function(element){
		element = $(element);
		var method = element.tagName.toLowerCase();
		var parameter = Form.Element.Serializers[method](element);
		if (!isNull(parameter))
			return parameter[1];
	}
}

Form.Element.Serializers = {
	input: function(element){
		switch (element.type.toLowerCase()){
			case "submit":
			case "hidden":
			case "password":
			case "text":
				return Form.Element.Serializers.textarea(element);
			case "checkbox":  
			case "radio":
				return Form.Element.Serializers.inputSelector(element);
		}
		return null;
  	},
	
  	textarea: function(element){
    	return [element.name, element.value];
  	},
	
  	inputSelector: function(element){
    	if (element.checked)
      		return [element.name, element.value];
  	},
	
	select: function(element){
    	return Form.Element.Serializers[element.type == "select-one" ? "selectOne" : "selectMany"](element);
  	},
  
  	selectOne: function(element){
    	var value = "";
		var opt;
		var index = element.selectedIndex;
    	if (index >= 0){
      		opt = element.options[index];
      		value = opt.value;
      		if (!value && !("value" in opt))
        		value = opt.text;
    	}
    	return [element.name, value];
  	},
  
  	selectMany: function(element){
    	var value = [];
    	for (var i=0; i<element.length; i++){
      		var opt = element.options[i];
      		if (opt.selected){
        		var optValue = opt.value;
        		if (!optValue && !('value' in opt))
          			optValue = opt.text;
        		value.push(optValue);
      		}
    	}
    	return [element.name, value];
  	}
}

var $F = Form.Element.getValue;















/* url */
var URL = {
	getParameter: function(parameter, url){
		return isNull(url.match(new RegExp("[?#&]"+parameter+"=(.*?)(?:[#&]|$)", "i"))) ? "" : RegExp.$1;
	},
	
	getSuffix: function(url){
		var dot = url.lastIndexOf(".");
		return dot==-1 ? "" : url.substr(dot+1);
	},
	
	getProtocol: function(url){
		return isNull(url.match(/^(\w+):\/\//)) ? "" : RegExp.$1;
	},
	
	getHost: function(url){
		return isNull(url.match(/:\/\/([a-zA-Z0-9.]+)/)) ? "" : RegExp.$1;
	},
	
	getHostPort : function(url){
		return isNull(url.match(/:\/\/([a-zA-Z0-9.:]+)/)) ? "" : RegExp.$1;
	},
	
	isValid: function(url){
		//if (!isNull())
		return true;
	},
	
	isLocal: function(url){
		return !isNull(url.match(/(^file|^[A-Za-z]):/i));
	}
}
/* xml */
var XML = {};
XML.Parser = {
	parseFromString: function(xmlStr, ignoreWhite){
		if (Browser.isFireFox && (isUndef(ignoreWhite) ? true : ignoreWhite)){
			var reg = /<!\[CDATA\[(.*?)\]\]>/ig;
			var reg2 = /<!\[CDATA\[\.\]\]>/i;
			var ret = $A(xmlStr.match(reg));
			xmlStr = xmlStr.replace(reg, "<![CDATA[.]]>").replace(/>\s+?</g, "><");
			for (var i=0; i<ret.length; i++){
				xmlStr = xmlStr.replace(reg2, ret[i]);
			}			
		}
		
		var xmlDoc = null;
		try{
			if (window.DOMParser){
				xmlDoc = new DOMParser().parseFromString(xmlStr, "text/xml");
				return xmlDoc;
			}else{
				var XMLDOM = ["MSXML4.DOMDocument",
							   "MSXML3.DOMDocument",
							   "MSXML2.DOMDocument",
							   "MSXML.DOMDocument",
							   "Microsoft.XmlDom"];
				var parser = null;
				for (var i=0; i<XMLDOM.length; i++){
					try{
						parser = new ActiveXObject(XMLDOM[i]);
						break;
					}catch(e){}
				}
				if (!parser) throw "init dom parser error!";
				parser.loadXML(xmlStr);
				return parser;
			}
		}catch(e){ 
			//alert(isString(e) ? e : e.message);	
		}
		return null;
	},
	
	parseToObject: function(xmlDoc){
		var isTextNode = function(node){
			return (node)&&(node.nodeType == 3 || node.nodeType == 4);
		};
		var parse = function(element){
			if (isTextNode(element))
				throw "xml format error!";
									
			var obj = {};
			for (var i=0; i<element.attributes.length; i++){
				var attr = element.attributes[i];
				obj[attr.nodeName] = attr.nodeValue;
			}
			
			if (!element.hasChildNodes())
				return obj;
			
			for (var i=0; i<element.childNodes.length; i++){
				var child = element.childNodes[i];
				if (isTextNode(child))
					return child.nodeValue;
								
				var node = obj[child.nodeName];
				var result = parse(child);				
				if (isUndef(node)) obj[child.nodeName] = result;
				else{
					isArray(node) ? obj[child.nodeName].push(result) 
						: (obj[child.nodeName] = [node, result]);
				}				
			}
						
			return obj;
		}
		return parse(xmlDoc.documentElement);
	}
}
/* ajax */
var Ajax = {
	getTransport: function(){
		if (window.XMLHttpRequest)	
			return new XMLHttpRequest();
		var XMLHTTP = ["Msxml2.XMLHTTP.6.0",
					   "Msxml2.XMLHTTP.5.0",
					   "Msxml2.XMLHTTP.4.0",
					   "Msxml2.XMLHTTP.3.0",
					   "Msxml2.XMLHTTP.2.6",
					   "Microsoft.XMLHTTP.1.0",
					   "Microsoft.XMLHTTP.1",
					   "Microsoft.XMLHTTP"];
		for (var i=0; i<XMLHTTP.length; i++){
			try{
				return new ActiveXObject(XMLHTTP[i]);
			}catch (e){}
		}
		return null;
	}
};

Ajax.Response = function(){};
Ajax.Response.prototype = {
	getResponseXML: function(){},
	getResponseText: function(){},
	getResponseObject: function(){},
	getResponseJSON: function(){}
};

Ajax.Request = Class.create();
Ajax.Request.Events = ["Uninitialized", "Loading", "Loaded", "Interactive", "Complete"];
Ajax.Request.prototype = {
	initialize: function(url, options){
		this._url     = url;
		this._options = {};
		Class.extend(this._options, options || {});		
		this._request = this.makeRequest();		
	},
	
	makeRequest: function(){
		if (URL.getHost(this._url) == URL.getHost(window.location.href)
						|| URL.isLocal(window.location.href)){
			return new Ajax.XMLHttpRequest(this._url, this._options);
		}
		
		return new Ajax.IFrameBridgeRequest(this._url, this._options);
	},
	
	cancel: function(){
		this._request.cancelRequest();
	}
}


Ajax.Base = function(){};
Ajax.Base.prototype = {
	makeRequest: function(){},
	cancelRequest: function(){},
	initResponse: function(){},
	dispatchEvents: function(){},
	setOptions: function(options){
		var opt = {
			method:"GET", 	//GET.POST
			async: true, 	//false
			parameters: "", 
			headers: [],
			response: null, //Text.XML.Object.JSON
			responseHeaders: [], 
			bridge: "/web/bridge.htm"
		};
		Class.extend(opt, options || {});
		opt.method = opt.method.toUpperCase();
		return opt;
	},
	
	setListener: function(options){
		Events.initialize(this);
		for (var opt in options){
			if (!isNull(opt.match(new RegExp("^on"))) && isFunction(options[opt])){
				this._response[opt] = this._options[opt];
				this.addEventListener(opt, this._response);
			}
		}
	},
		
	success: function(){
		return isUndef(this._transport.status) ||
				this._transport.status == 0 ||
				(this._transport.status >= 200 && this._transport.status < 300);
	}	
}


Ajax.XMLHttpRequest = Class.create();
Ajax.XMLHttpRequest.prototype = Class.extend(new Ajax.Base(), {
	initialize: function(url, options){
		this._url       = url;
		this._options   = this.setOptions(options);
		this._transport = Ajax.getTransport();
		this._response  = new Ajax.Response();
		this._alreadyResponse = false;
		this.initResponse();
		this.setListener(options);
		this.makeRequest();
	},
		
	setRequestHeaders: function(){
		var headers = this._options.headers;
		if (this._options.method == "POST")
			headers.push({label:"Content-type", value:"application/x-www-form-urlencoded"});
		if (this._transport.overrideMimeType)
			headers.push({label:"Connection", value:"close"});
			
		for (var i=0; i<headers.length; i++){
			this._transport.setRequestHeader(headers[i].label, headers[i].value);	
		}
	},
	
	initResponse: function(){
		this._response.getResponseXML = Delegate.create(this, function(){	
			return !Browser.isFireFox ? this._transport.responseXML : 
					XML.Parser.parseFromString(this._transport.responseText);
		}),
		
		this._response.getResponseText = Delegate.create(this, function(){
			return this._transport.responseText;
		}),
		
		this._response.getResponseObject = Delegate.create(this, function(){
			return XML.Parser.parseToObject(this._response.getResponseXML());
		}),
		
		this._response.getResponseJSON = Delegate.create(this, function(){
			return eval("(" + this._transport.responseText + ")");
		})
	},
	
	makeRequest: function(){
		try{
			if (this._options.method == "GET" && this._options.parameters.length > 0)
				this._url += (this._url.indexOf("?") == -1 ? "?" : "&") + this._options.parameters;
			
			if (this._options.async){
				this._transport.onreadystatechange = Delegate.create(this, this.dispatchEvents);					
			}
			this._transport.open(this._options.method, this._url, this._options.async);
			this.setRequestHeaders();
			this._transport.send(this._options.method == "POST" ? this._options.parameters : null);
		}catch(e){
			alert(isString(e)?e:e.message);
			this.dispatchEvent({type:"onException", exception:e});
		}		
	},
	
	dispatchEvents: function(){
		var evt = Ajax.Request.Events[this._transport.readyState];
		if (evt != "Complete")
			this.dispatchEvent("on"+evt);
		else{
			this._transport.onreadystatechange = DoNothing;
			var allHeaders = this._transport.getAllResponseHeaders();
			this.dispatchEvent({type:"onComplete", status:this._transport.status, headers:allHeaders});
			this._alreadyResponse = true;
			
			var evtObj = {type:"on"+this._transport.status, headers:allHeaders};
			var headers = this._options.responseHeaders;
			for (var i=0; i<headers.length; i++)
				evtObj[headers[i].camelize()] = this._transport.getResponseHeader(headers[i]);
			this.dispatchEvent(evtObj);	
	
			if (!this.success())
				this.dispatchEvent("onFailure");
			else{
				evtObj.type = "onSuccess";
				try{
					evtObj.response = (this._response["getResponse" + this._options.response] || DoNothing)();
					this.dispatchEvent(evtObj);
				}catch(e){
					this.dispatchEvent({type:"onException", exception:e});
				}
			}
			
			this._options   = null;
			this._response  = null;
			this._transport = null;			
		}
	},
	
	cancelRequest: function(){
		if (!this._alreadyResponse){
			this._transport.abort();
			this.dispatchEvent("onCancel");
		}
	}
});


Ajax.IFrameBridgeRequest = Class.create();
Ajax.IFrameBridgeRequest.prototype = Class.extend(new Ajax.Base(), {
	initialize: function(url, options){
		this._url      = url;
		this._options  = this.setOptions(options);
		this._content  = null;
		this._request  = null;
		this._response = new Ajax.Response();
		this._cancel   = false;
		this._bridge   = "bridge_" + URL.getHost(this._url).replace(/\./g, "_");
		this.setListener(options);
		this.checkBridge();		
	},
	
	checkBridge: function(){
		this._transport = $(this._bridge);
		if (!this._transport){
			this.initBridge();
		}else{
			if (this._transport.getAttribute("loaded")){
				this.makeRequest();
			}else{
				var interval = setInterval(Delegate.create(this, function(){
					if (this._transport.getAttribute("loaded")){
						clearInterval(interval);
						this.makeRequest();
					}
				}), 50);
			}
		}
	},
	
	initBridge: function(){
		var iframe = document.createElement("iframe");
		iframe.id = this._bridge;
		iframe.width = iframe.height = 0;	
		iframe.style.visibility = "hidden";
		document.body.appendChild(iframe);
		this._transport = iframe;
		Events.addListener(iframe, Browser.isMSIE ? "readystatechange" : "load", Delegate.create(this, this.onBridgeLoaded));
		//iframe[Browser.isMSIE ? "onreadystatechange" : "onload"] = Delegate.create(this, this.onBridgeLoaded);
		iframe.src = "http://" + URL.getHostPort(this._url) + this._options.bridge;
	},
	
	onBridgeLoaded: function(){
		if (Browser.isMSIE && this._transport.readyState != "complete")		return;
		//this._transport[Browser.isMSIE ? "onreadystatechange" : "onload"] = null;
		this._transport.setAttribute("loaded", "loaded");
		this.makeRequest();
	},
	
	makeRequest: function(){
		this._content = this._transport.contentWindow;
		var options = {events:[], dispatcher:{}};
		Events.initialize(options.dispatcher);
		for (var opt in this._options){
			if (opt.match(new RegExp("^on")) && isFunction(this._options[opt])){
				options.events.push(opt);
				options.dispatcher.addEventListener(opt, this._response);
			}else{
				options[opt] = this._options[opt];
			}
		}
		try{
			if (!this._cancel)
				this._request = this._content.makeRequest(this._url, options);
		}catch(e){}
	},
	
	cancelRequest: function(){
		this._cancel = true;
		if (this._request) this._request.cancelRequest();
	}
});

/*
Ajax.IFrameRequest = Class.create();
Ajax.IFrameRequest.prototype = Class.extend(new Ajax.Base(), {
	initialize: function(url, options){
		this._url       = url;
		this._transport = null;
		this._options   = this.setOptions(options);
		this._response  = new Ajax.Response();
		this.initResponse();
		this.setListener(options);
		this.makeRequest();
	},
	
	initResponse: function(){
		this._response.getResponseText = Delegate.create(this, function(){
			return this._transport.responseText;
		}),
		
		this._response.getResponseJSON = Delegate.create(this, function(){
			return eval("(" + this._transport.responseText + ")");
		})		
	},
	
	makeRequest: function(){
		var iframe = document.createElement("iframe");
		iframe.width = iframe.height = 0;		
		iframe.style.visibility = "hidden";
		document.body.appendChild(iframe);
		this._transport = iframe;
		iframe.onreadystatechange = Delegate.create(this, this.dispatchEvents);
		iframe.src = this._url;
	},
	
	dispatchEvents: function(){
		if (this._transport.readyState == "complete"){	
			this.dispatchEvent("onComplete");
			try{
				this._transport.responseText = this._transport.contentWindow.document.body.innerHTML;
				var evtObj = {type:"onSuccess"};
				evtObj.response = (this._response["getResponse" + this._options.response] || DoNothing)();
				this.dispatchEvent(evtObj);
			}catch(e){
				this.dispatchEvent({type:"onException", exception:e});
			}	
		}
	}
});

Ajax.XDomainScriptRequest = Class.create();
Ajax.XDomainScriptRequest.prototype = Class.extend(new Ajax.Base(), {
	initialize: function(url, options){
		this._url       = url;
		this._transport = null;
		this._options   = this.setOptions(options);
		this._response  = new Ajax.Response();
		this.initResponse();
		this.setListener(options);
		this._script = this.makeRequest();
	},
	
	initResponse: function(){
		this._response.getResponseText = Delegate.create(this, function(){
			return this._transport.responseObject;
		}),
		
		this._response.getResponseJSON = Delegate.create(this, function(){
			return eval("(" + this._transport.responseObject + ")");
		}),
		
		this._response.getResponseObject = Delegate.create(this, function(){
			return this._transport.responseObject;
		})
	},
	
	makeRequest: function(){
		var script = document.createElement("script");
	//	document.getElementsByTagName("head")[0].appendChild(script);
		document.body.appendChild(script);
		this._transport = script;
		script.onreadystatechange = Delegate.create(this, this.dispatchEvents);
		script.type = "text/javascript";
		script.src = this._url;
	},
	
	dispatchEvents: function(){
		if (this._transport.readyState == "loaded" || this._transport.readyState == "complete"){
			this.dispatchEvent("onComplete");
			try{
			//	alert(this._options.variable);
				setTimeout(Delegate.create(this, function(){
					this._transport.responseObject = eval(this._options.variable);
			//		alert(this._options.variable + "   = \n" + this._transport.responseObject);
					var evtObj = {type:"onSuccess"};
					evtObj.response = (this._response["getResponse" + this._options.response] || DoNothing)();
					this.dispatchEvent(evtObj);
				}), 1);				
			}catch(e){
				this.dispatchEvent({type:"onException", exception:e});
			}
		}
	}
});
*/
/* table */
var TABLE = {
	
	getRows : function (tableid) {
		return $(tableid).rows?$(tableid).rows:$(tableid).firstChild.childNodes;
	},

	deleteRow : function (tableid, rownum) {
		$(tableid).deleteRow(rownum);
	}

}
