//////////////////// *LIBRARY ////////////////////
var Library = {
	ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
	loadScript: function(path){
		var head = document.getElementsByTagName('head')[0];
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.src = path;
		head.appendChild(script);
	}
}

//////////////////// *JS_EXTENSION ////////////////////
String.prototype.stripScripts = function(){
	return this.replace(new RegExp(Library.ScriptFragment, 'img'), '');
}
String.prototype.evalScripts = function(){
	var matchAll = new RegExp(Library.ScriptFragment, 'img');
	var matchOne = new RegExp(Library.ScriptFragment, 'im');
	var matches = this.match(matchAll);
	if(matches != undefined && matches.length){
		try {
			for(var i=0; i<matches.length; i++)
				eval(matches[i].match(matchOne)[1]);
		} catch(e){
			if(Page.isDev){
				alert('problem evaluating script...');
				for(var i in e){
					alert(i+': '+e[i]);
				}
			}
		}
	}
}
String.prototype.replaceAll = function(str1,str2,replaceCreated){
	if (replaceCreated) {
		var str = this;
		while(str.indexOf(str1) != -1)
			str = str.replace(str1,str2);
		return str;
	} else {
		return this.split(str1).join(str2);
	}
}
String.prototype.trim = function(inner){
	var str = this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, '$1');
	if (inner)
		str = str.replaceAll('  ',' ',true);
	return str;
}
String.prototype.left = function(n){
	if (n <= 0)
		return "";
	else if (n > this.length)
		return this;
	else
		return this.substring(0,n);
}
String.prototype.right = function(n){
    if (n <= 0)
       return "";
    else if (n > this.length)
       return this;
    else {
       var iLen = this.length;
       return this.substring(iLen, iLen - n);
    }
}
Array.prototype.indexOf = function(obj){
	for(var i=0; i<this.length; i++)
		if(this[i] == obj) return i;
	return -1;
}

//////////////////// *CLIENT ////////////////////
var Client = {
	viewportWidth: function(){
		return (document.width !== undefined) ? document.width+100 : document.body.offsetWidth+100;
	},
	viewportHeight: function(){
		return (document.height !== undefined) ? document.height+100 : document.body.offsetHeight+100;
	},
	viewportSize: function(){
		return { width: this.viewportWidth(), height: this.viewportHeight() };
	}
};

//////////////////// *PAGE ////////////////////
var Page = {
	isDev: false,
	blackOut: function(){
		var DebugDiv = Elem.create('div',{className: 'DebugDiv'});
		var DebugDivBG = Elem.create('div',{className: 'DebugDivBG'});
		DebugDivBG.style.height = Client.viewportHeight()+'px';
		DebugDivBG.style.width = Client.viewportWidth()+'px';
		Elem.append(DebugDiv,DebugDivBG);
		Elem.prepend(document.body,DebugDiv);
	},
	showDebugMsg: function(msg){
		var DebugDiv = Elem.create('div',{className: 'DebugDiv'});
		
		var DebugDivBG = Elem.create('div',{className: 'DebugDivBG'});
		Elem.append(DebugDiv,DebugDivBG);
		
		var DebugDivBox = Elem.create('div',{className: 'DebugDivBox',innerHTML: msg});
		Elem.append(DebugDiv,DebugDivBox);
		
		var DebugDivX = Elem.create('div',{className: 'DebugDivX'});
		DebugDivX.onmousedown = function(){
			Elem.remove(this.parentNode.parentNode);
		}
		Elem.prepend(DebugDivBox,DebugDivX);
		
		Elem.prepend(document.body,DebugDiv);
	},
	disableSubmits: function(){
		var elems = document.body.getElementsByTagName('input');
		for(var i=0; i<elems.length; i++){
			if(elems[i].getAttribute('type') == 'submit' || elems[i].getAttribute('type') == 'reset')
				elems[i].disabled = true;
		}
	},
	enableSubmits: function(){
		var elems = document.body.getElementsByTagName('input');
		for(var i=0; i<elems.length; i++){
			if(elems[i].getAttribute('type') == 'submit' || elems[i].getAttribute('type') == 'reset')
				elems[i].disabled = false;
		}
	}
}

