/**
 +-------------------------------------------------------------------------------------------
 * @project ThinkJS
 * @package src
 * @author Mc@Spring <Heresy.Mc@gmail.com>
 * @version $ID: Think.js Created on 2008-03-28 by Mc@Spring at 22:47:28 $
 * @todo TODO
 * @update Modified on 2008-03-28 by Mc@Spring at 22:47:28
 * @link http://groups.google.com/group/mspring
 * @copyright Copyright (C) 2008-2009 MC@Spring Team. All rights reserved.
 * @declare These are inspired by those found in
 * 	mootools.js <http://mootools.net/>,
 * 	jquery.js <http://jquery.com/>,
 * 	ext.js <http://extjs.com/>,
 * 	yahoo.js <http://developer.yahoo.com/yui/>
 *
 *                                Licensed under The Apache License
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License
 +-------------------------------------------------------------------------------------------
 */
window['undefined'] = window['undefined'];

/**
 * @class ThinkJS
 * ThinkJS core object
 * @singleton
 */
ThinkJS = {version : '0.0.1'};

/**
 * @method apply
 * Copy all the properties of servant to main.
 * If defaults is provide that will also be applied for default values
 * @param {Object} main The receiver of the properties
 * @param {Object} servant The source of the properties
 * @param {Object} defaults The default of the properties
 * @return {Object}
 * @member ThinkJS
 */
ThinkJS.apply = function(main, servant, defaults){
	if(defaults){
		ThinkJS.apply(main, defaults);
	}
	if(!servant){
		servant = main;
		main = this;
	}
    if(main && typeof servant == 'object'){
        for(var ppt in servant){
            main[ppt] = servant[ppt];
        }
    }
    return main;
};

/**
 * @function Void
 * ThinkJS core utilties and functions
 * Initialize and extend ThinkJS object properties
 * @param {Void}
 * @return {Object}
 * @singleton
 */
