if (typeof Form.Item.Validators == 'undefined') {
	Form.Item.Validator = function (expression, message) {
		if (isFunction(expression)) {
			this.expression = expression;
		} else {
			this.expression = new Function('value', 'item', 'message', 'return (' + expression + ')');
		}
		this.message = message;
	}
	
	Form.Item.Validator.prototype.isValid = function (item, message) {
		return this.expression(item.value, item, message);
	}
}


if (typeof Validators == 'undefined') {
	Validators = {};
	
	Validators.isEmpty = function (val) {
		//var rx = new RegExp('^\\s*$', 'ig');
		//return ! isset(val) || rx.test(val);
		return ! isset(val) || ! val.trim();
	}
	
	Validators.isNotEmpty = function (val) {
		return ! Validators.isEmpty(val);
	}
	
	Validators.isSelected = function (val) {
		return val != '' /*&& val != '0'*/;
	}
	
	/**
	* Available formats:
	*
	*	1. Just string
	*
	*		Validators.isString(value)
	*
	*	2. String with RegExp
	*
	*		Validators.isString(value, new RegExp('^[0-9a-f]+$', 'i'))
	*
	*	3. String with max length
	*
	*		Validators.isString(value, 50)
	*
	*	4. String with min and max length
	*
	*		Validators.isString(value, 4, 10)
	*		Validators.isString(value, 10, 4)
	*
	*	5. String with different length and RegExp combinations
	*
	*		Validators.isString(value, 25, /^[XYZ]+$/)
	*		Validators.isString(value, /^[XYZ]+$/, 25)
	*		Validators.isString(value, 5, 15, /^[abc]+$/)
	*		Validators.isString(value, /^[01]+$/, 4, 8)
	*/
	Validators.isString = function (val, expr1, expr2, expr3) {
		// Params testing
		if (val === '') {
			return true;
		}
		if (! isset(expr1) && ! isset(expr2) && ! isset(expr3)) {
			return true;
		}
		// RX testing
		expr = null;
		if (expr1 instanceof RegExp) {
			expr = expr1;
		} else if (expr2 instanceof RegExp) {
			expr = expr2;
		} else if (expr3 instanceof RegExp) {
			expr = expr3;
		}
		valid = true;
		if (expr !== null) {
			valid &= expr.test(val);
		}
		// MIN/MAX testing
		min = Number.POSITIVE_INFINITY; max = Number.NEGATIVE_INFINITY;
		if (isNumber(expr1)) {
			if (expr1 < min) {
				min = expr1;
			}
			if (expr1 > max) {
				max = expr1;
			}
		}
		if (isNumber(expr2)) {
			if (expr2 < min) {
				min = expr2;
			}
			if (expr2 > max) {
				max = expr2;
			}
		}
		if (isNumber(expr3)) {
			if (expr3 < min) {
				min = expr3;
			}
			if (expr3 > max) {
				max = expr3;
			}
		}
		if (max !== Number.NEGATIVE_INFINITY) {
			valid &= (val.length <= max);
			if (min !== max) {
				valid &= (val.length >= min);
			}
		}
		return Boolean(valid);
	}
	
	Validators.isStringVarName = function (val, expr1, expr2) {
		return Validators.isString(val, new RegExp('^[a-z0-9_]*$', 'i'), expr1, expr2);
	}
	
	Validators.isStringAlphas = function (val, expr1, expr2) {
		if (System.Language === 'lt') {
			expr = new RegExp('^[a-ząčęėį�šųūž]*$', 'i');
		} else if (System.Language === 'ru') {
			expr = new RegExp('^[абвгдеёжзийклмнопрст�уфхцчшщъы�ьэюя]*$', 'i');
		} else {
			expr = new RegExp('^[a-z]*$', 'i');
		}
		return Validators.isString(val, expr, expr1, expr2);
	}
	
	Validators.isStringAlphaSpaces = function (val, expr1, expr2) {
		if (System.Language === 'lt') {
			expr = new RegExp('^[a-ząčęėį�šųūž\\s]*$', 'i');
		} else if (System.Language === 'ru') {
			expr = new RegExp('^[абвгдеёжзийклмнопр�ст�уфхцчшщ�ъы�ьэюя\\s]*$', 'i');
		} else {
			expr = new RegExp('^[a-z\\s]*$', 'i');
		}
		return Validators.isString(val, expr, expr1, expr2);
	}
	
	Validators.isStringLatinAlphaSpaces = function (val, expr1, expr2) {
		return Validators.isString(val, new RegExp('^[a-z\\s]*$', 'i'), expr1, expr2);
	}
	
	Validators.isStringNumbers = function (val, expr1, expr2) {
		return Validators.isString(val, new RegExp('^[0-9]*$', 'i'), expr1, expr2);
	}
	
	Validators.isStringAlphaNumbers = function (val, expr1, expr2) {
		if (System.Language === 'lt') {
			expr = new RegExp('^[0-9a-ząčęėį�šųūž]*$', 'i');
		} else if (System.Language === 'ru') {
			expr = new RegExp('^[0-9абвгдеёжзийклмнопр�ст�уфхцчшщ�ъы�ьэюя]*$', 'i');
		} else {
			expr = new RegExp('^[0-9a-z]*$', 'i');
		}
		return Validators.isString(val, expr, expr1, expr2);
	}
	
	Validators.isStringLatinAlphaNumbers = function (val, expr1, expr2) {
		return Validators.isString(val, new RegExp('^[0-9a-z]*$', 'i'), expr1, expr2);
	}
	
	//
	// .int(value, 50)        // max
	// .int(value, 50, true)  // max
	// .int(value, 50, false) // min
	// .int(value, 10, 50)    // min <= x <= max
	//
	
	Validators.isNumber = function (val, expr1, expr2) {
		number = Number(val);
		if (isNaN(number)) {
			return false;
		}
	
		if (! isset(expr1) && ! isset(expr2)) {
			return true;
		}
	
		// MIN/MAX testing
		min = Number.POSITIVE_INFINITY; max = Number.NEGATIVE_INFINITY;
		if (isNumber(expr1)) {
			if (expr1 < min) {
				min = expr1;
			}
			if (expr1 > max) {
				max = expr1;
			}
		}
		if (isNumber(expr2)) {
			if (expr2 < min) {
				min = expr2;
			}
			if (expr2 > max) {
				max = expr2;
			}
		}
	
		// MIN/MAX swich testing
		swc = null;
		if (isBool(expr1) && swc === null) {
			swc = expr1;
		}
		if (isBool(expr2) && swc === null) {
			swc = expr2;
		}
		swc = Boolean(swc);
	
		valid = true;
		if (max !== Number.NEGATIVE_INFINITY) {
			valid &= (min === max)
			? (swc ? (number <= max) : (number >= min))
			: ((number <= max) && (number >= min));
		}
		return Boolean(valid);
	}
	
	Validators.isNumeric = Validators.isNumber;
	
	Validators.isInt = function (val, expr1, expr2) {
		if (! Validators.isNumber(val, expr1, expr2)) {
			return false;
		}
		number = Number(val);
		return (number == Math.ceil(number));
	}
	
	Validators.isInteger = Validators.isInt;
	
	Validators.isFloat = Validators.isNumber;
	Validators.isDouble = Validators.isFloat;
	
	Validators.isDate = function (val) {
		if (val == '') {
			return true;
		}
		var s = val.split('-', 3), x, d = new Date(s[0], s[1] - 1, s[2]);
		s = d.getFullYear() + '-';
		x = d.getMonth() + 1;
		if (x < 10) {
			x = '0' + x;
		}
		s += x + '-';
		x = d.getDate();
		if (x < 10) {
			x = '0' + x;
		}
		s += x;
		return s == val;
	}
	
	Validators.isTime = function (val) {
		if (val == '') {
			return true;
		}
		var rx = new RegExp('^(([01]?\\d|2[0-3]):[0-5]\\d)$');
		return rx.test(val);
	}
	
	Validators.isUnlimitedTime = function (val) {
		if (val == '') {
			return true;
		}
		var rx = new RegExp('^\\d+:[0-5]\\d$');
		return rx.test(val);
	}
	
	Validators.isDateTime = function (val) {
		var dt = val.split(new RegExp('[ T]', 'i'), 2);
		// Whether no date...
		if (dt[0] === '') {
			return dt.length === 1 || dt[1] === '';
		}
		// Whether have date but no time...
		if (dt.length === 1 || dt[1] === '') {
			return false;
		}
		// Whether have date and time...
		return Boolean(Validators.isDate(dt[0]) && Validators.isTime(dt[1]));
	}
	
	
	Validators.isDateTimeEmpty = function (val) {
		var dt = val.split(new RegExp('[ tT]'), 2);
		return Validators.isEmpty(dt[0]) || Validators.isEmpty(dt[1]);
	}
	
	Validators.isDateTimeNotEmpty = function (val) {
		var dt = val.split(new RegExp('[ tT]'), 2);
		return ! Validators.isEmpty(dt[0]) && ! Validators.isEmpty(dt[1]);
	}
	
	
	Validators.isDateTimeDateEmpty = function (val) {
		var dt = val.split(new RegExp('[ tT]'), 2);
		return Validators.isEmpty(dt[0]);
	}
	
	Validators.isDateTimeDateNotEmpty = function (val) {
		var dt = val.split(new RegExp('[ tT]'), 2);
		return ! Validators.isEmpty(dt[0]);
	}
	
	
	Validators.isDateTimeTimeEmpty = function (val) {
		var dt = val.split(new RegExp('[ tT]'), 2);
		return Validators.isEmpty(dt[1]);
	}
	
	Validators.isDateTimeTimeNotEmpty = function (val) {
		var dt = val.split(new RegExp('[ tT]'), 2);
		return ! Validators.isEmpty(dt[1]);
	}
	
	//Validators.Custom.FirstLevelDomains='(';
	//Validators.Custom.FirstLevelDomains+='a[c-gil-oq-uwz]|';		//ac,ad,ae,af,ag,ai,al,am,an,ao,aq,ar,as,at,au,aw,az
	//Validators.Custom.FirstLevelDomains+='b[a-bd-jm-or-tvwyz]|';	//ba,bb,bd,be,bf,bg,bh,bi,bj,bm,bn,bo,br,bs,bt,bv,bw,by,bz
	//Validators.Custom.FirstLevelDomains+='c[acdf-ik-orsuvx-z]|';	//ca,cc,cd,cf,cg,ch,ci,ck,cl,cm,cn,co,cr,cs,cu,cv,cz,cy,cz
	//Validators.Custom.FirstLevelDomains+='d[ejkmoz]|';			//de,dj,dk,dm,do,dz
	//Validators.Custom.FirstLevelDomains+='e[ceghr-u]|';			//ec,ee,eg,eh,er,es,et,eu
	//Validators.Custom.FirstLevelDomains+='f[i-kmorx]|';			//fi,fj,fk,fm,fo,fr,fx
	//Validators.Custom.FirstLevelDomains+='g[abd-ilmnp-uwy]|';		//ga,gb,gd,ge,gf,gg,gh,gi,gl,gm,gn,gp,gq,gr,gs,gt,gu,gw,gy
	//Validators.Custom.FirstLevelDomains+='h[kmnrtu]|';			//hk,hm,hn,hr,ht,hu
	//Validators.Custom.FirstLevelDomains+='i[delm-oq-t]|';			//id,ie,il,im,in,io,iq,ir,is,it
	//Validators.Custom.FirstLevelDomains+='j[emop]|';				//je,jm,jo,jp
	//Validators.Custom.FirstLevelDomains+='k[eg-imnprwyz]|';		//ke,kg,kh,ki,km,kn,kp,kr,kw,ky,kz
	//Validators.Custom.FirstLevelDomains+='l[a-cikr-vy]|';			//la,lb,lc,li,lk,lr,ls,lt,lu,lv,ly
	//Validators.Custom.FirstLevelDomains+='m[acdghk-z]|';			//ma,mc,md,mg,mh,mk,ml,mm,mn,mo,mp,mq,mr,ms,mt,mu,mv,mw,mx,my,mz
	//Validators.Custom.FirstLevelDomains+='n[ace-giloprtuz]|';		//na,nc,ne,nf,ng,ni,nl,no,np,nr,nt,nu,nz
	//Validators.Custom.FirstLevelDomains+='om|';					//om
	//Validators.Custom.FirstLevelDomains+='p[ae-hk-nrtwy]|';		//pa,pe,pf,pg,ph,pk,pl,pm,pn,pr,pt,pw,py
	//Validators.Custom.FirstLevelDomains+='qa|';					//qa
	//Validators.Custom.FirstLevelDomains+='r[eouw]|';				//re,ro,ru,rw
	//Validators.Custom.FirstLevelDomains+='s[a-eg-ort-vyz]|';		//sa,sb,sc,sd,se,sg,sh,si,sj,sk,sl,sm,sn,so,sr,st,su,sv,sy,sz
	//Validators.Custom.FirstLevelDomains+='t[cdf-hjkm-prtvwz]|';	//tc,td,tf,tg,th,tj,tk,tm,tn,to,tp,tr,tt,tv,tx,tz
	//Validators.Custom.FirstLevelDomains+='u[agkmsyz]|';			//ua,ug,uk,um,us,uy,uz
	//Validators.Custom.FirstLevelDomains+='v[aceginu]|';			//va,vc,ve,vg,vy,vn,vu
	//Validators.Custom.FirstLevelDomains+='w[fs]|';				//wf,ws
	//Validators.Custom.FirstLevelDomains+='y[etu]|';				//ye,yt,yu
	//Validators.Custom.FirstLevelDomains+='z[admrw]|';				//za,zd,zm,zr,zw
	//Validators.Custom.FirstLevelDomains+='aero|';					//aero
	//Validators.Custom.FirstLevelDomains+='biz|';					//biz
	//Validators.Custom.FirstLevelDomains+='co(m|op)|';				//com,coop
	//Validators.Custom.FirstLevelDomains+='edu|';					//edu
	//Validators.Custom.FirstLevelDomains+='gov|';					//gov
	//Validators.Custom.FirstLevelDomains+='in(fo|t)|';				//info,int
	//Validators.Custom.FirstLevelDomains+='m(il|useum)|';			//mil,museum
	//Validators.Custom.FirstLevelDomains+='n(ame|et)|';			//name,net
	//Validators.Custom.FirstLevelDomains+='org|';					//org
	//Validators.Custom.FirstLevelDomains+='pro';					//pro
	//Validators.Custom.FirstLevelDomains+=')';
	
	Validators.isEmail = function (val) {
	//
	//	// Params testing
	//	if (typeof item !== 'object') return false;
	//	if (item.value === '') return true;
	//
	//	var rx = '^(.+)@(.+)$';
	//
	//	// The following pattern is used to check if the entered e-mail address
	//	// fits the user@domain format. It also is used to separate the username
	//	// from the domain.
	//	var emailPat=new RegExp('^(.+)@(.+)$');
	//
	//	// The following string represents the pattern for matching all special
	//	// characters. We don't want to allow special characters in the address.
	//	// These characters include ( ) < > @ , ; : \ ' . [ ]
	//	var specialChars='\\(\\)<>@,;:\\\\\\\'\\.\\[\\]';
	//
	//	// The following string represents the range of characters allowed in a
	//	// username or domainname.  It really states which chars aren't allowed.
	//	// var validChars='\\[^\\s' + specialChars + '\\]';
	//	// var validChars='[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]';
	//	var validChars='\\w';
	//
	//	// The following pattern applies if the 'user' is a quoted string (in
	//	// which case, there are no rules about which characters are allowed
	//	// and which aren't; anything goes). E.g. 'jiminy cricket'@disney.com
	//	// is a legal e-mail address.
	//	var quotedUser='(\'[^\']*\')';
	//
	//	// The following pattern applies for domains that are IP addresses,
	//	// rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
	//	// e-mail address. NOTE: The square brackets are required.
	//	// var ipDomainPat=new RegExp('^\\[(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\]$');
	//	// var ipDomainPat=new RegExp('^\\[([1-9]|1\\d)?\\d|2([0-4]\\d|5[0-5])(\\.([1-9]|1\\d)?\\d|2([0-4]\\d|5[0-5])){3}\\]$');
	//	// \[([1-9]|1\d)?\d|2([0-4]\d|5[0-5])(\.([1-9]|1\d)?\d|2([0-4]\d|5[0-5])){3}\]
	//
	//	// The following string represents an atom (basically a series of
	//	// non-special characters.)
	//	// var atom=validChars + '+';
	//	var atom='[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+';
	//
	//	// The following string represents one word in the typical username.
	//	// For example, in john.doe@somewhere.com, john and doe are words.
	//	// Basically, a word is either an atom or quoted string.
	//	// var word='(' + atom + '|' + quotedUser + ')';
	//	var word='([^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+|(\'[^\']*\'))';
	//
	//	// The following pattern describes the structure of the user
	//	// var userPat=new RegExp('^' + word + '(\\.' + word + ')*$');
	//	var userPat=new RegExp('^([^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+|(\'[^\']*\'))(\\.([^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+|(\'[^\']*\')))*$');
	//
	//
	//
	//	// The following pattern describes the structure of a normal symbolic
	//	// domain, as opposed to ipDomainPat, shown above.
	//	// var domainPat=new RegExp('^' + atom + '(\\.' + atom +')*$');
	//	// var domainPat=new RegExp('^[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+(\\.[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+)*$');
	//	var domainPat=new RegExp('^[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+(\\.[^\\s\\(\\)<>@,;:\\\\\\\'\\.\\[\\]]+)*$');
	//
	//	var emailPat=new RegExp('^(.+)@(.+)$');
	//
	//	(\'[^\']*\'|\w+([\.\-]\w+)*)@(\w+(\.\w+)|\[\d{1,3}(\.\d{1,3}){3}\])
	//
	//	// Finally, let's start trying to figure out if the supplied address is valid.
	//
	//	// Begin with the coarse pattern to simply break up user@domain into
	//	// different pieces that are easy to analyze.
	//	var matchArray=item.value.match(emailPat);
	//	if (null===matchArray)
	//	{
	//		// Too many/few @'s or something; basically, this address doesn't
	//		// even fit the general mould of a valid e-mail address.
	//		// alert('Email address seems incorrect (check @ and .'s)')
	//		return false;
	//	}
	//	var user=matchArray[1];
	//	var domain=matchArray[2];
	//
	//	// See if 'user' is valid
	//	if (null===user.match(userPat))
	//	{
	//		// The username doesn't seem to be valid.
	//		return false;
	//	}
	//
	//	// if the e-mail address is at an IP address (as opposed to a symbolic
	//	// host name) make sure the IP address is valid.
	//	var IPArray=domain.match(ipDomainPat);
	//	if (null!==IPArray)
	//	{
	//		// this is an IP address
	//		for (var i=1; i<=4; i++)
	//		{
	//			if (IPArray[i]>255)
	//			{
	//				// Destination IP address is invalid!
	//				return false;
	//			}
	//		}
	//		return true;
	//	}
	//
	//	// Domain is symbolic name
	//	var domainArray=domain.match(domainPat);
	//	if (null===domainArray)
	//	{
	//		// The domain name doesn't seem to be valid.
	//		return false;
	//	}
	//
	//	// domain name seems valid, but now make sure that it ends in a
	//	// three-letter word (like com, edu, gov) or a two-letter word,
	//	// representing country (uk, nl), and that there's a hostname preceding
	//	// the domain or country.
	//
	//	// Now we need to break up the domain to get a count of how many atoms
	//	// it consists of.
	//	var atomPat=new RegExp(atom,'g');
	//	var domArr=domain.match(atomPat);
	//	var len=domArr.length;
	//	var country=new RegExp(Validators.Custom.FirstLevelDomains);
	//	if (null==domArr[domArr.length-1].match(country))
	//	{
	//		// The address must end with valid first level domain
	//		return false;
	//	}
	//
	//	// Make sure there's a host name preceding the domain.
	//	if (len<2)
	//	{
	//		// This address is missing a hostname!
	//		return false;
	//	}
	//
	//	// If we've gotten this far, everything's valid!
	//	return true;
	//
	
		return Validators.isString(val, new RegExp('^\\s*(\'[^\']*\'|\\w+([\\.\\-]\\w+)*)@(\\w+([\\.\\-]\\w+)*|\\[\\d{1,3}(\\.\\d{1,3}){3}\\])\\s*$', 'i'));
	}
	
	Validators.isURL = function (val) {
	//
	//	var expression1 = new RegExp('index\\.php\\?','i');
	//
	//	var expression2 = new RegExp('^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\;\?\\\\+&%\$#\=~_\-]+))*$', 'i');
	//
	//	var protocol = '';
	//	var servername =  '(\w+\.)*'+Validators.Custom.FirstLevelDomains+' (www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)';
	//
	//	// Validators.Custom.FirstLevelDomains
	//
	
		return Validators.isString(val, new RegExp('^\\s*(((ht|f)tp(s?))\\://)?\\w+([\\.+-]\\w+)+(\\:\\d{1,5})?(/.*)?\\s*$','i'));
	}
	
	Validators.isPhone = function (val) {
		return Validators.isString(val, new RegExp('^\\s*((\\+\\d+(\\s*-?\\s*\\d+)*|[08])\\s*)?(\\(\\d+(\\s*-?\\s*\\d+)*\\)\\s*)?\\d+(\\s*-?\\s*\\d+)*\\s*$', 'i'));
	}


	//
	// HtmlItem
	//

	Validators.isHtmlEmpty = function (val) {
		return Validators.isEmpty(val) || val.trim().match(new RegExp('^<(p|div)( .*?)?>\\s*(&nbsp;\\s*)*</\\1>$', 'i')) !== null;
	}
	
	Validators.isNotHtmlEmpty = function (val) {
		return ! Validators.isHtmlEmpty(val);
	}
	
	//
	// FileItem, MultiFileItem
	//
	
	Validators._rxFileName = new RegExp('^[ 0-9a-z._-]+$', 'i');
	
	Validators.isValidFileName = function (val, expr1, expr2) {
		var z;
		z = val.lastIndexOf('/');  if (z >= 0) val = val.substr(z+1);
		z = val.lastIndexOf('\\'); if (z >= 0) val = val.substr(z+1);
		return Validators.isString(val, Validators._rxFileName, expr1, expr2);
	}
}