//////////////////// *CLASS ////////////////////
var Class = {
	create: function(){
		return function(){
			this.init.apply(this, arguments);
		}
	},
	extend: function(parent,child){
		child._super = parent;
		for(var i in parent){
			if(!child[i]) child[i] = parent[i];
			else(child[i+'_base']) = parent[i];
		}
		return child;
	}
}

//////////////////// *TRY ////////////////////
var Try = {
	these: function(){
		var r = false;
		for(var i=0; i<arguments.length; i++){
			try {
				r = arguments[i]();
				break;
			}catch(e){}
		}
		return r;
	}
}

//////////////////// *EVENT ////////////////////
// Mozilla has an Event object, ie is gay and does not.
if(!Event){
	var Event = {};
}
Event = Class.extend(Event,{
	pageLoaded: false,
	observe: function(obj,e,func){
		obj = $(obj);
		if(obj.attachEvent){
			obj.attachEvent('on'+e,func);
		} else if(obj.addEventListener){
			obj.addEventListener(e,func,false);
		}
	},
	stop: function(e,dontPreventDefault){
		if(e.preventDefault){
			e.stopPropagation();
			if(!dontPreventDefault)
				e.preventDefault();
		} else {
			if(!dontPreventDefault)
				e.returnValue = false;
			e.cancelBubble = true;
		}
	},
	getModifiers: function(e){
		return {
			ALT: e.altKey,
			CTRL: e.ctrlKey,
			SHIFT: e.shiftKey
		}
	}
});


//////////////////// *ELEM ////////////////////
var Elem = {
	create: function(tag,init){
		var elem = document.createElement(tag);
		if(init){
			for(var i in init){
				if(i == 'attributes'){
					for(var j in init[i]) elem.setAttribute(j,init[i][j]);
				} else {
					elem[i] = init[i];
				}
			}
		}
		return elem;
	},
	remove: function(elem){
		elem = $(elem);
		elem.parentNode.removeChild(elem);
	},
	get: function(tag,parent,matchObj){
		if(!tag) tag = '*';
		if(!parent) parent = document;
		else parent = $(parent);
		var elems = parent.getElementsByTagName(tag);
		var r = [];
		if(!matchObj) r = elems;
		for(var i=0; i<elems.length; i++){
			var elem = elems[i];
			for(var j in matchObj){
				if(j == 'attributes'){
					for(var k in matchObj[j]){
						if(elem.getAttribute(k) == matchObj[j][k]){
							r.push(elem);
							break;
						}
					}
				} else {
					if(j == 'className'){
						if(Elem.hasClassName(elem,matchObj[j])){
							r.push(elem);
							break;
						}
					} else if(elem[j] == matchObj[j]){
						r.push(elem);
						break;
					}
				}
			}
		}
		return r;
	},
	addClassName: function(elem,c){
		elem = $(elem);
		if(elem.className == undefined) return;
		if(!Elem.hasClassName(elem,c)) elem.className = elem.className + ' ' + c;
	},
	removeClassName: function(elem,c){
		elem = $(elem);
		if(elem.className == undefined) return;
		var cArr = elem.className.split(' ');
		for(var i=0; i<cArr.length; i++){
			if(cArr[i] == c){
				cArr.splice(i,1);
				break;
			}
		}
		elem.className = cArr.join(' ');
	},
	hasClassName: function(elem,c){
		elem = $(elem);
		if(!elem.className) return;
		var cArr = elem.className.split(' ');
		var has = false;
		for(var i=0; i<cArr.length; i++){
			if(cArr[i] == c){
				has = true;
				break;
			}
		}
		return has;
	},
	toggleClassName: function(elem,c){
		if($(elem).className == undefined) return;
		Elem[Elem.hasClassName(elem,c) ? 'removeClassName' : 'addClassName'](elem,c);
	},
	update: function(elem,html,evalScripts){
		elem = $(elem);
		elem.innerHTML = html.stripScripts();
		if(evalScripts || evalScripts == undefined){
			setTimeout(function(){html.evalScripts()}, 10);
		}
	},
	empty: function(elem){
		elem = $(elem);
		try {
			elem.innerHTML = '';
		} catch(e) {
			var elems = elem.getElementsByTagName('*');
			for(var i=0; i<elems.length; i++){
				elem.removeChild(elems[i]);
			}
		}
	},
	prepend: function(elem,node){
		elem = $(elem);
		elem.insertBefore(node,elem.firstChild);
	},
	append: function(elem,node){
		elem = $(elem);
		elem.appendChild(node);
	},
	setOpacity: function(elem,opacity){
		elem = $(elem);
		elem.style.opacity = opacity/100;
		elem.style.filter = 'alpha(opacity='+opacity+')';
	},
	visible: function(elem){
		return $(elem).style.display != 'none';
	},
	toggle: function(){
		for(var i=0; i<arguments.length; i++){
			var elem = $(arguments[i]);
			Elem[Elem.visible(elem) ? 'hide' : 'show'](elem);
		}
	},
	hide: function(){
		for(var i=0; i<arguments.length; i++)
			$(arguments[i]).style.display = 'none';
	},
	show: function(){
		for(var i=0; i<arguments.length; i++)
			$(arguments[i]).style.display = '';
	},
	getChildren: function(elem){
		elem = $(elem);
		if(elem.children) return elem.children;
		var elems = [];
		var c = elem.childNodes;
		for(var i=0; i<c.length; i++){
			var n = c[i];
			if(n.nodeName != '#text') elems.push(n);
		}
		return elems;
	},
	getLastChild: function(elem){
		elem = $(elem);
		var lastChild = elem.lastChild;
		while(lastChild.nodeName == '#text')
			lastChild = lastChild.previousSibling;
		return lastChild;
	}
}

