/*
* @	WST - Web Standards Tools v 1.1
* @ http://wstframework.org
* @ Diego de Andrade Pereira - contact@wstframework.org
* @ Released on 13/10/2008 10:07
* @ See GPL LICENSE.txt for the license usage
*/

(function(){
	/* ------------------------------------------------------------------------------------------------
													BASICS
	------------------------------------------------------------------------------------------------ */
	var wst = window.wst = function()
	{
		var wstFnID = 'wst.constructor';
		
		// wst uid
		this.uid = wst.core.instances.length;
		wst.core.instances[this.uid] = this;
		
		/* ------------------------------------------------------------------------------------------
												PROTOTYPE OBJECTS
		------------------------------------------------------------------------------------------ */
		
		// wst children object
		this.children.constructor = this;
		
		// wst opacity object
		if(this.opacity)
		{
			this.opacity = new this.opacity();
			this.opacity.constructor = this;
		}
		
		// wst rollOver object
		if(this.rollOver)
		{
			this.rollOver = new this.rollOver();
			this.rollOver.constructor = this;
		}
	};
	
	wst.proto = wst.prototype = {};
	
	wst.ok = wst.proto.ok = function(expr)
	{
		var wstFnID = 'wst.ok';
		
		return (expr != null) && (expr != undefined) && (expr !== '') && (expr !== false);
	};
	
	wst.extend = wst.proto.extend = function(target, base)
	{
		var wstFnID = 'wst.extend';
		
		if(wst.ok(target) && wst.ok(base))
		{
			var prop;
			
			if(target instanceof Array && typeof target.length == 'number')
			{
				var i = -1;
				
				while(target[++i])
				{
					for(prop in base)
						target[i][prop] = base[prop];
				}
			}
			else
			{
				for(prop in base)
					target[prop] = base[prop];
			}
			
			return target;
		}
	};
	
	wst.object = {
		create : function(base)
		{
			var wstFnID = 'wst.object.create';
			var object = function(){};
			base = base || false;
			
			if(base)
				wst.extend(object, base);
			
			return object;
		},
		clone : function(base)
		{
			var wstFnID = 'wst.object.clone';
			
			return wst.extend(this.create(), (base || new wst));
		}
	};
	
	/* ------------------------------------------------------------------------------------------------
													EXTENDED
	------------------------------------------------------------------------------------------------ */
	wst.extend(wst, {
		validObject : function(expr)
		{
			var wstFnID = 'wst.validObject';
			expr = expr || this.E[0];
			expr = typeof expr == 'string' ? this.get(expr) : expr;
			return (expr != null && (typeof expr == 'object' || typeof expr == 'function') && ((typeof expr.nodeType != 'undefined' ? expr.nodeType != 8 : false) || expr == window || expr == document));
		},
		error : function()
		{
			var wstFnID = 'wst.error';
			var msg, args = arguments;
			var caller = wst.core._getCaller();
			
			switch(args.length)
			{
				case 1:
					if(typeof args[0] == 'string')
					{
						msg = args[0];
					}
					else
					{
						msg = wst.messages.functions.errorFrom + ': ' + (args[1] || caller || wst.messages.functions.errorFromDefault) + '\n'
							+ wst.messages.functions.errorName + ': ' + args[0].name + '\n'
							+ wst.messages.functions.errorNumber + ': ' + (args[0].number & 0xFFFF) + '\n'
							+ wst.messages.functions.errorDescription + ': ' + args[0].description + '\n'
							+ wst.messages.functions.errorMessage + ': ' + args[0].message;
					}
					break;
				case 2:
					msg = wst.messages.functions.errorFrom + ': ' + (args[1] || caller || wst.messages.functions.errorFromDefault) + '\n'
						+ wst.messages.functions.errorName + ': ' + args[0].name + '\n'
						+ wst.messages.functions.errorType + ': ' + args[0] + '\n'
						+ wst.messages.functions.errorNumber + ': ' + (args[0].number & 0xFFFF) + '\n'
						+ wst.messages.functions.errorDescription + ': ' + args[0].description + '\n'
						+ wst.messages.functions.errorMessage + ': ' + args[0].message;
					break;
				case 3:
					msg = wst.messages.functions.errorTitle + '\n'
						+ wst.messages.functions.errorFrom + ': ' + (caller || wst.messages.functions.errorFromDefault) + '\n'
						+ wst.messages.functions.errorMessage + ': ' + args[0] + '\n'
						+ wst.messages.functions.errorUrl + ': ' + args[1] + '\n'
						+ wst.messages.functions.errorLine + ': ' + (wst.browser.ie ? args[2] - 1 : args[2]);
					break;
			}
			
			if(wst.log.enabled && wst.log.errors.enabled)
				wst.log.add('errors', caller, (typeof args[0].message != 'undefined' ? args[0].message : args[0]));
			
			if(this.alertErrors ? true : wst.core.alertErrors)
				alert(msg);
		}
	});
	
	/*****************
	* @ DOM OBJECT @ *
	*****************/
	var dom = wst.object.create();
	
	var _comparsions = {
		'=' : function(curValue, value, regGen){ return value.indexOf('|') > 0 ? !!regGen.run(curValue, '^(' + value + ')$') : (curValue == value); },
		'!=' : function(curValue, value, regGen){ return value.indexOf('|') > 0 ? !regGen.run(curValue, '^(' + value + ')$') : (curValue != value); },
		'*=' : function(curValue, value, regGen){ return !!regGen.run(curValue, '.*(' + value + ').*'); },
		'~=' : function(curValue, value, regGen){ return !!regGen.run(curValue, '(?:^|\\s)(' + value + ')(?:\\s|$)'); },
		'%=' : function(curValue, value, regGen){ return !regGen.run(curValue, '.*(' + value + ').*'); },
		'^=' : function(curValue, value, regGen){ return !!regGen.run(curValue, '^(' + value + ')'); },
		'$=' : function(curValue, value, regGen){ return !!regGen.run(curValue, '(' + value + ')$'); },
		'|=' : function(curValue, value, regGen){ return !!regGen.run(curValue, '^(' + value + '-)'); }
	};
	
	wst.extend([dom, dom.prototype], {
		getByAttr : function(attr, value, tagToFind, type, self, optTag, not, array)
		{
			var wstFnID = 'wst.dom.getByAttr';
			var nodes = array ? array : [];
			var attrs = wst.translate.HTML.attributes;
			attr = attrs[attr] || attr;
			tagToFind = tagToFind || '*';
			value = value || false;
			type = type || '=';
			self = self || false;
			optTag = optTag || '*';
			var regGen = new wst.Regex();
			var es = self ? (wst.is.array(tagToFind) ? tagToFind : [tagToFind]) : (wst.is.dom(tagToFind) ? tagToFind.getElementsByTagName(optTag) : document.getElementsByTagName(tagToFind));
			var curE, curValue, addCur;
			var i = -1, len = es.length;
			
			while(++i < len)
			{
				curE = es[i];
				curValue = curE[attr];
				
				if(wst.ok(curValue) && wst.binarySearch(curE, nodes, true) == -1)
					addCur = value ? _comparsions[type](curValue, value, regGen) : true;
				else
					addCur = false;
				
				if(not ^ addCur)
					nodes.push(curE);
			}
			
			return nodes;
		},
		prev : function(e, sibs, tag)
		{
			var wstFnID = 'wst.dom.prev';
			var root = this.dom;
			sibs = sibs || [];
			tag = tag || '*';
			
			wst.loop(e, function(){
				if(this.previousSibling)
				{
					var sib = this;
					
					while(sib = sib.previousSibling)
					{
						if((sib.nodeType == 1 || ((!root.getTextNodes ? wst.dom.getTextNodes == true : true) && sib.nodeType == 3))
						&& (wst.binarySearch(sib, sibs, true) == -1)
						&& sib.nodeName.toLowerCase() == (tag == '*' ? sib.nodeName.toLowerCase() : tag))
							sibs.push(sib);
					}
				}
			});
			
			return sibs;
		},
		next : function(e, sibs, tag)
		{
			var wstFnID = 'wst.dom.next';
			var root = this.dom;
			sibs = sibs || [];
			tag = tag || '*';
			
			wst.loop(e, function(){
				if(this.nextSibling)
				{
					var sib = this;
					
					while(sib = sib.nextSibling)
					{
						if((sib.nodeType == 1 || ((!root.getTextNodes ? wst.dom.getTextNodes == true : true) && sib.nodeType == 3))
						&& (wst.binarySearch(sib, sibs, true) == -1)
						&& sib.nodeName.toLowerCase() == (tag == '*' ? sib.nodeName.toLowerCase() : tag))
							sibs.push(sib);
					}
				}
			});
			
			return sibs;
		},
		siblings : function(e, sibs, tag)
		{
			var wstFnID = 'wst.dom.siblings';
			var root = this;
			sibs = sibs || [];
			tag = tag || '*';
			
			wst.loop(e, function(){
				if(typeof this.nextSibling != 'undefined' || typeof this.previousSibling != 'undefined')
				{
					wst.apply(root.dom.prev, [this, sibs, tag], root);
					wst.apply(root.dom.next, [this, sibs, tag], root);
				}
			});
			
			return sibs;
		},
		parent : function(e, parents, tag)
		{
			var wstFnID = 'wst.dom.parent';
			var parent;
			parents = parents || [];
			
			wst.loop(e, function(){
				if((parent = !!this.parentNode ? this.parentNode : this == document ? window : this == window && !!window.parent ? window.parent : null) && (wst.binarySearch(parent, parents, true) === -1))
					parents.push(parent);
			});
			
			return parents;
		},
		children : function(e, children, tag)
		{
			var wstFnID = 'wst.dom.children';
			var root = this;
			children = children || [];
			
			wst.loop(e, function(){
				if(root.dom.hasChildren(this))
				{
					wst.loop(this.childNodes, function(){
						if((this.nodeType == 1 || (this.nodeType == 3 && (!root.dom.getTextNodes ? wst.dom.getTextNodes == true : true)))
							&& (this.nodeName.toLowerCase() == (tag == '*' ? this.nodeName.toLowerCase() : tag)))
							children.push(this);
					});
				}
			});
			
			return children;
		},
		hasChildren : function(expr)
		{
			var wstFnID = 'wst.dom.hasChildren';
			var e = expr[0] || expr || this.E[0];
			
			return e ?
				e.hasChildNodes ?
					e.hasChildNodes()
					: (e.childNodes ? e.childNodes.length > 0 : false)
				: false;
		},
		family : function(type, e, n)
		{
			var wstFnID = 'wst.dom.family';
			var tag, returnObject = wst.core._duplicateWST(this);
			
			if(typeof n == 'string')
			{
				tag = n;
				n = -1;
			}
			else
			{
				tag = '*';
				n = !wst.ok(n) ? -1 : n;
			}
			
			wst.apply(returnObject.dom[type], [returnObject.E, e, tag], returnObject);
			returnObject.total = (returnObject.E = (n == -1 ? e : [e[n]] || [])).length;
			returnObject.expr = tag;
			
			return returnObject;
		},
		selectors : {
			' ' : function(f, tag, attr, not)
			{
				var te, tf = [];
				var af = !wst.is.array(f) ? [f] : f;
				var a, v, sep;
				var root = this.dom;
				var addCur;
				
				if(attr)
				{
					attr = root.getAttrValue(attr);
					a = attr[0];
					v = attr[2];
					sep = attr[1];
					
					wst.loop(af, function(){
						te = root.getByAttr(a, v, this, sep, not, tag, not, tf);
						
						if(tag == '*')
						{
							// 'this' has only textNodes
							if((!root.getTextNodes ? wst.dom.getTextNodes == true : true) && !wst.array.valid(te) && root.hasChildren(this))
							{
								te = this.childNodes;
								
								wst.loop(te, function(){
									if(this.nodeType != 8)
										tf.push(this);
								});
							}
						}
					});
				}
				else
				{
					if(!not)
					{
						wst.loop(af, function(){
							te = this.getElementsByTagName(tag);
							
							if(tag == '*')
							{
								// 'this' has only textNodes
								if((!root.getTextNodes ? wst.dom.getTextNodes == true : true) && !wst.array.valid(te) && root.hasChildren(this))
									te = this.childNodes;
								
								if(wst.binarySearch(this, tf, true) === -1)
								{
									wst.loop(te, function(){
										if(this.nodeType != 8)
											tf.push(this);
									});
								}
							}
							else
							{
								wst.loop(te, function(){
									if(wst.binarySearch(this, tf, true) === -1)
										tf.push(this);
								});
							}
							
						});
					}
					else
					{
						tag = tag.toLowerCase();
						
						wst.loop(af, function(){
							if((this.nodeType != 8) && (this.nodeName.toLowerCase() != (tag == '*' ? this.nodeName.toLowerCase() : tag)))
								tf.push(this);
						});
					}
				}
				
				f = tf;
				
				return f;
			},
			'#' : function(f, tag, id, not)
			{
				var te = document.getElementById(id);
				tag = tag.toLowerCase();
				
				if(wst.is.dom(te) ? te.nodeName.toLowerCase() != (tag == '*' ? te.nodeName.toLowerCase() : tag) : true)
					te = null;
				
				f = (te != null) ^ not ? [te] : [];
				
				return f;
			},
			'.' : function(f, tag, clss, not)
			{
				var tf = [], len;
				var af = !wst.is.array(f) ? [f] : f;
				var root = this.dom;
				
				root.getByAttr('class', clss, af, '=', true, tag, not, tf);
				f = tf;
				
				return f;
			},
			'[' : function(f, tag, attr, not)
			{
				var tf = [], af = !wst.is.array(f) ? [f] : f;
				var a, v, sep;
				var root = this.dom;
				
				attr = root.getAttrValue(attr);
				a = attr[0];
				v = attr[2];
				sep = attr[1];
				
				root.getByAttr(a, v, af, sep, true, tag, not, tf);
				f = tf;
				
				return f;
			},
			'>' : function(f, tag, attr, not)
			{
				var tf = [];
				var af = !wst.is.array(f) ? [f] : f;
				var root = this.dom;
				
				wst.apply(root.children, [af, tf, tag], this);
				
				// filter by attr
				if(attr)
				{
					var a, v, sep;
					attr = root.getAttrValue(attr);
					a = attr[0];
					v = attr[2];
					sep = attr[1];
					tf = root.getByAttr(a, v, tf, sep, true, tag, false);
				}
				
				f = tf;
				
				return f;
			},
			'+' : function(f, tag, attr, not)
			{
				var te = [], tf = [];
				var af = !wst.is.array(f) ? [f] : f;
				var root = this.dom;
				var next;
				tag = tag.toLowerCase();
				
				af.loop(function(){
					if(this.nextSibling)
					{
						next = this;
						
						while(next = next.nextSibling)
						{
							if(next.nodeType == 1)
							{
								if(wst.binarySearch(next, tf, true) === -1 && next.nodeName.toLowerCase() == (tag == '*' ? next.nodeName.toLowerCase() : tag))
								{
									tf.push(next);
									break;
								}
							}
						}
					}
				});
				
				// filter by attr
				if(attr)
				{
					var a, v, sep;
					attr = root.getAttrValue(attr);
					a = attr[0];
					v = attr[2];
					sep = attr[1];
					tf = root.getByAttr(a, v, tf, sep, true, tag, false);
				}
				
				f = tf;
				
				return f;
			},
			'~' : function(f, tag, attr, not)
			{
				var te = [], tf = [];
				var af = !wst.is.array(f) ? [f] : f;
				var root = this.dom;
				
				wst.apply(root.next, [af, tf, tag], this);
				
				// filter by attr
				if(attr)
				{
					var a, v, sep;
					attr = root.getAttrValue(attr);
					a = attr[0];
					v = attr[2];
					sep = attr[1];
					tf = root.getByAttr(a, v, tf, sep, true, tag, false);
				}
				
				f = tf;
				
				return f;
			},
			'-' : function(f, tag, attr, not)
			{
				var te = [], tf = [];
				var af = !wst.is.array(f) ? [f] : f;
				var root = this.dom;
				
				wst.apply(root.prev, [af, tf, tag], this);
				
				// filter by attr
				if(attr)
				{
					var a, v, sep;
					attr = root.getAttrValue(attr);
					a = attr[0];
					v = attr[2];
					sep = attr[1];
					tf = root.getByAttr(a, v, tf, sep, true, tag, false);
				}
				
				f = tf;
				
				return f;
			},
			':' : function(f, pseudoAttr, value, not)
			{
				var af = !wst.is.array(f) ? [f] : f;
				var tf;
				var root = this;
				f = [];
				
				if(af.length > 0)
				{
					switch(pseudoAttr)
					{
						case 'first':			// additional: get the first element of the current selection
							f = not ? af.shift() : [af[0]];
							break;
						case 'last':			// additional: get the last element of the current selection
							f = not ? af.pop() : af.slice(-1);
							break;
						case 'first-child':		// CSS 2 standard: get all elements of the current selection that are first children
							var children, addCur;
							
							af.loop(function(){
								children = wst.apply(root.dom.children, [this.parentNode, null, '*', not], root);
								
								addCur = this == children[0];
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'last-child':		// additional: get all elemnts of the current selection that are last children
							var children, addCur;
							
							af.loop(function(){
								children = wst.apply(root.dom.children, [this.parentNode, null, '*', not], root);
								
								addCur = this == children.slice(-1)[0];
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'only-child':		// CSS 3: get elemnt if it is the only child of its parent
							var children, addCur;
							
							af.loop(function(){
								children = wst.apply(root.dom.children, [this.parentNode, null, '*', not], root);
								
								addCur = (children.length == 1) && (this == children[0]);
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'empty':			// CSS 3: get element if it has not child
							var addCur;
							
							af.loop(function(){
								addCur = !root.dom.hasChildren(this);
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'root':			// CSS 3: get the root element of the document
							// http://www.w3.org/TR/css3-selectors/#structural-pseudos
							// " The :root pseudo-class represents an element that is the root of the document.
							// In HTML 4, this is always the HTML element."
							f = [document.documentElement];
							
							break;
						case 'not':				// CSS 3: get element if it doesn't match to the expression
							var self = !wst.regex(value, '^(?:[\\w-]+|\\*)$');
							f = wst.apply(_get, [_matchSelectors(value, self), af, true], root);
							
							break;
						case 'nth-child':		// CSS 3: get element if is it the nth child of its parent
							var matches;
							var step,	// a: step size
								offset;	// b: start offset
							var i = -1, last = -1, te, nodes, parent, index, addCur, repeat;
							
							if(wst.regex(value, '^\\d+$'))
							{
								step = 0;
								offset = parseInt(value);
							}
							else if(wst.regex(value, '^\\D+$'))
							{
								step = Number(((value == 'even' || value == 'odd') && 2) || (value == 'n' && 1));
								offset = Number((value == 'even' && 2) || ((value == 'odd' || value == 'n') && 1));
							}
							else
							{
								matches = wst.regex(value, '^((?:-)?\\d*)?(?:n)?((?:[+-]{1,1})?\\d*)?$');
								step = parseInt(wst.ok(matches[1]) && matches[1]) || ((String(matches[1]).indexOf('-') != -1) && -1) || 1;
								offset = parseInt(wst.ok(matches[2]) && matches[2]) || step;
							}
							
							if(offset < 0)
								offset = Math.abs(offset + step);
							
							repeat = step != 0;
							
							while(te = af[++i])
							{
								if(parent != te.parentNode)
								{
									last = -1;
									parent = te.parentNode;
									nodes = wst.apply(root.dom.children, [parent, null, '*', not], root);
								}
								
								index = wst.binarySearch(te, nodes, true) + 1;
								
								if(repeat)
								{
									if(step < 0)
									{
										addCur = index <= offset;
									}
									else
									{
										if(last == -1)
											addCur = index >= offset;
										else
											addCur = index >= (last + step);
									}
								}
								else
								{
									addCur = index == offset;
								}
								
								if(not ^ addCur)
								{
									last = index;
									f.push(te);
								}
							}
							
							break;
						case 'enabled':			// CSS 3: get elements with enabled property set to true
							var addCur;
							
							af.loop(function(){
								addCur = !this.disabled;
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'disabled':		// CSS 3: get elements with enabled property set to false
							var addCur;
							
							af.loop(function(){
								addCur = !!this.disabled;
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'checked':			// CSS 3: get elements with checked property set to true
							var addCur;
							
							af.loop(function(){
								addCur = !!this.checked;
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'contains':		// CSS 3: get elements that have the given text as a substring of its contents
							var text, addCur;
							
							af.loop(function(){
								text = this.innerText || this.textContent || '';
								addCur = text.search(value) > -1;
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						case 'lang':			// CSS 2: get elements with the given lang attribute
							var addCur;
							
							af.loop(function(){
								addCur = this.getAttribute('lang') == value;
								
								if(not ^ addCur)
									f.push(this);
							});
							break;
						default:
							break;
					}
				}
				
				return f;
			}
		},
		getAttrValue : function(a)
		{
			var wstFnID = 'wst.dom.getAttrValue';
			var attrs = wst.translate.HTML.attributes;
			var r;
			var regex = new wst.Regex('(\\w*)([!*^$%|~]?=)(.*)');
			
			a = a.indexOf('[') > -1 ? a.replace(wst.regex({expr:'\\]|\\[', flags:'g'}), '') : a;
			a = attrs[a] || a;
			r = regex.run(a) ? a.replace(wst.regex({expr:'\\\'|"', flags:'g'}), '').match(regex.object).slice(1) : [a, '=', ''];
			
			return r;
		},
		cssAttrName : function(attr, sintax)
		{
			var wstFnID = 'wst.dom.cssAttrName';
			sintax = sintax || '';
			
			if(attr.indexOf('-') > -1 && !wst.browser.gecko || sintax == 'js')
				attr = attr.replace(wst.regex({expr:'-(\\w{1})', flags:'g'}), function($1){ return $1.replace('-', '').toUpperCase() });
			else if(attr.indexOf('-') == -1 && wst.browser.gecko || sintax == 'css')
				attr = attr.replace(wst.regex({expr:'([A-Z]{1})', flags:'g'}), function($1){ return ('-' + $1).toLowerCase() });
			
			return attr;
		},
		cssHexValue : function(str)
		{
			var wstFnID = 'wst.dom.cssHexValue';
			var values = str.match(wst.regex({expr:'(\\d+)', flags:'g'}));
			var hex = '#';
			var i = -1, current;
			
			while((current = values[++i]) != null)
				hex += wst.hexEncode(current);
				
			return hex;
		},
		getStyle : function(style)
		{
			var wstFnID = 'wst.dom.getStyle';
			var e = this.E[0];
			style = this.dom.cssAttrName(style);
			
			if(e.currentStyle)
			{
				style = e.currentStyle[style];
			}
			else if(window.getComputedStyle)
			{
				style = document.defaultView.getComputedStyle(e, null).getPropertyValue(style);
				style = style.indexOf('rgb') > -1 ? this.dom.cssHexValue(style) : style;
			}
			
			return style;
		},
		setStyle : function(styles, value)
		{
			var wstFnID = 'wst.dom.setStyle';
			var root = this.dom;
			var e = this.E;
			value = value || false;
			
			wst.loop(e, function(styles, value){
				if(typeof styles == 'object')
				{
					var style;
					
					for(style in styles)
						this.style[root.cssAttrName(style, 'js')] = styles[style];
				}
				else
				{
					this.style[root.cssAttrName(styles, 'js')] = value;
				}
			}, [styles, value]);
		},
		makeXHTML : function(e, formatSource)
		{
			var wstFnID = 'wst.dom.makeXHTML';
			formatSource = formatSource || false;
			var newLine = formatSource ? '\n' : '';
			//var tab = formatSource ? '\t' : '';
			//var nTab = 0;
			var xhtml = '';
			var HTMLChars;
			
			if(wst.modules.HTMLChars ? !wst.modules.HTMLChars.loaded : false)
			{
				if(wst.modules.load('HTMLChars') === false)
					return false;
			}
			
			HTMLChars = wst.translate.HTML.chars;
			
			wst.loop(e, function(){
				var tag = this.nodeType == 1 ? (this.nodeName || this.tagName).toLowerCase() : '';
				var attrs = '';
				var children = '';
				//var i = 0;
				
				if(!!this.attributes ? this.attributes.length > 0 : false)
				{
					wst.loop(this.attributes, function(){
						attrs += wst.browser.ie ? 
							this.nodeValue != null && this.nodeValue != '' ? ' ' + this.nodeName + '="' + this.nodeValue + '"' : ''
							: ' ' + this.nodeName + '="' + this.nodeValue + '"';
					});
				}
				
				if(wst.dom.hasChildren(this))
				{
					//nTab++;
					wst.loop(this.childNodes, function(){
						children += wst.dom.makeXHTML(this);
					});
					
					//while(i++ < nTab)
					//	tab += tab;
				}
				
				xhtml += tag != '' ? 
					'<' + tag + attrs + (children == '' ? '/>' : '>' + newLine + children + newLine + '</' + tag + '>') : 
					this.nodeType == 3 ? 
						!!HTMLChars ?
							this.nodeValue.replace(wst.regex({expr:'[^\\w\\s\\.!?,@#$%\\(\\)\\[\\]-]', flags:'g'}), function(char){ return !!HTMLChars[char] ? HTMLChars[char].name : char })
							: this.nodeValue
						: '';
			});
			
			return xhtml;
		},
		tag : function()
		{
			var wstFnID = 'wst.dom.tag';
			var e = this.E[0];
			
			return e.nodeName.toLowerCase();
		},
		type : function()
		{
			var wstFnID = 'wst.dom.type';
			var e = this.E[0];
			
			return e.nodeType;
		},
		value : function(val)
		{
			var wstFnID = 'wst.dom.value';
			var e = this.E[0];
			
			if(!wst.is.undefined(val))
			{
				if(!wst.is.undefined(e.value))
				{
					e.value = val;
				}
				else
				{
					if(e.nodeValue)
						e.nodeValue = val;
				}
				
				return this;
			}
			else
			{
				return !wst.is.undefined(e.value) ? e.value : e.nodeValue;
			}
		},
		lookup : function(e)
		{
			var wstFnID = 'wst.dom.lookup';
			var copy = wst.core._duplicateWST(this);
			var results = copy.get(e);
			return results;
		},
		at : function(n, len)
		{
			var wstFnID = 'wst.dom.at';
			var copy = wst.core._duplicateWST(this);
			var final = n + (len || 1);
			copy.E = copy.E.slice(n, final);
			return copy;
		},
		first : function()
		{
			var wstFnID = 'wst.dom.first';
			var copy = wst.core._duplicateWST(this);
			copy.E = [copy.E[0]];
			return copy;
		},
		last : function()
		{
			var wstFnID = 'wst.dom.last';
			var copy = wst.core._duplicateWST(this);
			copy.E = copy.E.slice(-1);
			return copy;
		},
		append : function(e)
		{
			var wstFnID = 'wst.dom.append';
			
			if(wst.ok(e))
			{
				e = typeof e == 'string' ? wst.cE(e) : typeof e.E != 'undefined' ? e.E : wst.is.array(e) ? e : [e];
				
				this.E.loop(function(){
					wst.loop(e, function(parent){
						parent.appendChild(this);
					}, [this]);
				});
				
				return this;
			}
		},
		appendTo : function(parent)
		{
			var wstFnID = 'wst.dom.appendTo';
			
			parent = typeof parent == 'string' ? wst.get(parent).E[0] : typeof parent.E != 'undefined' ? parent.E[0] : parent;
			
			if(wst.ok(parent))
			{
				this.E.loop(function(parent){
					parent.appendChild(this);
				}, [parent]);
				
				return this;
			}
		},
		remove : function(e)
		{
			var wstFnID = 'wst.dom.remove';
			
			e = typeof e == 'string' ? wst.get(e).E : wst.ok(e) ? typeof e.E != 'undefined' ? e.E : e : false;
			
			if(e)
			{
				this.E.loop(function(){
					wst.loop(e, function(parent){
						parent.removeChild(this);
					}, [this]);
				});
			}
			else
			{
				this.E.loop(function(){
					this.parentNode.removeChild(this);
				});
			}
			
			return this;
		},
		after : function(contentToAppend)
		{
			var wstFnID = 'wst.dom.after';
			var elements = this.E;
			
			if(wst.ok(contentToAppend))
			{
				elements.loop(function(){
					if(this.insertBefore)
					{
						var contents = typeof contentToAppend == 'string' ? wst.cE(contentToAppend) : contentToAppend;
						
						wst.loop(contents, function(parent, reference){
							parent.insertBefore(this, reference);
						}, [this.parentNode, this.nextSibling]);
					}
				});
				
				return this;
			}
		},
		before : function(contentToAppend)
		{
			var wstFnID = 'wst.dom.before';
			var elements = this.E;
			
			if(wst.ok(contentToAppend))
			{
				elements.loop(function(){
					if(this.insertBefore)
					{
						var contents = typeof contentToAppend == 'string' ? wst.cE(contentToAppend) : contentToAppend;
						
						wst.loop(contents, function(parent, reference){
							parent.insertBefore(this, reference);
						}, [this.parentNode, this]);
					}
				});
				
				return this;
			}
		},
		replace : function(contentToReplace)
		{
			var wstFnID = 'wst.dom.replace';
			var root = this;
			var elements = root.E;
			
			if(wst.ok(contentToReplace))
			{
				elements.loop(function(i){
					if(this.replaceChild)
					{
						var contents = typeof contentToReplace == 'string' ? wst.cE(contentToReplace) : contentToReplace;
						
						wst.loop(contents, function(parent, oldChild){
							parent.replaceChild(this, oldChild);
							root.E[i] = this;
						}, [this.parentNode, this]);
					}
				});
				
				return this;
			}
		},
		clone : function(cloneChildren)
		{
			var wstFnID = 'wst.dom.clone';
			var elements = this.E;
			var clones = [];
			var wstClonedElements = wst.core._duplicateWST(this);
			cloneChildren = cloneChildren || true;
			
			elements.loop(function(){
				clones.push(this.cloneNode(cloneChildren));
			});
			
			wstClonedElements.total = (wstClonedElements.E = clones).length;
			
			return wstClonedElements;
		},
		content : function(contentToAppend)
		{
			var wstFnID = 'wst.dom.content';
			var elements = this.E;
			var contents = '';
			var isString = typeof contentToAppend == 'string';
			
			if(wst.ok(contentToAppend) ? (isString ? !wst.regex('\\:\\w+\\:', contentToAppend) : false) : false)
			{
				if(wst.core.mode == 'strict')
				{
					contents = isString ? wst.cE(contentToAppend) : contentToAppend;
					
					elements.loop(function(){
						wst.get(this)
							.clear()
							.append(contents);
					});
				}
				else if(wst.core.mode == 'quirk')
				{
					elements.loop(function(){
						this.innerHTML = '';
						
						if(isString)
							this.innerHTML = contentToAppend;
						else
							this.appendChild(contentToAppend);
					});
				}
				
				return this;
			}
			else
			{
				var contentMode = contentToAppend || ':innerHTML:';
				
				if(wst.core.mode == 'strict')
				{
					var WSTgetTextNodes = this.dom.getTextNodes;
					this.dom.getTextNodes = true;
					
					if(contentMode == ':innerHTML:')
						contents = this.dom.makeXHTML(this.children().E);
					else if(contentMode == ':outerHTML:')
						contents = this.dom.makeXHTML(elements);
					
					this.dom.getTextNodes = WSTgetTextNodes;
				}
				else if(wst.core.mode == 'quirk')
				{
					if(contentMode == ':innerHTML:')
						contents = elements[0].innerHTML;
					else if(contentMode == ':outerHTML:')
						contents = elements[0].outerHTML;
				}
				
				return contents;
			}
		},
		clear : function(onlyWhiteSpace)
		{
			var wstFnID = 'wst.dom.clear';
			
			// only clear if the selection has elements, otherwise the document would be used
			// as the parent node and all the elements on the document would be removed!
			if(this.total > 0)
			{
				if(wst.core.mode == 'strict')
				{
					var WSTgetTextNodes = this.dom.getTextNodes;
					this.dom.getTextNodes = true;
					var nodes = this.lookup('*').E;
					this.dom.getTextNodes = WSTgetTextNodes;
					onlyWhiteSpace = onlyWhiteSpace || false;
					
					nodes.loop(function(){
						if(onlyWhiteSpace ? this.nodeType == 3 : true)
							this.parentNode.removeChild(this);
					});
				}
				else if(wst.core.mode == 'quirk')
				{
					this.E.loop(function(){
						this.innerHTML = '';
					});
				}
			}
			
			return this;
		},
		css : function(style, value)
		{
			var wstFnID = 'wst.dom.css';
			
			if(value || typeof style == 'object')
			{
				wst.apply(this.dom.setStyle, [style, value], this);
				return this;
			}
			else
			{
				return wst.apply(this.dom.getStyle, [style], this);
			}
		},
		attr : function(attr, value)
		{
			var wstFnID = 'wst.dom.attr';
			var obj = this.E;
			var updateValue = typeof value != 'undefined' || typeof attr == 'object';
			
			if(wst.ok(obj))
			{
				var attrs = wst.translate.HTML.attributes;
				var correctAttr = attrs[attr] || attr;
				var attrValue = null;
				
				if(updateValue)
				{
					this.loop(obj, function(correctAttr, value){
						if(typeof correctAttr == 'object')
						{
							for(var prop in correctAttr)
								this.setAttribute(prop, correctAttr[prop]) ? true : this[prop] = correctAttr[prop];
						}
						else
						{
							this.setAttribute(correctAttr, value) ? true : this[correctAttr] = value;
						}
					}, [correctAttr, value]);
				}
				else
				{
					obj = obj[0];
					attrValue = obj.getAttribute(correctAttr) || (obj.attributes.getNamedItem(attr) ? obj.attributes.getNamedItem(attr).value : false) || obj[correctAttr] || '';
				}
				
				if(attrValue != null)
					return attrValue;
				else
					return this;
			}
		},
		clss : function(class1, class2)
		{
			var wstFnID = 'wst.dom.clss';
			var elements = this.E;
			var returnValue = null;
			
			if(this.total > 0)
			{
				var clss, keyword, value;
				
				switch(arguments.length)
				{
					case 2:
						elements.loop(function(class1, class2){
							clss = this.className;
							
							if(wst.regex(clss, '(?:^|\\s+)(' + class1 + ')(?:\\s+|$)'))
								clss = clss.replace(class1, class2);
							else if(!wst.regex(clss, '(?:^|\\s+)(' + class2 + ')(?:\\s+|$)'))
								clss = clss + (clss != '' ? ' ' : '') + class2;
							
							this.className = clss;
						}, [class1, class2]);
						
						returnValue = this;
						break;
					case 1:
						keyword = class1.match(wst.regex('has|remove'));
						
						if(!keyword)
						{
							elements.loop(function(class1){
								if(class1 != '')
								{
									clss = this.className;
									
									if(!wst.regex(clss, '(?:^|\\s+)(' + class1 + ')(?:\\s+|$)'))
										clss = clss + (clss != '' ? ' ' : '') + class1;
									
									this.className = clss;
								}
								else
								{
									this.className = '';
								}
							}, [class1]);
							
							returnValue = this;
						}
						else
						{
							clss = elements[0].className;
							value = class1.match(wst.regex(':(\\w+)$'));
							
							switch(keyword[0])
							{
								case 'has':
									returnValue = value ? (!!wst.regex(clss, '(?:^|\\s+)(' + value[1] + ')(?:\\s+|$)')) : null;
									break;
								case 'remove':
									if(value)
									{
										elements.loop(function(value, clss){
											var needle = wst.regex(clss, '(?:^|\\s+|:)(' + value[1] + ')(?:\\s+|$)');
											clss = clss.replace((needle ? needle[1] : ''), '');
											this.className = clss;
										}, [value, clss]);
									}
									
									returnValue = this;
									break;
							}
						}
						break;
					default:
						returnValue = elements[0].className;
						break;
				}
			}
			
			return returnValue;
		},
		filter : function(expr, value)
		{
			var wstFnID = 'wst.dom.filter';
			var e = this.E;
			var r = [];
			
			if(wst.is.fn(expr))
			{
				r = wst.array.filter(e, expr);
			}
			else
			{
				var prop = expr;
				var actions = {
					'default' : function(){
						return this[prop] == value;
					},
					'has-children' : function(){
						return wst.dom.hasChildren(this);
					}
				};
				var specialAction = expr.charAt(0) == '@';
				var action = specialAction ? expr.slice(1) : expr;
				
				if(specialAction && actions[action])
					r = wst.array.filter(e, actions[action]);
				else
					r = wst.array.filter(e, actions['default']);
			}
			
			this.total = (this.E = r).length;
			return this;
		},
		index : function(expr)
		{
			var wstFnID = 'wst.dom.index';
			var index = -1;
			expr = expr ? expr : this.E ? this.E[0] : null;
			
			if(expr)
			{
				var root = wst.is.wst(this) ? this : wst;
				var nodes = wst.apply(root.dom.children, [expr.parentNode, null, '*', false], root);
				index = wst.binarySearch(expr, nodes, true);
			}
			
			return index;
		},
		sort : function(elements)
		{
			var wstFnID = 'wst.dom.sort';
			var returnValue;
			elements = elements ?
				elements
				: this.E ?
					this.E : [];
			
			if(elements.length > 0)
			{
				elements.sort(_sortDOM);
				returnValue = wst.is.wst(this) ? this : elements;
			}
			
			return returnValue;
		},
		equals : function(expr)
		{
			var wstFnID = 'wst.dom.equals';
			var elements = this.E;
			var targets = wst.is.wst(expr) ? expr.E : wst.is.array(expr) ? expr : [expr];
			var theSame = false;
			
			if(elements ? (elements.length > 0 && (elements.length === targets.length)) : false)
			{
				if(elements.length == 1)
				{
					theSame = elements[0] === targets[0];
				}
				else
				{
					var i = -1;
					var len = elements.length;
					
					while(++i < len)
					{
						theSame = elements[i] === targets[i];
						
						if(!theSame)
							break;
					}
				}
			}
			
			return theSame;
		},
		getTextNodes : false,
		cacheElements : false
	});
	wst.extend(wst, {dom : dom});
	
	// auxiliar function for sort DOM elements list
	var _sortDOM = function(a, b)
	{
		var wstFnID = 'wst._sortDOM';
		
		if(a.compareDocumentPosition)
			return 3 - (a.compareDocumentPosition(b) & 6);
		else
			return a.sourceIndex - b.sourceIndex;
	};
	
	// creates an object from the given selector expression
	var _matchSelectors = function(expr, self)
	{
		var wstFnID = 'wst._matchSelectors';
		var multiSpaces = wst.regex({expr : '\\s{2,}', flags : 'g'});
		var specials = wst.regex({expr : '\\s*([>+~-])\\s*', flags : 'g'});
		var matches = wst.regex({expr : '((?:\\w(?:-\\w)?|\\*)+|(?:[#\\.:+>~-])|(?:\\[[^\\]]*\\])|\\s)|(?:\\([^)]+\\)\\)?)', flags : 'g'});
		expr = wst.trim(expr);
		expr = !self && expr.indexOf(' ') != 0 ? (!!wst.regex(expr, '^[#>+~-]') ? expr : ' ' + expr) : expr;
		expr = expr
			.replace(multiSpaces, ' ')
			.replace(specials, '$1')
			.match(matches);
		
		return expr;
	};
	
	// do the loop looking for elements
	var _get = function(matches, f, not)
	{
		var wstFnID = 'wst._get';
		var n = -1;
		var tagRegex = wst.regex('^(?:[\\w-]+|\\*)$');
		var selector, tag, attr;
		var timer, id;
		
		// loop the matches
		// the condition is checked inside the loop
		while(true)
		{
			selector = matches[++n];
			tag = matches[++n];
			
			// we must ensure a tag in the case of consecutive attribute searchs
			if(!tag && selector ? selector.charAt(0) == '[' : false)
				tag = '*';
			
			// if there's a selector and a tag (element) we lookup for it
			if(selector && tag)
			{
				// set tag if omited
				if(!tag.match(tagRegex))
				{
					tag = '*';
					--n;
				}
				
				// look for attributes
				if(matches[(n + 1)] != undefined)
				{
					switch(matches[(n + 1)].charAt(0))
					{
						case '[':
							attr = matches[++n];
							break;
						case '#':
							++n;
							attr = '[id="' + matches[++n] + '"]';
							break;
						case '.':
							++n;
							attr = '[class="' + matches[++n] + '"]';
							break;
						default:
							attr = null;
							break;
					}
				}
				else
				{
					attr = null;
				}
				
				// do the search using the current selector and tag
				switch(selector.charAt(0))
				{
					case '#': // ID
						if(attr == null)
						{
							attr = tag;
							tag = '*';
						}
						
						f = wst.apply(this.dom.selectors['#'], [f, tag, attr, not], this);
						break;
					case '.': // class
						if(attr == null)
						{
							attr = tag;
							tag = '*';
						}
						
						f = wst.apply(this.dom.selectors['.'], [f, tag, attr, not], this);
						break;
					case '+': // next immediate sibling
						f = wst.apply(this.dom.selectors['+'], [f, tag, attr, not], this);
						break;
					case '~': // next siblings
						f = wst.apply(this.dom.selectors['~'], [f, tag, attr, not], this);
						break;
					case '-': // previous siblings
						f = wst.apply(this.dom.selectors['-'], [f, tag, attr, not], this);
						break;
					case '>': // children
						f = wst.apply(this.dom.selectors['>'], [f, tag, attr, not], this);
						break;
					case ':': // pseudo-class | pseudo-element
						if(wst.regex('lang|not|nth-child|contains', tag) && matches[(n + 1)])
							attr = matches[++n].replace('(', '').replace(')', '');
						
						f = wst.apply(this.dom.selectors[':'], [f, tag, attr, not], this);
						break;
					case '[': // attributes
						attr = selector;
						f = wst.apply(this.dom.selectors['['], [f, tag, attr, not], this);
						break;
					case ' ': // descendant
						f = wst.apply(this.dom.selectors[' '], [f, tag, attr, not], this);
						break;
					default: // selector not accept
						f = [];
						break;
				}
			}
			else
			{
				break; // there's no more selectors, so exit the loop
			}
		}
		
		return f;
	};
	
	wst.extend(wst, {
		get : function(e, f)
		{
			/*
			* @ Available selectors:
			* @ E						= Tag
			* @ E F						= Descendant								- CSS 1			- ok
			* @ #id						= ID										- CSS 1			- ok
			* @ .class					= Class										- CSS 1			- ok
			* @ E, F					= Grouping									- CSS 1			- ok
			8 @ *						= Universal									- CSS 2			- ok
			* @ E > F					= Immediate children						- CSS 2			- ok
			* @ E + F					= Immediate next sibling					- CSS 2			- ok
			* @ E[attribute]			= Attribute									- CSS 2			- ok
			* @ E[attribute = value]	= Equal										- CSS 2			- ok
			* @ E[attribute ~= value]	= Contains value in space-separated list	- CSS 2			- ok
			* @ E[attribute |= value]	= Contains value in hyphen-separated list	- CSS 2			- ok
			* @ E[attribute *= value]	= Contains value as part of the string		- CSS 3			- ok
			* @ E[attribute ^= value]	= Start with								- CSS 3			- ok
			* @ E[attribute $= value]	= End with									- CSS 3			- ok
			* @ E[attribute != value]	= Different									- Additional	- ok
			* @ E[attribute %= value]	= Don't contains							- Additional	- ok
			* @ E:lang()				= Language									- CSS 2			- ok
			* @ E:first-child			= First child								- CSS 2			- ok
			* @ E:last-child			= Last child								- CSS 3			- ok
			* @ E:only-child			= Unique child								- CSS 3			- ok
			* @ E:not()					= Not										- CSS 3			- ok
			* @ E:empty					= Don't have children						- CSS 3			- ok
			* @ E:enabled				= Elements enabled							- CSS 3			- ok
			* @ E:disabled				= Elements disabled							- CSS 3			- ok
			* @ E:checked				= Elements checked							- CSS 3			- ok
			* @ E:nth-child()			= Get the nth child							- CSS 3			- ok
			* @ E:root					= Root element								- CSS 3			- ok
			* @ E:contains()			= Elements that have given text				- CSS 3			- ok
			* @ E:first					= First element of the current selection	- Additional	- ok
			* @ E:last					= Last element of the current selection		- Additional	- ok
			* @ E ~ F					= All next siblings							- CSS 3			- ok
			* @ E - F					= All previous siblings						- Additional	- ok
			* 
			* @ Usage examples:
			* @ div.test
			* @ #myElementID
			* @ *[rel="test"] or *[rel=test] or [rel=test]
			* @ #mySpan, .testClass, div
			* @ #testForm > ul li label + input[type="text"].someClass:last-child
			*/
			
			if(!wst.is.wst(this))
				return (new wst).get(e, f);
			
			try
			{
				var wstFnID = 'wst.get';
				var r = [];
				
				if(typeof e != 'undefined')
				{
					this.expr = e;
					
					if(typeof e == 'string')
					{
						// recover from cache
						if(wst.cache.enabled && this.dom.cacheElements ? wst.cache.get(this.expr) : false)
						{
							r = wst.cache.get(this.expr).dom;
						}
						else
						{
							f = this.total > 0 && typeof f == 'undefined' ? this.E : (!wst.is.array(f) ? [f || document] : f);
							
							if(e.indexOf(',') > -1)
							{
								var current, m, i = -1, oExpr = this.expr, arrayE = e.replace(wst.regex({expr:'\\s*,\\s+', flags:'g'}), ',').split(',');
								
								while(current = arrayE[++i])
								{
									m = this.get(current, f).E;
									r = wst.array(m, r);
								}
								
								r = wst.array.unique(r);
								
								this.expr = oExpr;
							}
							else
							{
								var n = -1;
								var str = e;
								
								e = _matchSelectors(e, false);
								r = wst.apply(_get, [e, f, false], this);
								
								// cache the result
								if(wst.cache.enabled && this.dom.cacheElements)
									wst.cache.add(this.expr, r, 'dom');
							}
						}
					}
					else
					{
						r = wst.is.wst(e) ?
							e.E :
							wst.ok(e) ?
								(!wst.is.array(e) ? wst.array.create(e) : e) :
								[];
					}
				}
				else
				{
					r = [];
				}
				
				// log
				if(wst.log.enabled && wst.log.dom.enabled)
					wst.log.add('dom', wst.core._getCaller(), (r.length || 1));
				
				this.total = (this.E = r).length;
				
				return this;
			}
			catch(err)
			{
				if(wst.log.enabled && wst.log.errors.enabled)
					wst.log.add('errors', wst.core._getCaller(), (err.message || err));
				
				this.total = (this.E = []).length;
				
				return this;
			}
		},
		add : function(expr)
		{
			var wstFnID = 'wst.add';
			var elemnts;
			
			if(wst.is.dom(expr))
			{
				this.E.push(expr);
				this.total += 1;
			}
			else if(wst.is.string(expr))
			{
				this.E = wst.array(this.E, this.get(expr).E);
				this.total = this.E.length;
			}
			
			return this;
		},
		pop : function(expr)
		{
			var wstFnID = 'wst.pop';
			
			if(!wst.is.undefined(expr))
			{
				if(wst.is.dom(expr))
				{
					wst.inArray(expr, this.E, 'delete');
					this.total -= 1;
				}
				else if(wst.is.string(expr))
				{
					var props = expr.split('=');
					
					this.filter(props[0], props[1]);
				}
				else if(wst.is.number(expr))
				{
					delete this.E[expr];
					this.total -= 1;
				}
			}
			else
			{
				this.E.pop();
				this.total -= 1;
			}
			
			return this;
		},
		parent : function(n)
		{
			var wstFnID = 'wst.parent';
			var e = [];
			return wst.apply(this.dom.family, ['parent', e, n], this);
		},
		next : function(n)
		{
			var wstFnID = 'wst.next';
			var e = [];
			return wst.apply(this.dom.family, ['next', e, n], this);
		},
		prev : function(n)
		{
			var wstFnID = 'wst.prev';
			var e = [];
			return wst.apply(this.dom.family, ['prev', e, n], this);
		},
		siblings : function(n)
		{
			var wstFnID = 'wst.siblings';
			var e = [];
			return wst.apply(this.dom.family, ['siblings', e, n], this);
		},
		children : wst.extend(
			function(n)
			{
				var wstFnID = 'wst.children';
				var e = [];
				return wst.apply(this.dom.family, ['children', e, n], this);
			}, {
				has : function()
				{
					var wstFnID = 'wst.children.has';
					return wst.apply(this.constructor.dom.hasChildren, [], this.constructor);
				}
			}
		),
		cE : function(e)
		{
			var wstFnID = 'wst.cE';
			var attrs, attr, quotes, element, array, args, tag, matches, endTag, startTag, uniqueTag, txt, parent, current, rootParent, elements = new Array();
			var i, j, level, tagsLen, childsLen, nesting;
			
			e = e.replace(wst.regex({expr:'[\\n\\t\\r]*', flags:'g'}), '');
			matches = e.match(wst.regex({expr:'<(\\w*)([^>]*)?>.*?(?:</\\1>)*?|<(\\w*)([^>]*)?\\/>|[^<]+', flags:'gim'}));
			
			if(wst.is.array(matches))
			{
				i = -1;
				tagsLen = matches.length;
				parent = null;
				nesting = 0;
				level = 0;
				
				while(++i < tagsLen)
				{
					current = matches[i];
					if(!!current && current != '')
					{
						startTag = !!wst.regex(current, {expr:'^<\\w*\\b[^>]*>$', flags:'im'});
						uniqueTag = !!wst.regex(current, {expr:'^<\\w*\\b[^>]*/>$', flags:'im'});
						endTag = !!wst.regex(current, {expr:'^</\\w*>$', flags:'im'});
						txt = !!wst.regex(current, {expr:'^[^<]*$', flags:'im'});
						
						if(startTag || uniqueTag)
						{
							array = current.match(wst.regex({expr:'^<(\\w*)([^>]*)>$', flags:'im'}));
							tag = array[1];
							args = array[2];
							element = document.createElement(tag);
							args = args.match(wst.regex({expr:'(\\w*)=(\\\'|\\")?([^\\2]*?)\\2', flags:'gim'}));
							
							if(wst.ok(args))
							{
								attrs = this.translate.HTML.attributes;
								quotes = wst.regex({expr:'^[\\\'\\"\\s]|[\\\'\\"\\s]$', flags:'g'});
								j = args.length;
								
								while(j-- > 0)
								{
									attr = args[j].match(wst.regex('([^=]+)=(.+)'));
									
									if(attr.length > 1)
									{
										attr[1] = attrs[attr[1]] || attr[1];
										attr[2] = attr[2].replace(quotes, '');
										
										if(attr[1] != 'style')
										{
											try{
												element[attr[1]] = attr[2];
											}
											catch(err){
												element.setAttribute(attr[1], attr[2]);
											};
										}
										else
										{
											element[attr[1]].cssText = attr[2];
										}
									}
								}
							}
							
							if(parent != null)
								parent.appendChild(element);
							else
								elements.push(element);
							
							if(!uniqueTag)
							{
								parent = element;
								level++;
							}
							
							if(i == 0)
								rootParent = parent;
						}
						else if(endTag)
						{
							// IE BUG: in some cases when we are at the top of the DOM tree, IE uses the documentFragment as the parentNode,
							// wich makes the method return the documentFragment as an element of the result array of elements.
							// So we compare the nodeType of the parentNode to see if it is different of 11, wich is the nodeType of the documetFragment.
							parent = this.validObject(parent.parentNode) && parent.parentNode.nodeType != 11 ? parent.parentNode : null;
							
							if(--level == 0)
							{
								nesting++;
								
								if(this.validObject(parent))
									elements.push(parent);
							}
						}
						else if(txt)
						{
							if(!!wst.regex(current, '.*&[^;]+;.*'))
							{
								if(wst.modules.HTMLEntities ? !wst.modules.HTMLEntities.loaded : false)
								{
									if(wst.modules.load('HTMLEntities') === false)
										return false;
								}
								
								current = current.replace(wst.regex({expr:'&[^;]+;', flags:'g'}), function(entity){ return wst.translate.HTML.entities[entity] });
							}
							
							element = document.createTextNode(current);
							
							if(parent != null)
								parent.appendChild(element);
							else
								elements.push(element);
						}
					}
				}
			}
			
			return nesting > 1 || (nesting <= 1 && elements.length > 1) ? elements : this.validObject(rootParent) ? rootParent : elements[0] ;
		},
		pos : function()
		{
			var wstFnID = 'wst.getPos';
			var curleft = 0, curtop = 0;
			var obj = this.E[0];
			
			if(obj.offsetParent)
			{
				curleft = obj.offsetLeft;
				curtop = obj.offsetTop;
				
				while(obj = obj.offsetParent)
				{
					curleft += obj.offsetLeft;
					curtop += obj.offsetTop;
				}
			}
			
			return {left : curleft, top : curtop};
		},
		show : function()
		{
			var wstFnID = 'wst.show';
			
			this.css('display', 'block');
			
			return this;
		},
		hide : function()
		{
			var wstFnID = 'wst.hide';
			
			this.css('display', 'none');
			
			return this;
		},
		scrollView : function()
		{
			var wstFnID = 'wst.scrollView';
			var args = arguments;
			var targets = this.E, pos, x, y;
			
			switch(args.length)
			{
				case 2:
					x = args[0];
					y = args[1];
					break;
				case 1:
					pos = wst.get(args[0]).pos();
					x = pos.left;
					y = pos.top;
					break;
			}
			
			targets.loop(function(){
				this.scrollLeft = x;
				this.scrollTop = y;
			});
			
			return this;
		},
		buildSelect : function(html, indexSelected, removeChilds)
		{
			var wstFnID = 'wst.buildSelect';
			indexSelected = indexSelected || 0;
			removeChilds = removeChilds || true;
			var result = wst.cE(html);
			result = wst.is.array(result) ? result : [result];
			
			this.E.loop(function(removeChilds, result){
				var i, option;
				
				if(removeChilds)
					wst.get(this).clear();
				
				i = 0;
				
				if(!wst.browser.ie)
				{
					while(option = result[i++])
						this.options.add(option, i);
				}
				else
				{
					while(option = result[i++])
						this.appendChild(option);
				}
				
				if(this.selectedIndex)
					this.selectedIndex = indexSelected;
				else
					wst.get(this.options[indexSelected]).attr('selected', true);
			}, [removeChilds, result]);
			
			return this;
		},
		randomize : function(min, max)
		{
			var wstFnID = 'wst.randomize';
			return Math.floor(Math.random() * (max - min + 1)) + min;
		},
		encodeUrl : function(oStr)
		{
			var wstFnID = 'wst.encodeUrl';
			var hex_chars = '0123456789ABCDEF';
			var noEncode = wst.regex('[\\d\\w\\-\\.\\=]');
			var str = new String(oStr);
			var n = -1, len = str.length;
			var strCode, hex1, hex2, strEncode = '';
			
			while(++n < len)
			{
				if(noEncode.test(str.charAt(n)))
				{
					strEncode += str.charAt(n);
				}
				else
				{
					strCode = str.charCodeAt(n);
					hex1 = hex_chars.charAt(Math.floor(strCode / 16));
					hex2 = hex_chars.charAt(strCode % 16);
					strEncode += '%' + (hex1 + hex2);
				}
			}
			
			return strEncode;
		},
		decodeUrl : function(oStr)
		{
			var wstFnID = 'wst.decodeUrl';
			var n, strCode, strDecode = '';
			var str = new String(oStr);
			var n = -1, len = str.length;
			
			while(++n < len)
			{
				if(str.charAt(n) == '%')
				{
					strCode = str.charAt(n + 1) + str.charAt(n + 2);
					strDecode += String.fromCharCode(parseInt(strCode, 16));
					n += 2;
				}
				else
				{
					strDecode += str.charAt(n);
				}
			}
			
			strDecode = strDecode.replace(wst.regex({expr:'\\+', flags:'g'}),' ');
			return strDecode;
		},
		base64encode : function(s)
		{
			var wstFnID = 'wst.base64encode';
			var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
			var r = '', p = '', n = '';
			var c = s.length % 3;
			
			if(c > 0)
			{
				for(; c < 3; c++)
				{
					p += '=';
					s += '\0';
				}
			}
		
			for(c = 0; c < s.length; c += 3)
			{
				if(c > 0 && (c / 3 * 4) % 76 == 0)
					r += '\r\n';
				
				n = (s.charCodeAt(c) << 16) + (s.charCodeAt(c+1) << 8) + s.charCodeAt(c+2);
				n = [(n >>> 18) & 63, (n >>> 12) & 63, (n >>> 6) & 63, n & 63];
				r += base64chars[n[0]] + base64chars[n[1]] + base64chars[n[2]] + base64chars[n[3]];
			}
			
			return r.substr(0, r.length - p.length) + p;
		},
		base64decode : function(s)
		{
			var wstFnID = 'wst.base64decode';
			var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
			var base64inv = {};
			var p = (s.charAt(s.length-1) == '=' ? (s.charAt(s.length-2) == '=' ? 'AA' : 'A') : "");
			var r = '';
			
			for(var i = 0; i < base64chars.length; i++)
				base64inv[base64chars[i]] = i;
			
			s = s.substr(0, s.length - p.length) + p;
			s = s.replace(wst.regex({expr:'[^'+base64chars.join('')+']', flags:'g'}), '');
			
			for(var c = 0; c < s.length; c += 4)
			{
				var n = (base64inv[s.charAt(c)] << 18) + base64inv[s.charAt(c+3)] + (base64inv[s.charAt(c+1)] << 12) + (base64inv[s.charAt(c+2)] << 6);
				r += String.fromCharCode((n >>> 16) & 255, (n >>> 8) & 255, n & 255);
			}
			
			return r.substr(0, r.length - p.length);
		},
		hexEncode : function(n)
		{
			var wstFnID = 'wst.hexEncode';
			var chars = '0123456789ABCDEF'.split('');
			var div = Math.floor(n / 16);
			var mod = n % 16;
			var hex = (chars[div] || '0') + '' + (chars[mod] || '0');
			
			return hex;
		},
		hexDecode : function(hex)
		{
			var wstFnID = 'wst.hexDecode';
			var chars = {'A':10, 'B':11, 'C':12, 'D':13, 'E':14, 'F':15};
			var char1 = hex.charAt(0).toUpperCase(), char2 = hex.charAt(1).toUpperCase();
			var n = Number((chars[char1] || char1) * 16) + Number(chars[char2] || char2);
			
			return n;
		},
		/*******************
		* @ EVENT OBJECT @ *
		*******************/
		event : wst.extend(
			function(){
				var wstFnID = 'wst.event';
				var evt = null;
				var args = arguments;
				var call = null;
				var i, k, len;
				
				while(args != null)
				{
					if(args.length > 0)
					{
						for(k = 0, len = args.length; k < len; k++)
						{
							if(args[k] ? (args[k].type || args[k].target || args[k].srcElement || args[k].keyCode || args[k].which || args[k].charCode) : false)
							{
								evt = args[k];
								break;
							}
						}
					}
					
					if(evt)
						break;
					
					args = (call = args.callee.caller).arguments;
				}
				
				return evt;
			
			}, {
				cancelDefault : function(evt)
				{
					var wstFnID = 'wst.event.cancelDefault';
					evt = evt || wst.event();
					
					if(evt.preventDefault)
						evt.preventDefault();
					
					evt.returnValue = false;
					return false;
				},
				cancelPropagation : function(evt)
				{
					var wstFnID = 'wst.event.cancelPropagation';
					evt = evt || wst.event();
					
					if(evt.stopPropagation)
						evt.stopPropagation();
					
					evt.cancelBubble = true;
				},
				keyCode : function(evt)
				{
					var wstFnID = 'wst.event.keyCode';
					evt = evt || wst.event();
					
					return evt.keyCode || evt.which || evt.charCode || -1;
				},
				mouseButton : function(evt)
				{
					var wstFnID = 'wst.event.mouseButton';
					evt = evt || wst.event();
					
					return evt.button || evt.which;
				},
				checkNumber : function(evt)
				{
					var wstFnID = 'wst.event.checkNumber';
					var keycode = wst.event.keyCode(evt);
					
					return ((keycode >= 48 && keycode <= 57) || (keycode >= 96 && keycode <= 105));
				},
				checkLetter : function(evt)
				{
					var wstFnID = 'wst.event.checkLetter';
					var keycode = wst.event.keyCode(evt);
					
					return (keycode >= 65 && keycode <= 90);
				},
				checkTab : function(evt)
				{
					var wstFnID = 'wst.event.checkTab';
					var keycode = wst.event.keyCode(evt);
					
					return !!wst.regex(keycode, '^[89]{1}$|^1[36-9]{1}$|^20$|^3[3-9]{1}$|^4[06]{1}$|^9[1-3]{1}$|^14[45]{1}$');
				},
				handlers : [],
				uid : 0,
				listen : function(oExp, evtType, handler)
				{
					var wstFnID = 'wst.event.listen';
					var root = this;
					var es;
					
					if(!handler)
					{
						handler = evtType;
						evtType = oExp;
						es = root.E;
					}
					else
					{
						es = root.get(oExp).E;
					}
					
					if(wst.log.enabled && wst.log.events.enabled)
						wst.log.add('events', wst.core._getCaller() + ' ' + wstFnID, es + '.on' + evtType + ' = ' + wst.core._getCaller(handler));
					
					es.loop(function(evtType, handler){
						if(this.addEventListener || this.attachEvent)
						{
							var orig = handler;
							var thisElement = this;
							
							handler = function(evt){
								var newEvent = wst.extend({}, evt);
								var args = [], arg;
								var i = 0;
								
								// fix the target element
								!root.ok(newEvent.target) ? newEvent.target = evt.srcElement : null;
								// Safari bug
								wst.browser.sf && newEvent.target.nodeType == 3 ? newEvent.target = evt.target.parentNode : null;
								// create storPropagation for any browser
								newEvent.stopPropagation = function(){ wst.event.cancelPropagation(evt) };
								// create preventDefault for any browser
								newEvent.preventDefault = function(){ wst.event.cancelDefault(evt) };
								// create metaKey = ctrlKey if not present
								!wst.ok(newEvent.metaKey) && wst.ok(newEvent.ctrlKey) ? newEvent.metaKey = evt.ctrlKey : null;
								// standard keyCode
								newEvent.keyCode = evt.keyCode || evt.which || evt.charCode;
								// mouse button
								!wst.ok(evt.button) ? newEvent.button = evt.which : null;
								// verify if the key is a number
								newEvent.isNumber = wst.event.checkNumber(evt);
								// verify if the key is a letter
								newEvent.isLetter = wst.event.checkLetter(evt);
								// verify if the key is a tab (see wst.event.isTab)
								newEvent.isTab = wst.event.checkTab(evt);
								
								// arguments to be passed, with the event object as the first one
								while(arg = arguments[i++])
									args.push(arg == evt ? newEvent : arg);
								
								// apply the arguments and the target element to the handler function
								return orig.apply(thisElement, args);
							};
							
							orig.uid = wst.event.uid++;
							wst.event.handlers[orig.uid] = {
								target : this,
								type : evtType,
								fn : handler
							};
							
							if(this.addEventListener && !this.attachEvent)
								this.addEventListener(evtType, handler, false);
							else if(this.attachEvent)
								this.attachEvent('on' + evtType, handler);
						}
						else if(wst.is.dom(this))
						{
							this['on' + evtType] = handler;
						}
					}, [evtType, handler]);
					
					return this;
				},
				unListen : function(oExp, evtType, handler)
				{
					var wstFnID = 'wst.event.unListen';
					var root = this;
					var es;
					
					if(!handler)
					{
						handler = evtType;
						evtType = oExp;
						es = root.E;
					}
					else
					{
						es = root.get(oExp).E;
					}
					
					if(wst.log.enabled && wst.log.events.enabled)
						wst.log.add('events', wst.core._getCaller() + ' ' + wstFnID, es + '.on' + evtType + ' = ' + wst.core._getCaller(handler));
					
					if(root.ok(handler))
					{
						var savedHandler = wst.event.handlers[handler.uid];
						
						if(savedHandler)
						{
							es.loop(function(evtType, handler){
								if(this.removeEventListener || this.detachEvent)
								{
									if(this.removeEventListener && !this.detachEvent)
										this.removeEventListener(evtType, handler, false);
									else if(this.detachEvent)
										this.detachEvent('on' + evtType, handler);
								}
								else if(typeof this == 'object' && this['on' + evtType])
								{
									this['on' + evtType] = null;
								}
							}, [evtType, savedHandler.fn]);
						}
						
						wst.event.handlers[handler.uid] = null;
						delete wst.event.handlers[handler.uid];
					}
					else
					{
						root.loop(wst.event.handlers, function(es, evtType){
							if(this.target == es && this.type == evtType)
							{
								var savedHandler = this.fn;
								
								wst.event.handlers[savedHandler.uid] = null;
								delete wst.event.handlers[savedHandler.uid];
								
								if(this.removeEventListener && !this.detachEvent)
									this.removeEventListener(evtType, savedHandler, false);
								else if(this.detachEvent)
									this.detachEvent('on' + evtType, savedHandler);
								else if(typeof this['on' + evtType] != 'undefined')
									this['on' + evtType] = null;
							}
						}, [es, evtType]);
					}
					
					return this;
				}
			}
		),
		loaded : function(fn, index, expr)
		{
			var wstFnID = 'wst.loaded';
			expr = wst.ok(expr) ? expr : this.expr;
			index = wst.ok(index) ? index : 0;
			var elements = (this.total > 0 && !wst.ok(expr) ? this.E : wst.get(expr).E).slice(index);
			
			if((elements.length > 0) && (elements.length > index))
			{
				index = elements.length;
				
				elements.loop(function(i){
					wst.apply(fn, [i], this);
				});
			}
			
			if(!wst.documentLoaded)
				wst.timeout(this, 'loaded', 70, fn, index, expr);
			
			return this;
		},
		ready : function(fn)
		{
			var wstFnID = 'wst.ready';
			var expr = this.expr;
			var onReady = function(evt){
				var wstFnID = 'wst.ready.onReady';
				
				if(wst.regex('complete|loaded', this.readyState))
					wst.apply(fn, [evt], this);
			};
			var onLoadGecko = function(evt){
				var wstFnID = 'wst.ready.onLoadGecko';
				
				wst.apply(fn, [evt], this);
			};
			var onReadyWebkit = function(fn, element){
				var wstFnID = 'wst.ready.onReadyWebkit';
				
				if(wst.regex('complete|loaded', element.readyState))
					wst.apply(fn, [evt], element);
			};
			
			if(wst.browser.gecko)
			{
				this.listen('DOMContentLoaded', onLoadGecko);
			}
			else if(wst.browser.webkit)
			{
				this.loop(function(){
					wst.timeout(onReadyWebkit, 70, fn, this);
				});
			}
			else
			{
				this.listen('readystatechange', onReady);
			}
			
			return this;
		},
		blockKey : function(limit)
		{
			var wstFnID = 'wst.blockKey';
			limit = limit || 0;
			
			var block = function(evt){
				if(this.value.length >= limit)
				{
					if(!evt.isTab)
						return evt.preventDefault();
				}
			};
			
			this.listen('keydown', block);
			
			return this;
		},
		onlyNumbers : function()
		{
			var wstFnID = 'wst.onlyNumbers';
			var aceptOnlyNumbers = function(evt){
				if(!evt.isNumber)
				{
					if(!evt.isTab)
						return evt.preventDefault();
				}
			};
			
			this.listen('keydown', aceptOnlyNumbers);
			
			return this;
		},
		disableRightClick : function(message)
		{
			var wstFnID = 'wst.disableRightClick';
			var disableRightClick = function(evt){
				if((evt.button <= 0 && wst.browser.ie) || evt.button == 2 || evt.button == 3)
				{
					
					if(message)
						alert(message);
					else if(wst.browser.op)
						wst.error(wst.messages.functions.disableRightClick);
					
					evt.stopPropagation();
					return evt.preventDefault();
				}
			};
			message = message || '';
			
			this.listen('contextmenu', disableRightClick);
			
			if(wst.browser.op)
				this.listen('mousedown', disableRightClick);
			
			return this;
		},
		setMask : function(format)
		{
			var wstFnID = 'wst.setMask';
			var arrayMask = [];
			var input, inputs = this.E;
			var separators = format.replace(wst.regex({expr : '\\d', flags : 'g'}), '').split('');
			var mouseButton;
			var maxLen = format.length;
			var keycode, ctrlkey, shiftkey, altkey, mouseButton;
			var i = -1;
			
			while(++i < maxLen)
			{
				if(wst.inArray(format.charAt(i), separators) !== false)
					arrayMask.push([i, format.charAt(i)]); // position, separator
			}
			
			// keydown event (main)
			var handleMask = function(evt)
			{
				var wstFnID = 'wst.setMask.handleMask';
				evt.stopPropagation();
				keycode = evt.keyCode;
				ctrlkey = evt.ctrlKey;
				shiftkey = evt.shiftKey;
				altkey = evt.altKey;
				mouseButton = null;
				input = this;
				
				// DELETE, BACKSPACE
				if(keycode == 46 || keycode == 8)
				{
					var pos = keycode == 46 ? wst.get(input).getSelectionPos() : wst.get(input).getSelectionPos() - 1;
					var char = input.value.charAt(pos);
					var text = '';
					
					if(char)
					{
						if(wst.inArray(char, separators) !== false)
						{
							formatStringToMask(input);
							//return evt.preventDefault();
						}
						else
						{
							text = input.value.replace(input.value.charAt(pos), '');
							
							if(wst.regex(text, '^\\D+$'))
								input.value = '';
						}
					}	
				}
				
				if(evt.isNumber)
				{
					if(input.value.length >= maxLen)
						return evt.preventDefault();
					
					wst.timeout(formatStringToMask, 1, input);
				}
				else
				{
					if(((keycode == 86 && ctrlkey) || mouseButton == 3) || wst.browser.op)
						wst.timeout(formatStringToMask, 1, input);
					
					if(!evt.isTab)
						return evt.preventDefault();
					else
						return true;
				}
			};
			
			// paste event
			var handleMaskPaste = function(evt)
			{
				var wstFnID = 'wst.setMask.handleMaskPaste';
				var input = this;
				
				if(((keycode == 86 && ctrlkey) || mouseButton == 3) || wst.browser.ie)
					wst.timeout(formatStringToMask, 1, input);
			};
			
			// mouse right click event
			var handleMaskClick = function(evt)
			{
				var wstFnID = 'wst.setMask.handleMaskClick';
				evt.stopPropagation();
				mouseButton = evt.which;
			};
			
			// format function
			var formatStringToMask = function(input)
			{
				var wstFnID = 'wst.setMask.formatStringToMask';
				var value = input.value.replace(wst.regex({expr : '\\D', flags : 'g'}), '');
				var formatedStr = '', subStr = '';
				var i = -1, last = 0, n = 0, prev = 0;
				var curPos, multi = false;
				
				while(curPos = arrayMask[++i])
				{
					if(prev == (curPos[0] - 1))
					{
						multi = true;
						subStr = '';
					}
					else
					{
						multi = false;
						subStr = value.substring(last, (curPos[0] - n));
					}
					
					if((subStr != '') || (curPos[0] === 0) || multi)
					{
						n++;
						formatedStr += subStr;
						
						if(input.value.length >= curPos[0])
						{
							if(curPos[0] === 0)
								formatedStr = curPos[1] + formatedStr;
							else
								formatedStr += curPos[1];
							
							prev = curPos[0];
							last += subStr.length;
						}
						else
						{
							break;
						}
					}
				}
				
				last = arrayMask.slice(-1)[0];
				
				if(formatedStr.lastIndexOf(last[1]) == last[0])
					formatedStr += input.value.substr((last[0] + 1), (maxLen - last[0] - 1));
				
				input.value = formatedStr;
			};
			
			this
				.listen('keydown', handleMask)
				.listen('mousedown', handleMaskClick)
				.listen('input', handleMaskPaste)	// Firefox
				.listen('paste', handleMaskPaste);	// IE
			
			// include the mask for the formValidator use if the 'autoMask' option is enabled
			if(wst.ok(wst.validation))
			{
				inputs.loop(function(format){
					if(this.id)
						wst.validation.masks[this.id] = format;
				}, format);
			}
			
			return this;
		},
		regexMask : function(stringMask)
		{
			var wstFnID = 'wst.regexMask';
			var mask = '^';
			var n = 0;
			var rn = wst.regex('\\d');
			var arrayString = stringMask.split('');
			
			for(var i = 0, len = arrayString.length; i < len; i++)
			{
				if(rn.test(arrayString[i]))
				{
					n++;
				}
				else
				{
					if(n > 0)
					{
						mask += '\\d{' + n + '}';
						n = 0;
					}
					
					mask += (arrayString[i] == ' ' ? '' : '\\') + arrayString[i];
				}
				
				if(i == (arrayString.length - 1) && n > 0)
					mask += '\\d{' + n + '}';
			}
			
			mask += '$';
			return wst.regex(mask);
		},
		getSelectionPos : function()
		{
			var wstFnID = 'wst.getSelectionPos';
			var selection;
			
			if(wst.ok(document.selection))
				selection = Math.abs(document.selection.createRange().moveStart('character', -1000000));
			else if(wst.ok(this.E[0].selectionStart))
				selection = this.E[0].selectionStart;
			
			return selection;
		},
		setSelectionPos : function(pos)
		{
			var wstFnID = 'wst.setSelectionPos';
			
			if(wst.ok(document.selection))
			{
				var range = document.selection.createRange();
				
				if(range.compareEndPoints('StartToEnd', range) != 0)
					range.collapse(true);
				
				range.moveStart('character', pos);
				range.moveEnd('character', pos);
				range.select();
			}
			else
			{
				this.E[0].selectionStart = pos;
				this.E[0].selectionEnd = pos;
			}
			
			return this;
		},
		inArray : function(searchedValue, array, op, keyName)
		{
			var wstFnID = 'wst.inArray';
			op = op || 'check';
			keyName = keyName || false;
			
			if(array.length != undefined)
			{
				if(array.length > 0)
				{
					var index = -1, size = array.length;
					
					while(++index < size)
					{
						if(keyName ? searchedValue == array[index][keyName] : searchedValue == array[index])
						{
							if(op == 'delete')
							{
								delete array[index];
								return true;
							}
							else if(op == 'check')
							{
								return index;
							}
						}
					}
				}
				
				return false;
			}
			else
			{
				for(var key in array)
				{
					if(keyName ? searchedValue == array[key][keyName] : searchedValue == array[key])
					{
						if(op == 'delete')
						{
							delete array[key];
							return true;
						}
						else if(op == 'check')
						{
							return key;
						}
					}
				}
				
				return false;
			}
		},
		binarySearch : function(value, array, isDOM)
		{
			var wstFnID = 'wst.binarySearch';
			var start = 0;
			var end = array.length - 1;
			var index = -1;
			
			if(isDOM === undefined)
				isDOM = wst.is.dom(value);
			
			// for faster search in some cases, we verify if the searched value is the first or last
			// element of the array, so we don't need to do the loop
			if(value === array[start])
			{
				index = start;
			}
			else if(value === array[end])
			{
				index = end;
			}
			else
			{
				// uses the Array.indexOf method if present (JavaScript 1.6)
				if(Array.indexOf)
				{
					array = wst.is.array(array) ? array : wst.array.create(array);
					index = array.indexOf(value);
				}
				else
				{
					// if the searched value was not found yet, we do the binary search
					var midValue, lowerValue, higherValue;
					var mid, up;
					var DOMSupport = !!value.compareDocumentPosition;
					
					while(start <= end)
					{
						mid = parseInt((start + end) / 2);
						lowerValue = array[mid - 1];
						midValue = array[mid];
						higherValue = array[mid + 1];
						
						if(isDOM)
							up = DOMSupport ? value.compareDocumentPosition(midValue) == 4 : midValue.sourceIndex > value.sourceIndex;
						else
							up = midValue > value;
						
						if(midValue === value)
						{
							index = mid;
							break;
						}
						else if(lowerValue === value)
						{
							index = mid - 1;
							break;
						}
						else if(higherValue === value)
						{
							index = mid + 1;
							break;
						}
						else if(up)
						{
							end = mid - 2;
						}
						else
						{
							start = mid + 2;
						}
					}
				}
			}
			
			return index;
		},
		regex : function(str, source)
		{
			var wstFnID = 'wst.regex';
			var re = new wst.Regex();
			
			switch(arguments.length)
			{
				case 2:
					if(typeof arguments[1] == 'string')
						return re.run(arguments[0], arguments[1]);
					else if(typeof arguments[1] == 'object')
						return re.run(arguments[0], arguments[1].expr, (arguments[1].flags || ''));
					break;
				case 1:
					if(typeof arguments[0] == 'string')
						return re.create(arguments[0]);
					else if(typeof arguments[0] == 'object')
						return re.create((arguments[0].expr || ''), (arguments[0].flags || ''));
					break;
				default:
					return false;
					break;
			}
		},
		loadImages : function()
		{
			var wstFnID = 'wst.loadImages';
			var imgs = arguments;
			var len = imgs.length;
			
			if(len > 0)
			{
				var img, src;
				
				while(src = imgs[--len])
				{
					img = new Image();
					img.src = src;
					wst.imagesLoaded.push(img);
				}
			}
		},
		include : function()
		{
			var wstFnID = 'wst.include';
			var list = arguments;
			
			if(list.length > 0)
			{
				var i = 0;
				var script;
				var type;
				var head = this.get('head');
				var include;
				
				while(script = list[i++])
				{
					type = String(script.split('.').slice(-1)[0]).toLowerCase();
										
					switch(type)
					{
						case 'js':
							include = wst.cE('<script src="' + script + '" type="text/javascript"></script>');
							break;
						case 'css':
							include = wst.cE('<link href="' + script + '" rel="stylesheet" type="text/css" media="all" />');
							break;
					}
					
					head.append(include);
				}
				
				return include;
			}
		},
		loop : function(e, fn, args)
		{
			var wstFnID = 'wst.loop';
			
			if(!fn || (wst.is.fn(e) && fn != undefined))
			{
				args = fn;
				fn = e;
				e = wst.is.wst(this) ? this.E : this;
			}
			
			if(e)
			{
				e = wst.validObject(e) ? [e] : e;
				args = args != undefined ? (wst.is.array(args) ? args : [args]) : false;
				var i, len;
				
				if(e.length != undefined)
				{
					i = -1;
					len = e.length;
					
					while(++i < len)
					{
						if(fn.apply(e[i], (args || [i])) === false)
							break;
					}
				}
				else
				{
					for(i in e)
					{
						if(fn.apply(e[i], (args || [i])) === false)
							break;
					}
				}
			}
			
			return this;
		},
		/*******************
		* @ TIMER OBJECT @ *
		*******************/
		timer : {
			init : null,
			end : null,
			elapsed : null,
			history : [],
			intervals : {},
			start : function()
			{
				var wstFnID = 'wst.timer.start';
				this.clear();
				var time1 = (new Date()).getTime();
				var id = this.history.length;
				
				this.init = time1;
				this.history.push({
					init : time1,
					end : null,
					elapsed : null
				});
				this.intervals[id] = true;
				//setTimeout(wst.timer.checkInterval, 10, id);
				
				return id;
			},
			stop : function(id)
			{
				var wstFnID = 'wst.timer.stop';
				var index = typeof id != 'undefined' ? id : this.history.length - 1;
				
				//clearInterval(this.intervals[index]);
				delete this.intervals[index];
				var time1 = this.history[index].init;
				var time2 = (new Date()).getTime();
				var diff = (time2 - time1) / 1000;
				this.end = time2;
				this.elapsed = diff;
				this.history[index].end = time2;
				this.history[index].elapsed = diff;
				
				return diff;
			},
			stopAll : function()
			{
				var wstFnID = 'wst.timer.stopAll';
				
				wst.loop(this.intervals, function(id){
					wst.timer.stop(id);
				});
				
				this.clear();
			},
			checkInterval : function(id)
			{
				var wstFnID = 'wst.timer.checkInterval';
				var index = typeof id != 'undefined' ? id : wst.timer.history.length - 1;
				
				if(wst.timer.intervals[id] == true)
				{
					wst.timer.check(id);
					setTimeout(wst.timer.checkInterval, 10, id);
				}
			},
			check : function(id)
			{
				var wstFnID = 'wst.timer.check';
				var index = typeof id != 'undefined' ? id : this.history.length - 1;
				var time1 = this.history[index].init;
				var time2 = (new Date()).getTime();
				var diff = (time2 - time1) / 1000;
				this.history[index].elapsed = diff;
				this.elapsed = diff;
				
				return diff;
			},
			clear : function()
			{
				var wstFnID = 'wst.timer.clear';
				this.init = null;
				this.end = null;
				this.elapsed = null;
			}
		},
		/*********************
		* @ TIMEOUT OBJECT @ *
		*********************/
		// Usages:
		// Ex. 1: wst.timeout(window, 'alert', 2000, 'Test example');
		// Ex. 2: wst.timeout(alert, 2000, 'Test example');
		timeout : wst.extend(
			function(object, fn, time)
			{
				var wstFnID = 'wst.timeout';
				var args, parent;
				var id = wst.timeout.timers.length;
				
				if(!wst.ok(time) || (typeof time != 'number' && arguments.length >= 3))
				{
					args = wst.array(arguments).slice(2) || [];
					time = fn;
					fn = object;
					object = null;
				}
				else
				{
					args = wst.array(arguments).slice(3);
				}
				
				parent = object || window;
				
				wst.timeout.timers[id] = setTimeout(function(){
					if(object)
						object[fn].apply(parent, args);
					else
						wst.apply(fn, args, parent);
					
					wst.timeout.clear(id);
				}, time);
				
				return id;
			}, {
				timers : [],
				update : function(id)
				{
					var wstFnID = 'wst.timeout.update';
					
					return wst.timeout;
				},
				remove : function(id)
				{
					var wstFnID = 'wst.timeout.remove';
					
					if(wst.ok(id))
					{
						wst.timeout.timers[id] = null;
						delete wst.timeout.timers[id];
					}
					
					return wst.timeout;
				},
				clear : function(id)
				{
					var wstFnID = 'wst.timeout.clear';
					
					if(wst.ok(id))
						clearTimeout(wst.timeout.timers[id]);
					
					return wst.timeout;
				}
			}
		),
		/*****************
		* @ LOG OBJECT @ *
		*****************/
		log : {
			add : function(log, name, msg)
			{
				var wstFnID = 'wst.log.add';
				
				if(this.enabled)
				{
					if(this[log] && this[log].enabled)
					{
						if(wst.modules.date ? !wst.modules.date.loaded : false)
						{
							if(wst.modules.load('date') === false)
								return false;
						}
						
						var now = new Date();
						var time = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
						var date = wst.date();
						this[log].entries.push(date + ': ' + name + ' - ' + msg);
					}
					else if(!this[log])
					{
						wst.error(log + wst.messages.functions.logAdd);
					}
				}
			},
			clear : function(log)
			{
				var wstFnID = 'wst.log.clear';
				
				if(this[log])
					this[log].entries = [];
			},
			enabled : false, // must be disabled during the page load
			errors : {
				enabled : true,
				entries : []
			},
			dom : {
				enabled : false,
				entries : []
			},
			common : {
				enabled : true,
				entries : []
			},
			events : {
				enabled : true,
				entries : []
			}
		},
		/*******************
		* @ CACHE OBJECT @ *
		*******************/
		/*
			object syntax
			
			wst.cache = {
				contents : {
					IDExpression : {
						common : object,	// default
						event : object,
						shadow : object,
						...
					}
				},
				methods ...
			}
		*/
		cache : {
			enabled : true,
			contents : {},
			iterator : 0,
			id : function(expr, add)
			{
				var wstFnID = 'wst.cache.id';
				var id = 'wst-cached' + (new Date).getTime() + (this.iterator++);
				add = add == undefined ? true : add;
				
				if(wst.is.dom(expr))
				{
					if(!expr.id && add)
						expr.id = id;
					else
						id = expr.id;
				}
				else if(wst.is.array(expr))
				{
					if(!wst.is.undefined(expr[0]))
					{
						if(!expr[0].id && add)
							expr[0].id = id;
						else
							id = expr[0].id;
					}
				}
				else
				{
					id = expr;
				}
				
				return id;
			},
			add : function(expr, content, type)
			{
				var wstFnID = 'wst.cache.add';
				var id = this.id(expr, true);
				type = type || 'common';
				
				if(this.enabled)
				{
					if(!this.contents[id])
						this.contents[id] = {};
					
					this.contents[id][type] = content;
				}
				
				return this;
			},
			get : function(expr)
			{
				var wstFnID = 'wst.cache.get';
				
				return this.contents[this.id(expr, false)];
			},
			clear : function(expr, type, removeID)
			{
				var wstFnID = 'wst.cache.clear';
				removeID = removeID == undefined ? false : removeID;
				
				if(this.enabled)
				{
					if(expr)
					{
						if(type)
							delete this.contents[this.id(expr, false)][type];
						else
							delete this.contents[this.id(expr, false)];
						
						if(wst.is.dom(expr) && removeID)
							expr.id = '';
					}
					else
					{
						this.contents = [];
					}
				}
				
				return this;
			}
		},
		/*******************
		* @ ARRAY OBJECT @ *
		*******************/
		array : wst.extend(
			function()
			{
				var wstFnID = 'wst.array';
				var arr = [], temp = [];
				var entries = wst.array.create(arguments);
				
				wst.loop(entries, function(){
					temp = temp.concat(!wst.is.array(this) ? wst.array.create(this) : this);
				});
				
				arr = temp;
				return arr;
			}, {
				create : function(newArray, forceLoop)
				{
					var wstFnID = 'wst.array.create';
					var array = [];
					forceLoop = !!forceLoop || false;
					
					if(wst.ok(newArray))
					{
						try{
							// Use Array.prototype.slice whenever possible
							array = Array.prototype.slice.call(newArray);
						}
						catch(err){
							//wst.error(err); // uncomment for debugging purposes
						};
						
						// IE does not accept window object (and some others) do be used in the Array.prototype.slice,
						// and creates an empty array. So we create the array at the simplest way
						if(array.length === 0 && (!wst.is.dom(newArray) || (wst.browser.ie && forceLoop)))
						{
							if(wst.ok(newArray.length))
							{
								var i = -1, len = newArray.length;
								
								while(++i < len)
									array.push(newArray[i]);
							}
							else
							{
								array = [newArray];
							}
						}
						// Brwosers like FF in some cases (eg with DOM elements like "select") returns the newArray fulfilled with "undefined" values.
						// If this happen, we create a new array with the passed value.
						else if(!!wst.regex(array.toString(), '^,*$'))
						{
							array = [newArray];
						}
					}
					
					return array;
				},
				filter : function(array, fn)
				{
					var wstFnID = 'wst.array.filter';
					var resultArray = [];
					
					wst.loop(array, function(key){
						if(wst.apply(fn, [key, array], array[key]) === true)
							 resultArray.push(array[key]);
					});
					
					return  resultArray;
				},
				unique : function(array)
				{
					var wstFnID = 'wst.array.unique';
					var resultArray = [];
					var i = -1, j, len = array.length, current, next, duplicate;
					
					while(current = array[++i])
					{
						j = i;
						duplicate = false;
						
						while(next = array[++j])
						{
							if(current === next)
								duplicate = true;
						}
						
						if(!duplicate)
							resultArray.push(current);
					}
					
					return resultArray;
				},
				values : function(array)
				{
					var wstFnID = 'wst.array.values';
					var key, resultArray = [];
					
					for(key in array)
						resultArray.push(array[key]);
					
					return resultArray;
				},
				keys : function(array)
				{
					var wstFnID = 'wst.array.keys';
					var key, resultArray = [];
					
					for(key in array)
						resultArray.push(key);
					
					return resultArray;
				},
				valid : function(array)
				{
					var wstFnID = 'wst.array.valid';
					
					return wst.is.array(array) ? array.length > 0 : false;
				}
			}
		),
		/****************
		* @ IS OBJECT @ *
		****************/
		is : wst.extend(
			function(expr)
			{
				var wstFnID = 'wst.is';
				
				if(wst.ok(expr))
				{
					var exprConstructor;
					
					try{
						exprConstructor = wst.regex(expr.constructor.toString(), 'function\\s+([^\\(\\s]+)\\s*\\(\\)')[1].toLowerCase();
					}
					catch(err){
						exprConstructor = wst.regex(Object.prototype.toString.call(expr), '\\[(?:object\\s+)?([\\w\\d]*)\\]')[1].toLowerCase();
					};
					
					exprConstructor = (exprConstructor == 'window') || (exprConstructor.search('html') > -1) ? 'object' : exprConstructor;
					exprConstructor = exprConstructor == 'object' && wst.is.dom(expr) ? 'DOMObject' : exprConstructor;
					
					return exprConstructor;
				}
				
				return expr + '';
			}, {
				string : function(expr)
				{
					var wstFnID = 'wst.is.string';
					
					return wst.ok(expr) ? expr instanceof String || this(expr) == 'string' : false;
				},
				number : function(expr)
				{
					var wstFnID = 'wst.is.number';
					
					return wst.ok(expr) ? expr instanceof Number || this(expr) == 'number' : false;
				},
				boolean : function(expr)
				{
					var wstFnID = 'wst.is.boolean';
					
					return wst.ok(expr) ? expr instanceof Boolean || this(expr) == 'boolean' : false;
				},
				fn : function(expr)
				{
					var wstFnID = 'wst.is.fn';
					
					return wst.ok(expr) ? (expr instanceof Function && !this.dom(expr)) : false;
				},
				object : function(expr)
				{
					var wstFnID = 'wst.is.object';
					
					return wst.ok(expr) ? expr instanceof Object : false;
				},
				array : function(expr)
				{
					var wstFnID = 'wst.is.array';
					
					return wst.ok(expr) ? (expr instanceof Array) && (typeof expr.length != 'undefined') : false;
				},
				date : function(expr)
				{
					var wstFnID = 'wst.is.date';
					
					return wst.ok(expr) ? expr instanceof Date : false;
				},
				regexp : function(expr)
				{
					var wstFnID = 'wst.is.regexp';
					
					return wst.ok(expr) ? expr instanceof RegExp : false;
				},
				error : function(expr)
				{
					var wstFnID = 'wst.is.error';
					
					return wst.ok(expr) ? expr instanceof Error : false;
				},
				wst : function(expr)
				{
					var wstFnID = 'wst.is.wst';
					
					return wst.ok(expr) ? expr instanceof wst : false;
				},
				dom : function(expr)
				{
					var wstFnID = 'wst.is.dom';
					
					return wst.ok(expr) ? (typeof expr.nodeName != 'undefined' && (typeof expr.nodeType != 'undefined' ? expr.nodeType != 8 : false)) : false;
				},
				undefined : function(expr)
				{
					var wstFnID = 'wst.is.undefined';
					
					return typeof expr == 'undefined' && expr == undefined;
				}
			}
		),
		apply : function(fn, args, parent)
		{
			var wstFnID = 'wst.apply';
			parent = parent || window;
			args = wst.ok(args) ? (wst.is.array(args) ? args : [args]) : [];
			
			if(fn.apply)
			{
				return fn.apply(parent, args);
			}
			else
			{
				try{
					// Simulate the call method in IE for functions that not allow
					// the method. E.g., we cannot do alert.call,
					// but we can do Function.prototype.call.apply(alert, [window, 'test to alert'])
					return Function.prototype.call.apply(fn, wst.array(parent, args));
				}
				catch(err){
					wst.error(err);
				};
			}
		},
		sleep : function(time)
		{
			var wstFnID = 'wst.sleep';
			var wakeTime = (new Date()).getTime() + time;
			
			while((new Date()).getTime() < wakeTime)
				continue;
		},
		trim : function(str)
		{
			var wstFnID = 'wst.trim';
			return str.replace(wst.regex({expr:'^\\s*|\\s*$', flags:'g'}), '');
		},
		ucf : function(str)
		{
			var wstFnID = 'wst.ucf';
			return str.charAt(0).toUpperCase() + str.slice(1);
		}
	});
	
	/**********************
	* @ ROLLOVER OBJECT @ *
	**********************/
	var rollOver = wst.object.create();
	
	wst.extend(rollOver.prototype, {
		add : function(roll1, roll2)
		{
			var wstFnID = 'wst.rollOver.add';
			var wstRollOver, wstRollOut;
			var wstObject = this.constructor;
			var elements = wstObject.E;
			var cssProperty = !!wst.regex(roll1, '^\\w+:\\s?.+$');
			var attrProperty = !!wst.regex(roll1, '^\\w+\\s?=(\\\'|")\\s?.+\\1?$');
			var whiteSpace = wst.regex({expr:'\\s', flags:'g'});
			var quotes = wst.regex({expr:'\\\'|"', flags:'g'});
			var overState = (!cssProperty && !attrProperty && roll1) || (cssProperty && roll1.replace(whiteSpace, '').split(':')) || (attrProperty && roll1.replace(whiteSpace, '').replace(quotes, '').split('='));
			var outState = (!cssProperty && !attrProperty && roll2) || (cssProperty && roll2.replace(whiteSpace, '').split(':')) || (attrProperty && roll2.replace(whiteSpace, '').replace(quotes, '').split('='));
			
			wst.loop(elements, function(overState, outState, cssProperty){
				if(cssProperty)
				{
					wstRollOver = function(){
						wst.get(this).css(overState[0], overState[1]);
					};
					
					wstRollOut = function(){
						wst.get(this).css(outState[0], outState[1]);
					};
				}
				else if(attrProperty)
				{
					wstRollOver = function(){
						wst.get(this).attr(overState[0], overState[1]);
					};
					
					wstRollOut = function(){
						wst.get(this).attr(outState[0], outState[1]);
					};
				}
				else
				{
					wstRollOver = function(){
						wst.get(this).clss(outState, overState);
					};
					
					wstRollOut = function(){
						wst.get(this).clss(overState, outState);
					};
				}
				
				wst.get(this)
					.listen('mouseover', wstRollOver)
					.listen('mouseout', wstRollOut);
				
				wst.cache.add(this, {over : wstRollOver, out : wstRollOut}, 'rollOver');
			}, [overState, outState, cssProperty]);
			
			return wstObject;
		},
		remove : function()
		{
			var wstFnID = 'wst.rollOver.remove';
			var wstObject = this.constructor;
			var elements = wstObject.E;
			var cached;
			
			wst.loop(elements, function(){
				cached = wst.cache.get(this).rollOver;
				
				if(cached)
				{
					wst.get(this)
						.unListen('mouseover', cached.over)
						.unListen('mouseout', cached.out);
					
					wst.cache.clear(this, 'rollOver');
				}
			});
			
			return wstObject;
		}
	});
	
	wst.extend(wst.proto, {rollOver : rollOver});
	
	wst.extend(wst, {
		/*********************
		* @ BROWSER OBJECT @ *
		*********************/
		Browser : function()
		{
			var wstFnID = 'wst.Browser';
			this.agent = navigator.userAgent;
			this.detect = function(agent)
			{
				var wstFnID = 'wst.Browser.detect';
				var agent = (agent || this.agent).toLowerCase();
				var ids = {
					'msie' : 'ie',
					'opera' : 'op',
					'firefox' : 'ff',
					'seamonkey' : 'sm',
					'safari' : 'sf'
				};
				var name = this.name = wst.regex(agent, 'msie|opera|firefox|seamonkey|safari')[0];
				this.ie = name == 'msie';
				this.op = name == 'opera';
				this.ff = name == 'firefox';
				this.sm = name == 'seamonkey';
				this.sf = name == 'safari';
				
				this.version = wst.regex(agent, name + '(?:\\s|\\/)?(\\d(?:\\.\\d+)*)')[1];
				this.id = ids[name] || null;
				this.gecko = !!wst.regex(agent, 'gecko');
				this.webkit = !!wst.regex(agent, 'webkit');
				this.js = navigator.javaEnabled();
				this.os = wst.regex(agent, 'windows|linux|mac')[0];
				// check for windows vista (WIN NT >= 6)
				this.os = this.os == 'windows' ?
					parseInt(wst.regex(agent, 'nt (\\d)')[1]) > 5 ? 'windows vista' : this.os
					: this.os;
			};
			
			this.detect();
		},
		/********************
		* @ REGEXP OBJECT @ *
		********************/
		Regex : function(source)
		{
			var wstFnID = 'wst.Regex';
			this.source = source || false;
			this.str = '';
			this.matches = false;
			this.test = false;
			this.object = false;
			this.flags = '';
			
			this.create = function(source, flags)
			{
				var wstFnID = 'wst.Regex.create';
				this.object = false;
				this.source = source || this.source;
				this.flags = flags || this.flags;
				
				if(this.source)
					this.object = new RegExp(this.source, this.flags);
				
				return this.object;
			};
			
			this.run = function(str, source, flags)
			{
				var wstFnID = 'wst.Regex.run';
				this.source = source || this.source;
				this.str = str || this.str;
				this.flags = flags || this.flags;
				
				if((!this.object && this.source && this.str) || this.object.source != this.source)
				{
					if(typeof this.source == 'string')
					{
						this.create();
					}
					else
					{
						this.object = this.source;
						this.source = this.object.source;
					}
				}
				
				if(this.object)
				{
					this.test = this.object.test(this.str);
					this.matches = this.object.exec(this.str);
				}
				else
				{
					this.test = false;
					this.matches = false;
				}
				
				return this.matches;
			};
			
			if(this.source)
				this.create();
		}
	});
	
	/* ------------------------------------------------------------------------------------------------
													CONFIG
	------------------------------------------------------------------------------------------------ */
	wst.extend(wst, {
		version : '1.1',
		E : [],
		total : 0, // we use total because length turns the object into an array, wich causes an error
		imagesLoaded : [],
		documentLoaded : false,
		onDocumentLoad : function()
		{
			var wstFnID = 'wst.onDocumentReady';
			
		},
		translate : {
			HTML : {
				attributes : {
					'class' : 'className',
					'colspan' : 'colSpan',
					'rowspan' : 'rowSpan',
					'for' : 'htmlFor'
				}
			}
		},
		/*******************
		* @ CORE OBJECT @ *
		*******************/
		core : {
			alertErrors : true,
			exposeBaseDir : true,
			instances : [],
			mode : 'strict', // avaiable values: strict, quirk
			runningAt : (function(){
				return window.location.protocol == 'file:' ? 'localFileSystem' : 'server';
			})(),
			_getWSTDir : function()
			{
				var wstFnID = 'wst.core._getWSTDir';
				
				if(wst.core.exposeBaseDir)
				{
					var dir = '';
					
					wst.get('script[src]').loop(function(){
						var path = wst.get(this).attr('src');
						
						if(path.indexOf('wst.core') > -1)
						{
							dir = (path.split('wst.core'))[0];
							return false;
						}
					});
					
					return dir;
				}
				
				return '';
			},
			_getCaller : function()
			{
				var wstFnID = 'wst.core._getCaller';
				var callerFn = arguments.callee.caller, anonymous = false, name = '', callerBody, matched;
				var nameRegex = 'wstFnID\\s*=\\s*(?:\\\'|")([^\\\'|"]*)(?:\\\'|")';
				var userFn = arguments[0];
				
				try{
					if(!userFn)
					{
						while(callerFn = callerFn.arguments.callee.caller)
						{
							callerBody = callerFn.toString();
							
							if(callerBody.indexOf('wstFnID') > -1)
							{
								name = wst.regex(callerBody, nameRegex)[1] || '';
								break;
							}
							else
							{
								name = callerFn.name || '';
							}
							
							anonymous = true;
						}
					}
					else
					{
						callerBody = userFn.toString();
						
						if(callerBody.indexOf('wstFnID') > -1)
						{
							name = wst.regex(callerBody, nameRegex)[1] || '';
						}
						else
						{
							name = callerFn.name || '';
							anonymous = true;
						}
					}
				}
				catch(err){
					anonymous = true;
				};
				
				name = anonymous ? '(anonymous) ' + name : name;
				return name;
			},
			_duplicateWST : function(instance)
			{
				var wstFnID = 'wst.core._duplicateWST';
				var newWST = new wst;
				var uid = newWST.uid;
				instance = instance || wst.core.instances.slice(-1)[0];
				
				// copy the object
				wst.extend(newWST, instance);
				
				// parent objects for internal functions
				// wst children object
				newWST.children.constructor = newWST;
				
				// wst opacity object
				if(newWST.opacity)
					newWST.opacity.constructor = newWST;
				
				// wst rollOver object
				if(newWST.rollOver)
					newWST.rollOver.constructor = newWST;
				
				newWST.uid = uid;
				
				return newWST;
			}
		},
		/*********************
		* @ MODULES OBJECT @ *
		*********************/
		modules : {
			// By default the dynamic load is made with Ajax. In this case the wst.Ajax module
			// already must to be loaded. Otherwise, the load is made with the "standard" mode, with
			// a script element. The better choice is Ajax.
			load : function(module, ajaxLoad)
			{
				var wstFnID = 'wst.modules.load';
				var customModule = module.split('/').slice(-1)[0].replace('.js', '');
				
				if(wst.ok(this[module]) ? !this[module].loaded : this[customModule] ? !this[customModule].loaded : true)
				{
					ajaxLoad = ajaxLoad || true;
					var logDomEnabled = wst.log.dom.enabled;
					wst.log.dom.enabled = false;
					var moduleSrc = this[module] ? wst.core.baseDir + this[module].src : module;
					
					if(wst.ok(wst.load) && ajaxLoad)
					{
						var moduleContent = wst.load(moduleSrc);
						var status = wst.ajax.stats.list.status.slice(-1)[0];
						
						if(status == 200)
						{
							if(this[module])
								this[module].loaded = true;
							else
								this[customModule] = {loaded : true, src : moduleSrc};
							
							var script = wst.cE('<script type="text/javascript"></script>');
							script.text = moduleContent;
							wst.get('head').append(script);
						}
						else
						{
							var err = '';
							
							switch(status)
							{
								case 404:
									err = '404: ' + module + wst.messages.functions.modulesLoad404;
									break;
								case 500:
									err = '500: ' + wst.messages.functions.modulesLoad500 + module;
									break;
								default:
									err = (status || '-001') + ': ' + wst.messages.functions.modulesLoadDefault + module;
									break;
							}
							
							wst.error(err);
						}
						
						wst.log.dom.enabled = logDomEnabled;
					}
					else
					{
						var wstFnCaller = arguments.callee.caller,
							wstArgsCaller = wstFnCaller.arguments,
							wstThisCaller = wstArgsCaller.callee.caller;
						var scriptEvt = wst.browser.ie ? 'readystatechange' : 'load';
						var script = wst.cE('<script src="' + moduleSrc + '" type="text/javascript"></script>');
						
						wst.listen(script, scriptEvt, function(){
							if(scriptEvt == 'readystatechange' ? this.readyState == 'complete' : true)
							{
								if(wst.modules[module])
									wst.modules[module].loaded = true;
								else
									wst.modules[module.split('/').slice(-1)[0]] = {loaded : true, src : moduleSrc};
								
								wstFnCaller.apply(wstThisCaller, wstArgsCaller);
							}
						});
						
						wst.get('head').append(script);
						wst.log.dom.enabled = logDomEnabled;
						
						return false;
					}
				}
			},
			// Must to be called before the page load event
			loadAll : function()
			{
				var wstFnID = 'wst.modules.loadAll';
				var module, modules = this;
				
				wst.loop(modules, function(module){
					if(this.autoLoad && !this.loaded)
					{
						if(!wst.documentLoaded)
						{
							wst.include(wst.core.baseDir + this.src);
							wst.modules[module].loaded = true;
						}
						else
						{
							wst.modules.load(module);
						}
					}
				});
			}
		}
	});
	
	/* ------------------------------------------------------------------------------------------------
													PROTOTYPE
	------------------------------------------------------------------------------------------------ */
	// Array
	wst.extend(Array.prototype, {loop : wst.loop});
	
	// wst
	wst.extend(wst.proto, {
		version : wst.version,
		uid : 0,
		E : [],
		total : wst.total,
		expr : '',
		alertErrors : wst.core.alertErrors,
		validObject : wst.validObject,
		valid : wst.valid,
		dom : wst.dom,
		get : wst.get,
		lookup : wst.dom.lookup,
		at : wst.dom.at,
		first : wst.dom.first,
		last : wst.dom.last,
		parent : wst.parent,
		next : wst.next,
		prev : wst.prev,
		siblings : wst.siblings,
		children : wst.children,
		filter : wst.dom.filter,
		index : wst.dom.index,
		sort : wst.dom.sort,
		equals : wst.dom.equals,
		tag : wst.dom.tag,
		type : wst.dom.type,
		value : wst.dom.value,
		append : wst.dom.append,
		appendTo : wst.dom.appendTo,
		remove : wst.dom.remove,
		after : wst.dom.after,
		before : wst.dom.before,
		replace : wst.dom.replace,
		clone : wst.dom.clone,
		content : wst.dom.content,
		clear : wst.dom.clear,
		attr : wst.dom.attr,
		css : wst.dom.css,
		clss : wst.dom.clss,
		pos : wst.pos,
		scrollView : wst.scrollView,
		show : wst.show,
		hide : wst.hide,
		buildSelect : wst.buildSelect,
		listen : wst.event.listen,
		unListen : wst.event.unListen,
		loaded : wst.loaded,
		ready : wst.ready,
		blockKey : wst.blockKey,
		onlyNumbers : wst.onlyNumbers,
		disableRightClick : wst.disableRightClick,
		setMask : wst.setMask,
		getSelectionPos : wst.getSelectionPos,
		setSelectionPos : wst.setSelectionPos,
		loop : wst.loop,
		on : function(evtType, opt)
		{
			var wstFnID = 'wst.on';
			
			if(this.total > 0)
			{
				if(wst.is.fn(opt))
				{
					this.listen(evtType, opt);
				}
				else
				{
					if(wst.ajax.action)
						wst.ajax.action(this, evtType, opt);
				}
			}
			
			return this;
		}
	});
	
	wst.extend(wst, {
		listen : wst.event.listen,
		unListen : wst.event.unListen,
		browser : (new wst.Browser())
	});
	
	wst.extend(wst.core, {
		baseDir : wst.core._getWSTDir()
	});
	
	/* ------------------------------------------------------------------------------------------------
											INTERNAL FUNCTIONS
	------------------------------------------------------------------------------------------------ */
	var wstOnDocumentReady = function(){
		var wstFnID = 'wstOnDocumentReady';
			
		wst.log.enabled = false;
		wst.documentLoaded = true;
		wst.apply(wst.onDocumentLoad, document);
	};
	
	var wstOnError = function(){
		var alertErrors = wst.core.alertErrors;
		wst.core.alertErrors = false;
		wst.error.apply(this, arguments);
		wst.core.alertErrors = alertErrors;
	};
	
	wst.get(document)
		.ready(wstOnDocumentReady)
		.listen('error', wstOnError);
})();