(function(){
	var ua = navigator.userAgent.toLowerCase();
	var isStrict = (document.compatMode == 'CSS1Compat'),
		isOpera = (ua.indexOf('opera') > -1),
		isSafari = (/webkid|khtml/).test(ua),
		isIE = (!isOpera && ua.indexOf('msie') > -1),
		isIE7 = (!isOpera && ua.indexOf('msie 7') > -1),
		isGecko = (!isSafari && ua.indexOf('gecko') > -1),
		isBorderBox = isIE && !isStrict;
	if(isIE && !isIE7){ // remove IE6 css image flicker
        try{document.execCommand('BackgroundImageCache', false, true);}catch(e){}
    }
	ThinkJS.apply(ThinkJS,
		{
			isReady : false,
			isStrict : isStrict,
			isOpera : isOpera,
			isSafari : isSafari,
			isIE : isIE,
			isIE7 : isIE7,
			isGecko : isGecko,
			isBorderBox : isBorderBox,
			isDebug : true,
			/**
			 * @method is
			 * Returns true if the passed in value/object exists or is 0
			 * Otherwise returns false, useful to accept zeroes.
			 * @param {Mixed} object to inspect
			 * @return {Boolean}
			 * @member ThinkJS
			 */
			is : function(o){
				return !!(o || o === 0);
			},
			/**
			 * @method def
			 * Returns true if the passed in value/object is defined
			 * That means is not null or undefined.
			 * @param {Mixed} object to inspect
			 * @return {Boolean}
			 * @member ThinkJS
			 */
			def : function(o){
				return (o != undefined);
			},
			/**
			 * @method type
			 * Returns the type of object that is passed in.
			 * If the object passed in is null or undefined it return false.
			 * @param {Mixed} object to inspect
			 * @return {String}
				[Example]
					'string' - if the object is a string
					'number' - if the object is a number
					'boolean' - if the object is a boolean
					'function' - if the object is a function
					'object' - if the object is an object
					'array' - if the object is an array
					'regexp' - if the object is a regular expression
					'element' - if the object is a DOM element node
					'textnode' - if the object is a DOM text node
					'collection' - if the object is a native htmlelements collection
					'whitespace' - if the object is a DOM whitespace node
					'class' - if object is a ThinkJS.SimpleObject.
					false - (boolean) if the object is not defined or none of the above.
				[/Example]
			 * @member ThinkJS

			 */
			type : function(o){
				if(!this.def(o)){return false;}
				if(o.HtmlElement){return 'element';}
				var x = typeof o;
				if(x == 'object' && o.nodeName){
					switch(o.nodeType){
						case 1:	return 'element';
						case 3:	return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
					}
				}
				if(x == 'object' || x == 'function'){
					switch(o.constructor){
						case Array: return 'array';
						case RegExp: return 'regexp';
						case this.SimpleObject: return 'class';
					}
					if(typeof o.length == 'number'){
						if(o.item){
							return 'collection';
						}else if(o.callee){
							return 'arguments';
						}
					}
				}
				return x;
			}
		},
		{
			/**
			 * @method time
			 * Return current Unix timestamp
			 * @params {Void}
			 * @return {Integer}
			 * @member ThinkJS
			 */
			time : function(){
				return new Date().getTime();
			},
			/**
			 * @method rand
			 * Returns a random integer number between the two passed in values.
			 * @param {Integer} The min value
			 * @param {Integer} The max value
			 * @return {Integer}
			 * @member ThinkJS
			 */
			rand : function(min, max){
				return Math.floor(Math.random() * (max - min + 1) + min);
			},
			/**
			 * @method random
			 * Returns a seed under the passed in argument
			 * @param {Integer} The base seed
			 * @return {Integer}
			 * @member ThinkJS
			 */
			random : function(i){
				return Math.ceil(((this.time()*9301+49297)%233280)/(233280.0)*i);
			},
			/**
			 * @method pick
			 * Returns the first object defined, if none is selected  it will return false.
			 * @params {Mixed} The list of value
			 * @return {Mixed}
			 * @member ThinkJS
			 */
			pick : function(/*arguments*/){
				for(var i = 0, l = arguments.length; i < l;i++){
					if(this.def(arguments[i])){
						return arguments[i];
					}
				}
				return false;
			},
			/**
			 * @method splat
			 * Returns an array base the argument passed in.
			 * @param {Mixed} object to inspect
			 * @return {Array}
			 * @member ThinkJS
			 */
			splat : function(o){
				var type = this.type(o);
				if (type && type != 'array'){
					o = [o];
				}
				return o;
			},
			/**
			 * @method merge
			 * Merge any number of objects recursively into a new array
			 * Without referencing them or their sub-objects.
			 * @params {Mixed}
			 * @return {Array}
			 * @member ThinkJS
			 */
			merge : function(/*arguments*/){
				var mix=[];
				for (var i=0,l=arguments.length;i<l;i++){
					var args=arguments[i],type=this.type(args);
					if(type=='array'){
						mix=mix.concat(args);
					}else if(type=='object'){
						var j=args.length;
						if(this.def(j)){
							for(var x=0;x<j;x++){mix=this.merge(mix,args[x]);}
						}else{
							for(o in args){mix=this.merge(mix,args[o]);}
						}
					}else if(type=='collection'){
						for(var x=0,j=args.length;x<j;x++){mix=this.merge(mix,args[x]);}
					}else if(this.def(args)){
						mix.push(args);
					}
				}
				return mix;
			},
			/**
			 * @method attempt
			 * Tries to execute a function. Returns false if it fails.
			 * @param {Object} The object bind to
			 * @param {Object} The bind function
			 * @param {Array} The arguments for function
			 * @return {Object}
			 * @member ThinkJS
			 */
			attempt : function(bind, fn, args){
				try {
					return fn.apply((bind || fn), this.splat(args));
				} catch(e){
					return false;
				}
			},
			/**
			 * @method foreach
			 * Iterates an array calling the passed function with each item
			 * Stopping if your function returns false.
			 * If the passed is not an array, your function is called once with it.
			 * @param {Array} The object list to bind
			 * @param {Object} The bind function
			 * @param {Object} The object that bind to
			 * @return {Object}
			 * @member ThinkJS
			 */
			foreach : function(args, fn, bind){
				if(!this.def(args.length) || this.type(args) == 'string'){args = [args];}
				for(var i = 0, l = args.length; i < l; i++){
					if(fn.apply((bind || args[i]), (this.splat(args[i])) === false)){break;}
				}
			},
			/**
			 * @method extendif
			 * Append .extend method to the objects passed in by prototype mode
			 * Its handy if you don't wanna the .extend method of an object to overwrite existing methods.
			 * @params {Object} The javascript objects wanna have .extend method
			 * @return {Object} The object with .extend method
			 * @member ThinkJS
			 */
			extendif : function(/*arguments*/){
				for(var i = 0, l = arguments.length;i < l;i++){
					arguments[i].extend = function(ppts){
						for(var ppt in ppts){
							if(!this.prototype[ppt]){this.prototype[ppt] = ppts[ppt];}
							if(!this[ppt]){
								this[ppt] = (function(){return function(bind){return this.prototype[ppt].apply(bind, Array.prototype.slice.call(arguments, 1));}})(ppt);
							}
						}
					};
				}
			},
			/**
			 * @method SimpleObject
			 * The base class object of the ThinkJS framework
			 * Creates a new class, its initialize method will fire upon when class instantiation.
			 * This will adds the .extend function to the class that can be used to override members on an instance.
			 * Initialize wont fire on instantiation when pass *null*.
			 * @params {Object}
			 * @return {Object}
			 * @member ThinkJS
			 */
			SimpleObject : function(property){
				var cls = function(){
					return (arguments[0] !== null && this.initialize && ThinkJS.type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
				};
				for(var ppt in this){cls[ppt] = this[ppt];}
				cls.prototype = property || {};
				cls.extend = function(ppts){
					for(var ppt in ppts){
						this.prototype[ppt] = ppts[ppt];
						if(!this[ppt]){
							this[ppt] = (function(){return function(bind){return this.prototype[ppt].apply(bind, Array.prototype.slice.call(arguments, 1));}})(ppt);
						}
					}
				};
				cls.constructor = ThinkJS.SimpleObject;
				return cls;
			}
		}
	);
	window.onerror = function(){return !ThinkJS.isDebug;};
	ThinkJS.extendif(Function, String, Array, Number);
})();

/**
 +-------------------------------------------------------------------------------------------
 * @project ThinkJS
 * @package src
 * @author Mc@Spring <Heresy.Mc@gmail.com>
 * @version $ID: Helper.js Created on 2008-03-28 by Mc@Spring at 22:47:28 $
 * @todo TODO
 * @update Modified on 2008-03-28 by Mc@Spring at 22:47:28
 * @link http://groups.google.com/group/mspring
 * @copyright Copyright (C) 2008-2009 MC@Spring Team. All rights reserved.
 * @declare These are inspired by those found in
 * 	mootools.js <http://mootools.net/>,
 * 	jquery.js <http://jquery.com/>,
 * 	ext.js <http://extjs.com/>,
 * 	yahoo.js <http://developer.yahoo.com/yui/>
 *
 *                                Licensed under The Apache License
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License
 +-------------------------------------------------------------------------------------------
 */
Function.extend({
	/**
	 * @method create
	 * Main function to create closures.
	 * @params {Object}
	 * @return {Function}
	 * @member Function
	 */
	create : function(opts){
		var that = this;
		this.options = ThinkJS.apply({
			'bind' : that,
			'event' : false,
			'arguments' : null,
			'delay' : false,
			'periodical' : false,
			'attempt' : false
		},	opts);
		return function(event){
			var args = ThinkJS.pick(that.options.arguments, arguments);
			if(that.options.event){args = ThinkJS.apply([event || window.event], args);}
			var rs = function(){return that.call(ThinkJS.pick(that.options.bind, that), args);};
			if(that.options.delay){return setTimeout(rs, that.options.delay);}
			if(that.options.periodical){return setInterval(rs, that.options.periodical);}
			if(that.options.attempt){return ThinkJS.attempt(rs);}
			return rs();
		};
	},
	/**
	 * @method bind
	 * Create closures with "this" easily.
	 * @params {Array}
	 * @return {Function}
	 * @member Function
	 */
	bind : function(o){
		var that = this;
		return function(){return that.apply(o, Array.prototype.slice.call(arguments, 1));};
	}
});
String.extend({
	/**
	 * @method test
	 * Searches for a match between the string and a regular expression.
	 * @param {Mixed} The string or regular expression you want to match the string with.
	 * @param {String} If first parameter is a string, any parameters you want to pass to the regular expression ('g' has no effect).
	 * @return {Boolean} If a match for the regular expression is found in this string returns true. Otherwise, returns false.
	 * @member String
	 */
	test : function(reg, sym){
		return ((ThinkJS.type(reg) == 'string') ? new RegExp(reg, sym) : reg).test(this);
	},
	/**
	 * @method contain
	 * Check if it is exist
	 * @param {String} The string to search for.
	 * @param {String} The string that separates the values in this string (eg. Element classNames are separated by a ' ').
	 * @return {Boolean} If the string is contained in this string, returns true. Otherwise, returns false.
	 * @member String
	 */
	contain : function(string, s){
		return (s) ? (s + this + s).indexOf(s + string + s) > -1 : this.indexOf(string) > -1;
	},
	/**
	 * @method trim
	 * Trims the leading or trailing or both leading and trailing spaces off a string.
	 * @param {Integer} Which type to trim
	 * @return {String}
	 * @member String
	 */
	trim : function(){
		var reg = /^\s+|\s+$/g;
		switch(arguments[0]){
			case 1:
				reg = /^\s+/g;
			break;
			case -1:
				reg = /\s+$/g;
			break;
			default:
			break;
		}
		return this.replace(reg, '');
	},
	/**
	 * @method clean
	 * trims (<String.trim>) a string AND removes all the double spaces in a string.
	 * @params {Void}
	 * @return {String}
	 * @member String
	 */
	clean : function(){
		return this.replace(/\s{2,}/g, ' ').trim();
	},
	/**
	 * @method stripTags
	 * Remove all HTML tags in a string AND clean (<String.clean>) it
	 * @params {Void}
	 * @return {String}
	 * @member String
	 */
	stripTags : function(){
		return this.replace(/<\/?[^>]+>/gi, '').clean();
	},
	/**
	 * @method capitalize
	 * Converts the first letter in each word of a string to Uppercase.
	 * @params {Void}
	 * @return {String}
	 * @member String
	 */
	capitalize : function(){
		return this.replace(/\b[a-z]/g,function(match){
			return match.toUpperCase();
		});
	},
	/**
	 * @method camelize
	 * Converts a hiphenated string to a camelcase string.
	 * @params {Void}
	 * @return {String}
	 * @member String
	 */
	camelize : function(){
		return this.replace(/-\D/g, function(match){
			return match.charAt(1).toUpperCase();
		});
	},
	/**
	 * @method hyphenate
	 * Converts a camelCased string to a hyphen-ated string.
	 * @params {Void}
	 * @return {String}
	 * @member String
	 */
	hyphenate: function(){
		return this.replace(/\w[A-Z]/g, function(match){
			return (match.charAt(0) + '-' + match.charAt(1).toLowerCase());
		});
	},
	/**
	 * @mehtod escapeRegExp
	 * Filter for RegExp
	 * @params {Void}
	 * @return {String}
	 * @member String
	 */
	escapeRegExp : function(){
		return this.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
	},
	/**
	 * @method toInt
	 * Parses a string to an integer.
	 * @params {Integer} The base to use (defaults to 10).
	 * @return {Integer}
	 * @member String
	 */
	toInt : function(base){
		return parseInt(this, base || 10);
	},
	/**
	 * @method toFloat
	 * Parses a string to an integer.
	 * @params {Void}
	 * @return {Float}
	 * @member String
	 */
	toFloat : function(){
		return parseFloat(this);
	},
	/**
	 * @method template
	 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.
	 * Each token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
	 * Example:
	<code>
		var cls = 'my-class', text = 'Some text';
		var s = "";
		var s = s.template('<div class="{0}">{1}</div>', cls, text);
		// s now contains the string: '<div class="my-class">Some text</div>'
	</code>
	 * @params {String}
	 * @return {String}
	 * @member ThinkJS
	 */
	template : function(/*arguments*/){
		var args = ThinkJS.arrayMerge(arguments);
		return this.replace(/\{(\d+)\}/g, function(k, v){
			return args[v];
		});
	},
	/**
	 * @method rgbToHex
	 * Converts an RGB value to hexidecimal. The string must be in the format of "rgb(255,255,255)" or "rgba(255,255,255,1)";
	 * @params {String}
	 * @return {String}
	 * @member String
	 */
	rgbToHex: function(array){
		var rgb = this.match(new RegExp('([\\d]{1,3})', 'g'));
		if (rgb[3] == 0) return 'transparent';
		var hex = [];
		for (var i = 0; i < 3; i++){
			var bit = (rgb[i]-0).toString(16);
			hex.push(bit.length == 1 ? '0'+bit : bit);
		}
		var hexText = '#'+hex.join('');
		if (array) return hex;
		else return hexText;
	},
	/**
	 * @method hexToRgb
	 * Converts a hexidecimal color value to RGB. Input string must be the hex color value (with or without the hash). Also accepts triplets ('333');
	 * @params {String}
	 * @return {String}
	 * @member String
	 */
	hexToRgb: function(array){
		var hex = this.match(new RegExp('^[#]{0,1}([\\w]{1,2})([\\w]{1,2})([\\w]{1,2})$'));
		var rgb = [];
		for (var i = 1; i < hex.length; i++){
			if (hex[i].length == 1) hex[i] += hex[i];
			rgb.push(parseInt(hex[i], 16));
		}
		var rgbText = 'rgb('+rgb.join(',')+')';
		if (array) return rgb;
		else return rgbText;
	}	
});
Array.extend({
	/**
	 * @method origin
	 * Creates a copy of an array, optionally from a specific range.
	 * Useful for applying the array prototypes to iterable objects such as a DOM Node collection or the arguments object.
	 * @param {Integer} The starting index.
	 * @param {Integer} The length of the resulting copied array.
	 * @return {Array}
	 * @member Array
	 */
	origin : function(offset, length){
		offset = offset || 0;
		if(offset < 0){
			offset += this.length;
		}
		length = length || this.length - offset;
		length += offset;
		return Array.prototype.slice.call(this, offset, length);
	},
	/**
	 * @method repeat
	 * Padding an array to give length with the template array
	 * @param {Integer} The length of return array.
	 * @param {Array} The template array
	 * @return {Array}
	 * @member Array
	 */
	repeat : function(tpl){
		var rs = [];
		if(ThinkJS.type(tpl) == 'array'){
			var al = tpl.length, tmp = a.slice(0, this.length%al);
			for(var i = 0, l = this.length/al; i < l; i++){
				rs = rs.concat(a);
			}
			rs = rs.concat(tmp);
		}
		return rs;
	},
	/**
	 * @method merge
	 * Merges an array in another array, without duplicates. (case- and type-sensitive)
	 * @params {Array}
	 * @return {Array}
	 * @member Array
	 */
	merge : function(){
		for (var i = 0, al = arguments.length;i < al;i++){
			for(var j = 0, la = arguments[i].length; j < la; j++){
				this.include(arguments[i][j]);
			}
		}
		return this;
	},
	/**
	 * @method contain
	 * Tests an array for the presence of an item.
	 * @param {Object} The item to search for in the array.
	 * @param {Integer} The index of the array at which to begin the search.
	 * @return {Boolean}
	 * @member Array
	 */
	contain : function(item, offset){
		offset = ((offset < 0) ? Math.max(0, l+offset) : offset) || 0;
		var l = this.length;
		for(var i = offset, al = this.length; i < al; i++){
			if(this[i] === item){
				return true;
			}
		}
		return false;
	},
	/**
	 * @method remove
	 * Removes all occurrences of an item from the array.
	 * @param {Object} The item to search for in the array.
	 * @return {Array}
	 * @member Array
	 */
	remove: function(item){
		var i = 0, al = this.length;
		while (i < al){
			if (this[i] === item){
				this.splice(i, 1);
				al--;
			} else {
				i++;
			}
		}
		return this;
	},
	/**
	 * @method each
	 * Calls a function for each element in the array.
	 * @param {Function} The function which should be executed on each item in the array. This function is passed the item and its index in the array.
	 * @param {Object} The object to use as 'this' in the function.
	 [code]
		var arr = ["one", "two", "three"];
		arr.each(
			function(item, index){
				alert(index + " = " + item);
			}
		); 
		// will alerts "0 = one" etc
	 [/code]
	 * @return {Array}
	 * @member Array
	 */
	each: function(fn, bind){
		for (var i = 0, al = this.length; i < al; i++){
			fn.call(bind, this[i], i, this);
		}
	},
	/**
	 * @method map
	 * Creates a new array with the results of calling a provided function on every element in the array.
	 * @param {Function} The function to produce an element of the new Array from an element of the current one.
	 * @param {Object} The object to use as 'this' in the function.
	 [code]
		var timesTwo = [1, 2, 3].map(
			function(item, index){
				return item * 2;
			}
		); 
		//now timesTwo = [2, 4, 6];
	 [/code]
	 * @return {Array}
	 * @member Array
	 */
	map : function(fn, bind){
		var rs = [];
		for(var i = 0, al = this.length;i < al;i++){
			rs[i] = fn.call(bind, this[i], i, this);
		}
		return rs;
	},
	/**
	 * @method filter
	 * filter* calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a true value.
	 * @param {Function} The function to produce an element of the new Array from an element of the current one.
	 * @param {Object} The object to use as 'this' in the function.
	 [code]
		var timesTwo = [1, 2, 3].filter(
			function(item, index){
				return ite >= 2;
			}
		); 
		//now timesTwo = [2, 3];
	 [/code]
	 * @return {Array}
	 * @member Array
	 */
	filter : function(fn, bind){
		var rs = [];
		for(var i = 0, al = this.length;i < al;i++){
			if(fn.call(bind, this[i], i, this)){
				rs.push(this[i]);
			}
		}
		return rs;
	},
	/**
	 * @method include
	 * includes the passed in element in the array, only if its not already present. 
	 * @param {Object} The item that should be added to this array.
	 * @return {Array}
	 * @member Array
	 */
	include: function(item){
		if (!this.contain(item)){
			this.push(item);
		}
		return this;
	}
});
Number.extend({
	/**
	 * @method limit
	 * Returns integer number between the two passed in values.
	 * @params {Number}
	 * @return {Number}
	 * @member Number
	 */
	limit : function(min, max){
		return Math.min(max, Math.max(min, this));
	}
});

/**
 +-------------------------------------------------------------------------------------------
 * @project ThinkJS
 * @package src
 * @author Mc@Spring <Heresy.Mc@gmail.com>
 * @version $ID: Element.js Created on 2008-03-28 by Mc@Spring at 22:47:28 $
 * @todo TODO
 * @update Modified on 2008-03-28 by Mc@Spring at 22:47:28
 * @link http://groups.google.com/group/mspring
 * @copyright Copyright (C) 2008-2009 MC@Spring Team. All rights reserved.
 * @declare These are inspired by those found in
 * 	mootools.js <http://mootools.net/>,
 * 	jquery.js <http://jquery.com/>,
 * 	ext.js <http://extjs.com/>,
 * 	yahoo.js <http://developer.yahoo.com/yui/>
 *
 *                                Licensed under The Apache License
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License
 +-------------------------------------------------------------------------------------------
 */
ThinkJS.Dom = new ThinkJS.SimpleObject({
	initialize : function(args, ol){
		this.elements = [];
		if(ThinkJS.def(ol)){
			this.elements.merge(this._Selector(args, ol));
		}else{
			for(var i = 0; args[i]; i++){
				this.elements.merge(this._Selector(args[i]));
			}
		}
		return this;
	},
	_attributes : {
		'class': 'className', 'for': 'htmlFor', 'colspan': 'colSpan', 
		'rowspan': 'rowSpan',	'accesskey': 'accessKey', 'value': 'value',
		'tabindex': 'tabIndex', 'maxlength': 'maxLength','selected': 'selected',
		'readonly': 'readOnly', 'frameborder': 'frameBorder', 
		'disabled': 'disabled', 'checked': 'checked', 'multiple': 'multiple' 
	},
	_attrIFlag : {'href' : 2, 'src' : 2},
	_walk : function(el, brother, start){
		brother += 'Sibling';
		var el = start ? el[start] : el[brother];
		while(el && ThinkJS.type(el) != 'element'){
			el = el[brother];
		}
		return el;
	},
	_Selector : function(el, ol){
		// #idName, idName
		// .className, tagName.className
		// @tagName
		// [id | tag | class] > [tag | class] > ....
		// tag[attribute[=|!=]value]
		var rs = [];
		if(ThinkJS.type(el) == 'string'){
			var el = el.replace(/\s*?/g, '');
			if(el.contain('>')){
				var that = this;
				this._Selector(el.split('>')[0], ol).each(function(io){
					that._Selector(el.replace(/[^>]*?>/i, ''), io).each(function(oi){rs.push(oi);})
				});
			}else if(el.contain('#')){
				rs.merge(this._idSelector(el.split('#')[1]));
			}else if(el.contain('.')){
				var css = el.split('.');
				rs.merge(this._cssSelector(css[0], css[1], ol));
			}else if(el.contain('@')){
				rs.merge(this._tagSelector(el.split('@')[1], ol));
			}else if(/\[.*?\]/g.test(el)){
				var ppt = [];
				rs.merge(this._pptSelector(el.replace(/\[.*?\]/gi, function($1){ppt.push($1.replace(/\[|\]/g, '')); return '';}), ppt, ol));
			}else{
				rs.merge(this._idSelector(el, ol));
			}
		}else{
			rs.merge([el]);
		}
		return rs;
	},
	_idSelector : function(id){
		return [document.getElementById(id)];
	},
	_tagSelector : function(tag, el){
		return ThinkJS.merge((el || document).getElementsByTagName(tag || '*'));
	},
	_cssSelector : function(tag, css, el){
		var els = [];
		this._tagSelector(tag, el).filter(function(e, i){
			return e.className.contain(css, ' ');
		}).each(function(o){
			if(ThinkJS.type(o) == 'element'){els.push(o);}
		});
		return els;
	},
	_pptSelector : function(tag, ppt, el){
		var els = [], l = ppt.length;
		this._tagSelector(tag, el).each(function(o){
			for(var i = 0; i < l; i++){
				var KV = ppt[i].split(/=|!=/g);
				if(KV.length == 1){
					if(o.getAttribute(KV[0])){els.push(o);}
				}else if(KV.length > 1){
					if(ppt[i].contain('!=') && (o.getAttribute(KV[0]) != KV[1])){
						els.push(o);
					}else if(o.getAttribute(KV[0]) == KV[1]){
						els.push(o);
					}
				}
			}
		});
		return els;
	}
 });
ThinkJS.Dom.extend({
	parent : function(){
		var els = [];
		this.elements.each(function(el){
			els.push(el.parentNode);
		});
		this.elements = els;
		return this;
	},
	child : function(){
		var els = [];
		this.elements.each(function(el){
			els.merge(ThinkJS.merge(el.childNodes).filter(function(node){return node.nodeType == 1;}));
		});
		this.elements = els;
		return this;
	},
	previous : function(){
		var that = this, els = [];
		this.elements.each(function(el){
			els.push(that._walk(el, 'previous'));
		});
		this.elements = els;
		return this;
	},
	next : function(){
		var that = this, els = [];
		this.elements.each(function(el){
			els.push(that._walk(el, 'next'));
		});
		this.elements = els;
		return this;
	},
	first : function(){
		var that = this, els = [];
		this.elements.each(function(el){
			els.push(that._walk(el, 'next', 'firstChild'));
		});
		this.elements = els;
		return this;
	},
	last : function(){
		var that = this, els = [];
		this.elements.each(function(el){
			els.push(that._walk(el, 'previous', 'lastChild'));
		});
		this.elements = els;
		return this;
	},
	odd : function(){
		this.elements = this.elements.filter(function(e, i){return (i+1)%2;});
		return this;
	},
	even : function(){
		this.elements = this.elements.filter(function(e, i){return i%2;});
		return this;
	},
	replace : function(nel){
		var nel = this._Selector(nel)[0];
		this.elements.each(function(el){el.parentNode.replaceChild(nel, el);});
		return this;
	},
	remove : function(){
		this.elements.each(function(el){el.parentNode.removeChild(el);});
		return this;
	},
	empty : function(){
		this.elements.each(function(el){
			ThinkJS.merge(el.childNodes).each(function(el){el.parentNode.removeChild(el);});
		});
		return this;
	},
	setOpacity : function(opt){
		this.elements.each(function(el){
			if(opt == 0){
				if(el.style.visibility != 'hidden'){el.style.visibility = 'hidden';}
			}else{
				if(el.style.visibility != 'visible'){el.style.visibility = 'visible';}
			}
			if(!el.currentStyle || el.currentStyle.hasLayout){el.style.zoom = 1;}
			if(ThinkJS.isIE){el.style.filter = (opt == 1) ? '' : 'alpha(opacity='+opt*100+')';}
			el.style.opacity = opt;
		});
		return this;
	},
	setStyle : function(key, value){
		var that = this;
		this.elements.each(function(el){
			switch(key){
				case 'opacity':
					return that.setOpacity(value.toFloat());
					break;
				case 'float':
					key = ThinkJS.isIE ? 'styleFloat' : 'cssFloat';
					break;
			}
			key = key.camelize();
			switch(ThinkJS.type(value)){
				case 'number':
					if(!['zIndex', 'zoom'].contain(key)){value += 'px';}
					break;
				case 'array':
					value = 'rgb('+value.join(',')+')';
					break;
			}
			el.style[key] = value;
		});
		return this;
	},
	setCSS : function(co){
		var that = this;
		if(ThinkJS.type(co) == 'object'){
			this.elements.each(function(el){
				for(key in co){that.setStyle(key, co[key]);}
			});
		}
		return this;
	},
	addClass : function(cn){
		this.elements.each(function(el){
			if(!el.className.contain(cn, ' ')){el.className = (el.className+' '+cn).clean();}
		});
		return this;
	},
	removeClass : function(cn){
		this.elements.each(function(el){
			if(el.className.contain(cn, ' ')){el.className = el.className.replace(new RegExp('(^|\\s)'+cn+'(?:\\s|$)'), '$1').clean();}
		});
		return this;
	},
	toggleClass : function(cn){
		this.elements.each(function(el){
			el.className = (el.className.contain(cn, ' ') ? el.className.replace(new RegExp('(^|\\s)'+cn+'(?:\\s|$)'), '$1') : (el.className+' '+cn)).clean();
		});
		return this;
	},
	switchClass : function(cn, nc){
		this.elements.each(function(el){
			if(el.className.contain(cn, ' ')){
				el.className = (el.className.replace(new RegExp('(^|\\s)'+cn+'(?:\\s|$)'), '$1')+' '+nc).clean();
			}else if(el.className.contain(nc, ' ')){
				el.className = (el.className.replace(new RegExp('(^|\\s)'+nc+'(?:\\s|$)'), '$1')+' '+cn).clean();
			}else{
				el.className = (el.className+' '+cn).clean();
			}
		});
		return this;
	},
	getProperty : function(ppt, n){
		var that = this, n = parseInt(n), rs = [];
		this.elements.each(function(el){
			if(that._attributes[ppt]){
				rs.push(el[that._attributes[ppt]]);
			}else{
				var ig = that._attrIFlag[ppt] || 0;
				 if(!ThinkJS.isIE || ig){
					rs.push(el.getAttribute(ppt, ig));
				}else{
					var node = el.attributes[ppt];
					rs.push(node ? node.nodeValue : null);
				}
			}
		});
		return ThinkJS.is(n) ? rs[n.limit(0, (rs.length - 1))] : rs;
	},
	setProperty : function(ppt, v){
		var that = this;
		this.elements.each(function(el){
			if(that._attributes[ppt]){
				el[that._attributes[ppt]] = v;
			}else{
				el.setAttribute(ppt, v);
			}
		});
		return this;
	},
	removeProperty : function(ppt){
		var that = this;
		this.elements.each(function(el){
			if(that._attributes[ppt]){
				el[that._attributes[ppt]] = '';
			}else{
				el.removeAttribute(ppt);
			}
		});
		return this;
	},
	getValue : function(n){
		var that = this, n = parseInt(n), rs = [];
		this.elements.each(function(el){
			switch(el.tagName.toLowerCase()){
				case 'select':
					ThinkJS.foreach(el.options, function(opt){
						if(opt.selected){rs.push(ThinkJS.pick(opt.value, opt.text));}
					});
				break;
				case 'input':
					if(!(el.checked && ['checkbox', 'radio'].contain(el.type)) && !['hidden', 'text', 'password'].contain(el.type)){break;}
				case 'textarea':
					rs.push(el.value);
				break;
			}
		});
		return ThinkJS.is(n) ? rs[n.limit(0, (rs.length - 1))] : rs;
	},
	getWidth : function(n){
		var n = parseInt(n), rs = [];
		this.elements.each(function(el){
			rs.push(parseInt(el.offsetWidth || el.style.width));
		});
		return ThinkJS.is(n) ? rs[n.limit(0, (rs.length - 1))] : rs;
	},
	getHeight : function(n){
		var n = parseInt(n), rs = [];
		this.elements.each(function(el){
			rs.push(parseInt(el.offsetHeight || el.style.height));
		});
		return ThinkJS.is(n) ? rs[n.limit(0, (rs.length - 1))] : rs;
	},
	getXY : function(n, of){
		var that = this, n = parseInt(n), of = of || [], left = 0, top = 0, rs = [];
		this.elements.each(function(el){
			do{
				left += el.offsetLeft || 0;
				top += el.offsetTop || 0;
				el = el.offsetParent;
			}while(el);
			ThinkJS.merge(of).each(function(e){
				left -= e.scrollLeft || 0;
				top -= e.scrollTop || 0;
			});
			rs.push({'x' : left, 'y' : top});
		});
		return ThinkJS.is(n) ? rs[n.limit(0, (rs.length - 1))] : rs;
	},
	setXY : function(x, y){
		this.elements.each(function(el){
			el.style.position = 'absolute';
			el.style.left = x + 'px';
			el.style.top = y + 'px';
		});
		return this;
	},
	setHTML : function(where, html){
		where = where.toLowerCase();
		this.elements.each(function(el){
			if(el.insertAdjacentHTML){
				switch(where){
					case 'beforbegin':
						el.insertAdjacentHTML('BeforeBegin', html);
					break;
					case 'afterbegin':
						el.insertAdjacentHTML('AfterBegin', html);
					break;
					case 'beforeend':
						el.insertAdjacentHTML('BeforeEnd', html);
					break;
					case 'afterend':
						el.insertAdjacentHTML('AfterEnd', html);
					break;
				}
			}else{
				var range = el.ownerDocument.createRange();
				var frag;
				switch(where){
					case 'beforbegin':
						range.setStartBefore(el);
		                frag = range.createContextualFragment(html);
		                el.parentNode.insertBefore(frag, el);
					break;
					case 'afterbegin':
						if(el.firstChild){
							range.setStartBefore(el.firstChild);
							frag = range.createContextualFragment(html);
							el.insertBefore(frag, el.firstChild);
						}else{
							el.innerHTML = html;
						}
					break;
					case 'beforeend':
						if(el.lastChild){
		                    range.setStartAfter(el.lastChild);
		                    frag = range.createContextualFragment(html);
		                    el.appendChild(frag);
		                }else{
		                    el.innerHTML = html;
		                }
					break;
					case 'afterend':
						range.setStartAfter(el);
		                frag = range.createContextualFragment(html);
		                el.parentNode.insertBefore(frag, el.nextSibling);
					break;
				}
			}
		});
		return this;
	}
 });
 
 ThinkJS.Event = new ThinkJS.SimpleObject({
	initialize : function(e){
		this.event = e;
		this.type = e.type;
		this.altKey = e.altKey;
		this.ctrlKey = e.ctrlKey;
		this.shiftKey = e.shiftKey;
		if(ThinkJS.is(e.button)){
			this.button = (typeof(e.which) !== 'undefined') ? e.button : ((e.button === 4) ? 1 : ((e.button === 2) ? 2 : 0));
		}
		if(e.type === 'keypress'){
			this.charCode = e.charCode || e.keyCode;
		}else if(e.keyCode && (e.keyCode === 46)){
			this.keyCode = 127;
		}else{
			this.keyCode = e.keyCode;
		}
		this.clientX = e.clientX;
		this.clientY = e.clientY;
		this.screenX = e.screenX;
		this.screenY = e.screenY;
		this.target = e.target ? e.target : e.srcElement;
		if(this.target){
			this.offsetX = (e.offsetX || (window.pageXOffset + (e.clientX || 0) - this.target.offsetLeft));
			this.offsetY = (e.offsetY || (window.pageYOffset + (e.clientY || 0) - this.target.offsetTop));
		}
	},
	onReady : function(){
		if(ThinkJS.isReady){return;}
		ThinkJS.isReady = true;
		if(this.Timer){clearInterval(this.Timer);}
		this.callee.each(function(fn){fn();});
		this.callee = null;
	},
	onDomReady : function(fn){
		if(!this.callee){
			var domReady = this.onReady.bind(this);
			if(document.addEventListener){
				document.addEventListener('DOMContentLoaded', domReady, false);
			}
			if(ThinkJS.isIE){
				document.write('<script id=_ie_on_load defer src=javascript:void(0)><\/script>');
				document.getElementById('_ie_on_load').onreadystatechange = function() {if (this.readyState == 'complete'){domReady();}};
			}
			if(ThinkJS.isSafari){
				this.Timer = setInterval(function(){if(['loaded', 'complete'].contain(document.readyState)){domReady();}}, 10);
			}
			if (window.addEventListener) {
				window.addEventListener('load', domReady, false);
			} else {
				if (window.attachEvent) {window.attachEvent('onload', domReady);}
			}
			this.callee = [];
		}
		this.callee.push(fn);
	}
 });
 
 ThinkJS.Dom.extend({
	addHandler : function(type, fn){
//		this.elements.each(function(el){
//			if(!ThinkJS.def(el.__FNS)){el.__FNS = {};}
//			var __FNC = el.__FNS[type];
//			if(!ThinkJS.def(__FNC)){el.__FNS[type] = __FNC = [];}
//			var BH;
//			if(el.addEventListener){
//				BH = function(e){return fn.call(el, new ThinkJS.Event(e));};
//				el.addEventListener(type, BH, false);
//			}else if(el.attachEvent){
//				BH = function(){return fn.call(el, new ThinkJS.Event(window.event));};
//				el.attachEvent(('on' + type), BH);
//			}
//			__FNC[__FNC.length] = {fn : fn, BH : BH};
//		});
//		return this;
	},
	removeHandler : function(type, fn){
//		this.elements.each(function(el){
//			if((ThinkJS.type(el.__FNS) !== 'object') || (el.__FNS == null)){return;}
//			var BH = null, __FNC = el.__FNS[type];
//			for(var i = 0, l = __FNC.length; i < l; i++){
//				if(__FNC[i].fn === fn){BH = __FNC[i].BH;break;}
//			}
//			if(ThinkJS.type(BH) !== 'function'){return;}
//			if(el.removeEventListener){
//				el.removeEventListener(type, BH, false);
//			}else if(el.detachEvent){
//				el.detachEvent(('on' + type), BH);
//			}
//			__FNC.splice(i, 1);
//		});
//		return this;
	},
	on : function(type, fn){
//		return this.addHandler(type, fn);
	},
	touchHandlers : function(o){
//		if(ThinkJS.type(o) == 'object'){
//			this.elements.each(function(el){for(x in o){$(el).addHandler(x, o[x]);}});
//		}
	},
	cleanHandlers : function(o){
//		if(ThinkJS.type(o) == 'object'){
//			this.elements.each(function(el){for(x in o){$(el).removeHandler(x, o[x]);}});
//		}
	}
 });

ThinkJS.Transitions = {
	linear: function(t, b, c, d) { return c*t/d + b; },
	sineInOut: function(t, b, c, d){return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;}
};
ThinkJS.Effect = new ThinkJS.SimpleObject({
	initialize : function(opts){
		this.options = ThinkJS.apply({
			start : function(){},
			stop : function(){},
			transition : ThinkJS.Transitions.sineInOut,
			duration : 500,
			unit : 'px',
			wait : true,
			fps : 50
		}, opts);
	},
	step : function(){
		var time = new Date().getTime();
		if(time < (this.time + this.options.duration)){
			this.cTime = time - this.time;
			this.now = this.compute(this.from, this.to);
		}else{
			setTimeout(this.options.stop.bind(this, this.el), 10);
			this.clear();
			this.now = this.to;
		}
		this.increase();
	},
	custom: function(from, to){
		if (!this.options.wait){this.clear();}
		if (this.timer){return;}
		setTimeout(this.options.start.bind(this, this.el), 10);
		this.from = from;
		this.to = to;
		this.time = new Date().getTime();
		this.timer = setInterval(this.step.bind(this), Math.round(1000/this.options.fps));
		return this;
	},
	clear: function(){
		clearInterval(this.timer);
		this.timer = null;
		return this;
	},
	compute : function(from, to){
		var change = to - from;
		return this.options.transition(this.cTime, from, change, this.options.duration);
	},
	set: function(to){
		this.now = to;
		this.increase();
		return this;
	},
	show: function(){
		return this.set(1);
	},
	hide: function(){
		return this.set(0);
	},
	increase : function(){
		this.setStyle(this.el, this.ppt, this.now);
	},
	setStyle: function(el, ppt, v){
		if (ppt == 'opacity'){
			if (v == 0 && el.style.visibility != 'hidden'){
				el.style.visibility = 'hidden';
			}else if(el.style.visibility != 'visible'){
				el.style.visibility = 'visible';
			}
			if (window.ActiveXObject){el.style.filter = 'alpha(opacity=' + v*100 + ')';}
			el.style.opacity = v;
		}else{
			el.style[ppt] = v+this.options.unit;
		}
	}
});
ThinkJS.FxOpacity = ThinkJS.SimpleObject(new ThinkJS.Effect);
ThinkJS.FxOpacity.extend({
	initialize: function(el, opts){
		this.el = el;
		this.options = ThinkJS.apply(this.options, opts);
		this.now = 1;
	},
	toggle: function(){
		if (this.now > 0){
			return this.custom(1, 0);
		}else{
			return this.custom(0, 1);
		}
	},
	increase: function(){
		this.setStyle(this.el, 'opacity', this.now);
	}
});
ThinkJS.FxWidth = ThinkJS.SimpleObject(new ThinkJS.Effect);
ThinkJS.FxWidth.extend({
	initialize: function(el, opts){
		this.el = el;
		this.options = ThinkJS.apply(this.options, opts);
		this.el.style.overflow = 'hidden';
		this.iniWidth = this.el.offsetWidth;
	},
	toggle: function(){
		if (this.el.offsetWidth > 0){
			return this.custom(this.el.offsetWidth, 0);
		}else{
			return this.custom(0, this.iniWidth);
		}
	},
	show: function(){
		return this.set(this.iniWidth);
	},
	increase: function(){
		this.setStyle(this.el, 'width', this.now);
	}
});
ThinkJS.FxHeight = ThinkJS.SimpleObject(new ThinkJS.Effect);
ThinkJS.FxHeight.extend({
	initialize : function(el, opts){
		this.el = el;
		this.options = ThinkJS.apply(this.options, opts);
		this.el.style.overflow = 'hidden';
	},
	toggle : function(){
		if(this.el.offsetHeight > 0){
			return this.custom(this.el.offsetHeight, 0);
		}else{
			return this.custom(0, this.el.scrollHeight);
		}
	},
	show : function(){
		return this.set(this.el.scrollHeight);
	},
	increase : function(){
		this.setStyle(this.el, 'height', this.now);
	}
});

ThinkJS.Dom.extend({
	FxOpacity : function(fn, opts, n){
		var n = parseInt(n).limit(0, (this.elements.length - 1)), FO = [];
		this.elements.each(function(el){
			if(!ThinkJS.def(el.__FNS)){el.__FNS = {__FXO : {}};}
			if(!ThinkJS.def(el.__FNS.__FXO[fn])){el.__FNS.__FXO[fn] = new ThinkJS.FxOpacity(el, opts);}
			FO.push(el.__FNS.__FXO[fn]);
		});
		if(ThinkJS.is(n) && (ThinkJS.type(FO[n][fn]) == 'function')){
			FO[n][fn]();
		}else{
			FO.each(function(o){if(ThinkJS.type(o[fn]) == 'function'){o[fn]();}});
		}
		return this;
	},
	FxWidth : function(fn, opts, n){
		var n = parseInt(n).limit(0, (this.elements.length - 1)), FO = [];
		this.elements.each(function(el){
			if(!ThinkJS.def(el.__FNS)){el.__FNS = {__FXW : {}};}
			if(!ThinkJS.def(el.__FNS.__FXW[fn])){el.__FNS.__FXW[fn] = new ThinkJS.FxWidth(el, opts);}
			FO.push(el.__FNS.__FXW[fn]);
		});
		if(ThinkJS.is(n) && (ThinkJS.type(FO[n][fn]) == 'function')){
			FO[n][fn]();
		}else{
			FO.each(function(o){if(ThinkJS.type(o[fn]) == 'function'){o[fn]();}});
		}
		return this;
	},
	FxHeight : function(fn, opts, n){
		var n = parseInt(n).limit(0, (this.elements.length - 1)), FO = [];
		this.elements.each(function(el){
			if(!ThinkJS.def(el.__FNS)){el.__FNS = {__FXH : {}};}
			if(!ThinkJS.def(el.__FNS.__FXH[fn])){el.__FNS.__FXH[fn] = new ThinkJS.FxHeight(el, opts);}
			FO.push(el.__FNS.__FXH[fn]);
		});
		if(ThinkJS.is(n) && (ThinkJS.type(FO[n][fn]) == 'function')){
			FO[n][fn]();
		}else{
			FO.each(function(o){if(ThinkJS.type(o[fn]) == 'function'){o[fn]();}});
		}
		return this;
	}
});

ThinkJS.XHR = ThinkJS.SimpleObject({
	initialize : function(){
		this.XHR = (function(){
			var O = null;
			if(window.XMLHttpRequest){
				O = new XMLHttpRequest();
			}else{
				var MS = [
					'MSXML2.XMLHTTP.6.0',
					'MSXML2.XMLHTTP.5.0',
					'MSXML2.XMLHTTP.4.0',
					'MSXML2.XMLHTTP.3.0',
					'MSXML2.XMLHTTP',
					'Microsoft.XMLHTTP'
				];
				for(var i = 0; MS[i]; i++){
					try{O = new ActiveXObject(MS[i]);break;}catch(e){}
				}
			}
			return O;
		})();
		return ThinkJS.def(this.XHR);
	},
	AJAX : function(opts){
		this.url = opts.url + (opts.url.contain('?') ? '&' : '?') + 'mc=' + ThinkJS.random(100000);
		this.data = opts.data || null;
		this.async = opts.async;
		this.method = this.data ? 'POST' : (['GET', 'POST'].contain(opts.method.toUpperCase()) ? opts.method : 'GET');
		this.course = opts.course || function(){};
		this.success = opts.success || function(){};
		this.failure = opts.failure || function(){};
		this.type = opts.type || 'xml';
		this.response = null;
		opts = null;
		if(this.XHR || this.initialize()){
			this.XHR.onreadystatechange = function(){};
			this.XHR.abort();
			try{
				this.XHR.open(this.method, this.url, this.async);
				if(this.method == 'POST'){this.XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');}
				this.XHR.onreadystatechange = this.process.bind(this);
				this.XHR.send(this.data);
				if(!this.async){this.process.bing(this);}
			}catch(E){this.failure(E);}
		}
		return this;
	},
	process : function(){
		if(this.XHR.readyState == 4){
			if(this.validate(this.XHR)){
				this.response = (this.type == 'xml') ? this.XHR.responseXML : this.XHR.responseText;
				this.success(this.response, this.XHR.status);
			}else{
				this.failure();
			}
		}else{
			this.course();
		}
	},
	validate : function(XHR){
		try{
			return (!XHR.status && location.protocol == 'file:') ||
				(XHR.status >= 200 && XHR.status < 300) || XHR.status == 304 || XHR.status == 1223 ||
				(ThinkJS.isSafari && !ThinkJS.def(XHR.status));
		}catch(e){}
		return false;
	},
	get : function(url, data, success, course, failure, type){
		if(ThinkJS.type(data) == 'function'){
			ok = data;
			data = null;
		}
		return this.AJAX({
			url : url,
			data : data,
			async : true,
			method : 'GET',
			success : success,
			course : course,
			failure : failure,
			type : type
		});
	},
	post : function(url, data, success, course, failure, type){
		if(ThinkJS.type(data) == 'function'){
			ok = data;
			data = 'mc=' + ThinkJS.random(100000);
		}
		return this.AJAX({
			url : url,
			data : data,
			async : true,
			method : 'POST',
			success : success,
			course : course,
			failure : failure,
			type : type
		});
	},
	getTXT : function(url, data, success, course, failure){
		return this.get(url, data, success, course, failure, 'text');
	},
	getXML : function(url, data, success, course, failure){
		return this.get(url, data, success, course, failure, 'xml');
	}
});

ThinkJS.Dom.extend({
	update : function(url, where, course, failure, type){
		var that = this, where = (['beforebegin', 'afterbegin', 'beforeend', 'afterend'].contain(where) ? where : null);
		var success = function(data, status){
			if(where){
				that.elements.each(function(el){$(el).setHTML(where, data);});
			}else{
				that.elements.each(function(el){$(el).empty().setHTML('afterbegin', data);});
			}
		};
		(new ThinkJS.XHR).get(url, null, success, course, failure, (type || 'text'));
		return this;
	},
	submit : function(url, success, course, failure, type){
		if(url){
			var QS = [], toQS = function(k, v){return ThinkJS.def(v) ? QS.push(k + '=' + encodeURIComponent(v)) : '';};
			this.elements.filter(function(tag){
				return (tag.tagName === 'FORM');
			}).each(function(el){
				ThinkJS.merge(
					el.getElementsByTagName('input'),
					el.getElementsByTagName('select'),
					el.getElementsByTagName('textarea')
				).each(function(e){
					var eK = e.name, eV = $(e).getValue(0);
					if(ThinkJS.type(eV) == 'array'){eV.each(toQS);}else{toQS(eK, eV);}
				});
			});
			(new ThinkJS.XHR).post(url, QS.join('&'), success, course, failure, (type || 'text'));
		}
		return this;
	},
	unsubmit : function(n){
		var n = parseInt(n), rs = [];
		if(n){
			if(ThinkJS.def(this.elements[n])){
				this.elements[n].setAttribute('onsubmit', 'return false;');
			}
		}else{
			this.elements.each(function(el){
				el.setAttribute('onsubmit', 'return false;');
			});
		}
		return this;
	},
	clear : function(n){
		if(n){
			if(ThinkJS.def(this.elements[n]) && ['input', 'textarea'].contain(el.tagName.toLowerCase())){
				el.value = '';
			}
		}else{
			this.elements.each(function(el){
				if(['input', 'textarea'].contain(el.tagName.toLowerCase())){
					el.value = '';
				}
			});
		}
		return this;
	}
});

ThinkJS.apply(window,	{
	$ : function(/*arguments*/){
		return new ThinkJS.Dom(arguments);
	},
	$$ : function(s, o){
		return new ThinkJS.Dom(s, o);
	},
	onReady : function(fn){
		return (new ThinkJS.Event(null)).onDomReady(fn);
	},
	getWidth : function(){
		var x = 0;
		if(ThinkJS.isSafari){
			x = this.innerWidth;
		}else if(ThinkJS.isOpera){
			x = document.body.clientWidth;
		}else{
			x = ThinkJS.isStrict ? document.documentElement.clientWidth : document.body.clientWidth;
		}
		return x;
	},
	getHeight : function(){
		var y = 0;
		if(ThinkJS.isSafari){
			y = this.innerHeight;
		}else if(ThinkJS.isOpera){
			y = document.body.clientHeight;
		}else{
			y = ThinkJS.isStrict ? document.documentElement.clientHeight : document.body.clientHeight;
		}
		return y;
	},
	getScrollWidth : function(){
		var x = 0;
		if (ThinkJS.isIE){
			x = Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth);
		}else if(ThinkJS.isSafari){
			x = document.body.scrollWidth;
		}else{
			x = document.documentElement.scrollWidth;
		}
		return x;
	},
	getScrollHeight : function(){
		var y = 0;
		if (ThinkJS.isIE){
				y = Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight);
		}else if(ThinkJS.isSafari){
			y = document.body.scrollHeight;
		}else{
			y = document.documentElement.scrollHeight;
		}
		return y;
	},
	getScrollX : function(){
		return this.pageXOffset || document.documentElement.scrollLeft;
	},
	getScrollY : function(){
		return this.pageYOffset || document.documentElement.scrollTop;
	},
	getSize : function(){
		return {
			'size' : {'x' : this.getWidth(), 'y' : this.getHeight()},
			'scrollSize' : {'x' : this.getScrollWidth(), 'y' : this.getScrollHeight()},
			'scroll' : {'x' : this.getScrollX(), 'y' : this.getScrollY()}
		};
	}
});