//////////////////// *FORM ////////////////////
var Form = {
	getForm: function(frm){
		if(frm) frm = $(frm);
		else if(document.forms[0]) frm = document.forms[0];
		return frm;
	},
	addSubmitEvent: function(frm,func){
		Event.observe(frm,'submit',func);
	},
	allowAutoFocus: true,
	focusFirstElement: function(){
		if(Form.allowAutoFocus){
			for(var i=0; i<document.forms.length; i++){
				var frm = document.forms[i];
				if(frm && frm.elements && frm.elements.length){
					for(var j=0; j<frm.elements.length; j++){
						var input = frm.elements[j];
						if(input.type != 'hidden' && input.type != 'reset' && input.type != 'submit' && input.type != 'button' && input.getAttribute('disallowautofocus') == null && Elem.visible(input)){
							try {
								input.focus();
								return;
							}catch(e){
							}
						}
					}
				}
			}
		}
	},
	serializeToObject: function(frm){
		frm = Form.getForm(frm);
		var obj = {};
		if(frm && frm.length){
			for(var i=0; i<frm.length; i++){
				var input = frm[i];
				if(!this.serializedInputs[input.name])
					obj[input.name] = this.serializeInput(input);
				this.serializedInputs[input.name] = true;
			}
			this.serializedInputs = {};
			return obj;
		}
	},
	serialize: function(frm){
		var obj = Form.serializeToObject(frm);
		str = '';
		for(var i in obj){
			str += i + '=' + encodeURIComponent(obj[i]) + '&';
		}
		return str;
	},
	serializedInputs: {},
	serializeInput: function(input){
		input = $(input);
		if(input.value == undefined) return;
		
		var str = '';
		
		if(input.type == 'checkbox'
		   || (input.type == 'select' && input.multiple)){
			var values = [];
			for(var i=0; i<input.form[input.name].length; i++){
				var subinput = input.form[input.name][i];
				if(subinput.type == 'checkbox' && subinput.checked)
					values.push(input.form[input.name][i].value);
				else if(subinput.type == 'select' && subinput.selected)
					values.push(input.form[input.name][i].value);
			}
			str = values.join(',');
		} else {
			str = input.value;
		}
		
		return str;
	},
	validate: function(frm){
		var retVal = true;
		var errFieldsArr = new Array();
		for(var i=0; i<frm.elements.length; i++){
			if(Form.validateInput(frm.elements[i],true) == false) {
				return false;
			}
		}
		return true;
	},
	validateInput: function(input,applyfocus,ignoreskipvalidation){
		input = $(input);
		
		// added so you can have little ajax forms within your main form and safely ignore their validation messages when submitting the outer form
		if(input.getAttribute('skipvalidation') != undefined && !ignoreskipvalidation){
			return true;
		}
		
		var required = input.getAttribute('required');
		required = required == 1 ? true : false;
		if(input.type == 'checkbox') required = false;
		
		var validation = input.getAttribute('validation');
		if(validation == '' || validation == ' ' || validation == null) validation = 'required';
		if(input.type != 'text' && input.type != 'textarea') validation = 'required';
		validation = validation.toLowerCase();
		
		var value = "";
		var valid = true;
		
		if(input.type == 'radio' || input.type == 'checkbox'){
			if(required)
				valid = false;
			else
				valid = true;
			if(input.checked) value = input.value;
			for(var i=0; i<input.form.elements.length; i++){
				var cinput = input.form.elements[i];
				if(cinput.name == input.name && cinput.checked){
					valid = Valid[validation](cinput.value,required);
					break;
				}
			}
		} else {
			value = input.value;
			valid = Valid[validation](value,required);
		}
		
		if(!input.form.errormsgs) input.form.errormsgs = {};
		if(!valid){
			// slap up an error message
			if(!input.form.errormsgs[input.name]){
				var msg = Form.errorMessage(input.getAttribute('message'),validation,input);
				Elem.addClassName(input,'invalid');
				input.form.errormsgs[input.name] = Elem.create('span',{className:'inputerror',innerHTML:msg})
				Elem.append(input.parentNode,input.form.errormsgs[input.name]);
			}
			if(applyfocus && Elem.visible(input)){
				try {
					input.focus();
				}catch(e){
				}
			}
			return false;
		}
		
		if(input.form.errormsgs[input.name]){
			// remove error message if it exists - the user fixed the input
			Elem.removeClassName(input,'invalid');
			Elem.remove(input.form.errormsgs[input.name]);
			input.form.errormsgs[input.name] = false;
		}
		
		return true;
	},
	errorMessage: function(msg,validation,input){
		if(msg == undefined || msg == null){
			switch(validation){
				case 'numeric':
					msg = 'Please enter a valid number.';
					break;
				case 'integer':
					msg = 'Please enter a valid whole number.';
					break;
				case 'email':
					msg = 'Please enter a valid email address.';
					break;
				case 'phone':
					msg = 'Please enter a valid US phone number.';
					break;
				case 'zip':
					msg = 'Please enter a valid US Zip Code.';
					break;
				case 'ssn':
					msg = 'Please enter a valid social security number or TIN (<i>nnn-nn-nnnn</i> or <i>nn-nnnnnnn</i>).';
					break;
				case 'guid':
					msg = 'Please enter a valid GUID.';
					break;
				case 'uuid':
					msg = 'Please enter a valid UUID.';
					break;
				case 'date':
					msg = 'Please enter a date in this format: m/d/yyyy';
					//msg = 'Please enter a date in one of these formats: yyyy-mm-dd &nbsp;&nbsp; mmddyy &nbsp;&nbsp; m/d/yy &nbsp;&nbsp; m/d/yyyy &nbsp;&nbsp; m-d-yy &nbsp;&nbsp; m-d-yyyy';
					break;
				default:
					msg = 'Please fill all required fields ('+input.name+').';
					break;
			}
		}
		return msg;
	},
	hideSelects: function(){
		if(!document.getElementById || !document.all) return false;
		for(var i=0; i<document.forms.length; i++){
			var frm = document.forms[i];
			for(var j=0; j<frm.elements.length; j++){
				var input = frm.elements[j];
				if(input.type.indexOf('select') != -1) input.style.visibility = "hidden";
			}
		}
	},
	showSelects: function(){
		if(!document.getElementById || !document.all) return false;
		for(var i=0; i<document.forms.length; i++){
			var frm = document.forms[i];
			for(var j=0; j<frm.elements.length; j++){
				var input = frm.elements[j];
				if(input.type.indexOf('select') != -1) input.style.visibility = "visible";
			}
		}
	},
	checkAll: function(name){
		var frm = $(name).form;
		var field = frm[name];
		for(var i=0; i<field.length; i++)
			field[i].checked = true;
	},
	uncheckAll: function(name){
		var frm = $(name).form;
		var field = frm[name];
		for(var i=0; i<field.length; i++)
			field[i].checked = false;
	}
}


//////////////////// *INPUT ////////////////////
var Input = {
	removeOptions: function(input){
		input = $(input);
		input.length = 0;
		return true;
	},
	addOption: function(input,label,value){
		input = $(input);
		input.length++;
		input.options[input.length-1].text = label;
		input.options[input.length-1].value = value;
		return true;
	},
	validateLength: function(input,maxlength){
		input = $(input);
		if(input.value.length > maxlength) input.value = input.value.substr(0,maxlength);
		var valspan = $(input.name+'_indicator');
		if(valspan != undefined && valspan != null)
			Elem.update(valspan,(maxlength-input.value.length)+' characters remaining.');
	},
	// this function is not complete - need to add support for all input types
	// right now it's just button,text,password,submit
	create: function(type,name,value,init){
		var type = type.toLowerCase();
		var str = '';
		var optionalAttrs = '';
		if(init == undefined) init = {};
		var csstype = 'text';
		if(type == 'button' || type == 'submit' || type == 'reset')
			csstype = 'button';
		for(var i in init){
			if(i != 'options' && i != 'checked' && typeof init[i] != 'function' && typeof init[i] != 'object'){
				optionalAttrs += ' '+i+'="'+init[i]+'"';
			} else if(i == 'checked'){
				if(init[i] == true)
					optionalAttrs += ' checked="checked"';
			}
		}
		switch(type){
			case 'button':
			case 'text':
			case 'password':
			case 'submit':
			case 'reset':
			case 'checkbox':
			case 'hidden':
				str = '<input type="'+type+'" name="'+name+'" id="'+name+'" value="'+value+'" class="'+csstype+'"';
				str += optionalAttrs;
				str += '/>';
				break;
			case 'textarea':
				str = '<textarea name="'+name+'" id="'+name+'" class="'+csstype+'"';
				str += optionalAttrs;
				str += '>'+value+'</textarea>';
				break;
			case 'select':
			case 'selectmultiple':
				str = '<select';
				if(type == 'selectmultiple')
					str += ' multiple="multiple"';
				str += ' name="'+name+'" id="'+name+'"';
				str += optionalAttrs;
				str += '>';
				if(!init.options) init.options = [];
				for(var i=0; i<init.options.length; i++){
					var opt = init.options[i];
					var val = opt;
					var lab = opt;
					if(typeof opt == 'object'){
						val = opt.value;
						lab = opt.label;
					}
					str += '<option value="'+val+'"';
					if(value == val)
						str += ' selected="selected"';
					str += '>'+lab+'</option>';
				}
				str += '</select>';
				break;
			case 'checkboxgroup':
			case 'radiogroup':
				for(var i=0; i<init.options.length; i++){
					var opt = init.options[i];
					var val = opt;
					var lab = opt;
					if(typeof opt == 'object'){
						val = opt.value;
						lab = opt.label;
					}
					str += '<input type="'+(type=='checkboxgroup' ? 'checkbox' : 'radio')+'" name="'+name+'" id="'+name+'" value="'+val+'"'
					if(value == val)
						str += ' checked="checked"';
					str += ' /> '+lab+'<br />';
				}
				break;
		}
		return str;
	}
}