/*switchpage for right rank*/
var switchpage = function(o, n, p){
	var ol = document.getElementById(o+p);
	var cl = document.getElementById(o+n);
	ol.style.display="none";
	cl.style.display="";
}


var p6 = 1;
function page6(num){
	switchpage("p6_", num, p6);
	p6 = num;
}

//set homepage
function setHomePage(obj){
  if(isIE){
var strHref=window.location.href;obj.style.behavior='url(#default#homepage)';obj.setHomePage('http://gamelist.mmosite.com');
  }else{
  if(window.netscape){
  try {  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  }  
  catch (e)  {  
  alert("Dear user,the copy function fails under firefox browser!\nPlease input 'about:config�� in the browser address\n and press enter and set \n'[signed.applets.codebase_principal_support]' to 'true'.");  
  }}
  var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
  prefs.setCharPref('browser.startup.homepage','http://gamelist.mmosite.com/');
  }
  
}

//add favorite
function   myAddPanel(title,url,desc){   
if((typeof   window.sidebar   ==   'object')   &&   (typeof   window.sidebar.addPanel   ==   'function')){
window.sidebar.addPanel(title,url,desc);   
}else{
window.external.AddFavorite(url,title);   
}   
}

function win_open_bug(){
var toUrl = 'http://report.help.mmosite.com/bug_report.htm?backurl='+escape(top.window.location.href);
window.open(toUrl);
}