//////////////////// *COOKIES ////////////////////
var Cookie = {
	create: function(name,value,days,d,p){
		var expires = '';
		var domain = '';
		var path = '';
		
		if (days){
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			expires = "; expires="+date.toGMTString();
		}
		if(d)
			domain = "; domain="+d;
		if(p)
			path = "; path="+p;
		else
			path = "; path=/";
		
		document.cookie = name+"="+value+expires+domain+path;
	},
	read: function(name){
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++)
		{
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}
}

//////////////////// *AJAX ////////////////////
var Ajax = Class.create();
Ajax.getTransport = function(){
	return Try.these(
		function(){return new ActiveXObject('Msxml2.XMLHTTP')},
		function(){return new ActiveXObject('Microsoft.XMLHTTP')},
		function(){return new XMLHttpRequest()}
	) || false;
}
Ajax.getCFC = function(cfc,method){
	return cfc+'?method='+method+'&ts='+new Date().getTime();
}
Ajax.getLoadingMsg = function(msg){
	if(!msg) msg = 'Loading..';
	return '<p class="message loading">'+msg+'</p>';
}
Ajax.prototype = {
	init: function(url,params){
		this.method = params.method || "get";
		this.method = this.method.toLowerCase();
		this.args = params.args || {};
		this.success = params.success || function(){};
		this.error = params.error || function(xhr){
			//Page.showDebugMsg('<h2>Asynchronous Request Error</h2>'+xhr.responseText);
			Elem.update(this.container,'<h2>Asynchronous Request Error</h2>'+xhr.responseText);
		};
		this.evalScripts = params.evalScripts || true;
		if(typeof this.args == 'object'){
			var paramstring = "";
			for(var i in this.args){
				if(typeof this.args[i] != 'object' && typeof this.args[i] != 'function')
					paramstring += i+"="+encodeURIComponent(this.args[i])+"&";
			}
		}
		this.container = params.container || false;
		this.XHR = Ajax.getTransport();
		//this.XHR.setRequestHeader('X-Requested-With','XMLHttpRequest');
		var me = this;
		this.XHR.onreadystatechange = function(){me.checkState()};
		if(this.method == 'get'){
			if(url.indexOf('?') != -1)
				url += '&';
			else
				url += '?';
			url += paramstring;
		}
		this.XHR.open(this.method, url, true);
		if(this.method == 'post') this.XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		this.XHR.send(paramstring);
	},
	checkState: function(){
		if(this.XHR.readyState == 4){
			if(this.XHR.status == 200){
				if(this.container) Elem.update(this.container,this.XHR.responseText,this.evalScripts);
				this.success(this.XHR);
				return;
			}
			this.error(this.XHR);
		}
	}
}

//////////////////// *VALIDATION ////////////////////
var Valid = {
	required: function(value,required){
		if((value == null || !value.length || value == ' ') && required) return false;
		return true;
	},
	numeric: function(value,required){
		var requiredvalid = Valid.required(value,required);
		if(requiredvalid && value.length) return !isNaN(value);
		else return requiredvalid;
	},
	integer: function(value,required){
		var requiredvalid = Valid.required(value,required);
		if(requiredvalid && value.length) return Valid.regex(value, /^[0-9]+$/, required);
		else return requiredvalid;
	},
	email: function(value,required){
		return Valid.regex(value, /^[a-zA-Z_0-9-'\+~]+(\.[a-zA-Z_0-9-'\+~]+)*@([a-zA-Z_0-9-]+\.)+[a-zA-Z]{2,7}$/, required);
	},
	phone: function(value,required){
		return Valid.regex(value, /^(((1))?[ ,\-,\.]?([\\(]?([1-9][0-9]{2})[\\)]?))?[ ,\-,\.]?([^0-1]){1}([0-9]){2}[ ,\-,\.]?([0-9]){4}(( )((x){0,1}([0-9]){1,5}){0,1})?$/, required);
	},
	zip: function(value,required){
		return Valid.regex(value, /^([0-9]){5,5}$|(([0-9]){5,5}(-| ){1}([0-9]){4,4}$)/, required);
	},
	ssn: function(value,required){
		//OLD return Valid.regex(value, /^[0-9]{3}(-| )?[0-9]{2}(-| )?[0-9]{4}$/, required);
		//OLD_IS_NEW_AGAIN any combination of numbers, dashes and spaces from 9 to 12 long is fine.
		return Valid.regex(value, /^[0-9 -]{9,12}$/, required);
		// NOTNEW Must be numbers only, and exactly 9 of them
		// return Valid.regex(value, /^[0-9]{9}$/, required);
	},
	guid: function(value,required){
		return Valid.regex(value, /[A-Fa-f0-9]{8,8}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{12,12}/, required);
	},
	uuid: function(value,required){
		return Valid.regex(value, /[A-Fa-f0-9]{8,8}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{4,4}-[A-Fa-f0-9]{16,16}/, required);
	},
	url: function(value,required){
		return Valid.regex(value, /^((http|https|ftp|file)\:\/\/([a-zA-Z0-0]*:[a-zA-Z0-0]*(@))?[a-zA-Z0-9-\.]+(\.[a-zA-Z]{2,3})?(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9-\._\?\,\'\/\+&amp;%\$#\=~])*)|((mailto)\:[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,7})|((news)\:[a-zA-Z0-9\.]*)$/, required);
	}, // '
	date: function(value,required){
		return Valid.regex(value, /^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|(0\d|[1][012])(0[1-9]|[12]\d|3[01])\d{2}|(0?\d|[1][012])(\/|\-)(0?[1-9]|[12]\d|3[01])(\/|\-)(19|20)?\d\d)$/, required);
	},
	regex: function(value, pattern, required){
		value = value.replace(/^\s+/,'').replace(/\s+$/,'');
		
		if(!value.length && !required) return true;
		return pattern.test(value);
	}
}


//////////////////// *DRAG ////////////////////
var Drag = Class.create();
Drag.prototype = {
	cookieName: false,
	init: function(elem, cookieName) {
		this.elem = $(elem);
		var me = this;
		this.elem.onmousedown = function(e){me.mouseDown(e)};
		this.elem.onmouseup = function(e){me.mouseDown(e)};
		if(cookieName){
			this.cookieName = cookieName;
			var elemPos = Cookie.read(this.cookieName);
			if(elemPos != null && elemPos != ''){
				elemPos = elemPos.split(',');
				elemPos = {left:elemPos[0], top:elemPos[1]};
			} else {
				elemPos = {left:20, top:20};
			}
			this.elem.style.left = elemPos.left;
			this.elem.style.top = elemPos.top;
		}
	},
	mouseDown: function(e){
		var e = e || window.event;
		var startWinX = this.elem.offsetLeft;
		var startWinY = this.elem.offsetTop;
		var startMouseX = e.clientX;
		var startMouseY = e.clientY;
		
		var me = this;
		document.onmousemove = function(e){
			var e = e || window.event;
			me.elem.style.left = (startWinX - (startMouseX - e.clientX)) + 'px';
			me.elem.style.top = (startWinY - (startMouseY - e.clientY)) + 'px';
			Event.stop(e);
		}
		document.onmouseup = function(e){
			document.onmousemove = null;
			document.onmouseup = null;
			if (me.cookieName){
				Cookie.create(me.cookieName, me.elem.style.left + "," + me.elem.style.top, 100);
			}
		}
	}
}

//////////////////// *SHORTCUTS ////////////////////
var $ = function(elem){
	if(typeof elem == 'string') elem = document.getElementById(elem);
	return elem;
}
var $G = Elem.get;
var $F = Form.serializeInput;
var $L = function(func){
	if(!Event.pageLoaded)
		Event.observe(window,'load',func);
	else
		setTimeout(func,10);
}
$L(function(){Event.pageLoaded=true;});
