/*< blank basic *******************************************************************/
fValidate.prototype.blank = function()
{
	if ( this.typeMismatch( 'text' ) ) return;
	if ( this.isBlank() )
	{
		this.throwError( [this.elem.fName] );
	}
}
/*/>*/
/*< number numbers *******************************************************************/
fValidate.prototype.number = function( type, lb, ub )
{
	if ( this.typeMismatch( 'text' ) ) return;
	var num  = ( type == 0 ) ? parseInt( this.elem.value, 10 ) : parseFloat( this.elem.value );
	lb       = this.setArg( lb, 0 );
	ub       = this.setArg( ub, Number.infinity );
	if ( lb > ub )
	{
		this.devError( [lb, ub, this.elem.name] );
		return;
	}
	var fail = Boolean( isNaN( num ) || num != this.elem.value );
	if ( !fail )
	{
		switch( true )
		{
			case ( lb != false && ub != false ) : fail = !Boolean( lb <= num && num <= ub ); break;
			case ( lb != false ) : fail = Boolean( num < lb ); break;
			case ( ub != false ) : fail = Boolean( num > ub ); break;
		}
	}
	if ( fail )
	{
		this.throwError( [this.elem.fName] );
		return;
	}
	this.elemPass = true;
}
/*/>*/
/*< numeric numbers *******************************************************************/
fValidate.prototype.numeric = function( len )
{
	if ( this.typeMismatch( 'text' ) ) return;
	len = this.setArg( len, '*' );
	var regex = new RegExp( ( len == '*' ) ? "^\\d+$" : "^\\d{" + parseInt( len, 10 ) + "}\\d*$" );
	if ( !regex.test( this.elem.value ) )
	{
		if ( len == "*" )
		{
			this.throwError( [this.elem.fName] );
		} else {
			this.throwError( [len, this.elem.fName], 1 );
		}
	}
}
/*/>*/
/*< length basic *******************************************************************/
fValidate.prototype.length = function( len, maxLen )
{
	if ( this.typeMismatch( 'text' ) ) return;
	var vlen = this.elem.value.length;
	len		= Math.abs( len );
	maxLen	= Math.abs( this.setArg( maxLen, Number.infinity ) );
	if ( len > maxLen )
	{
		this.devError( [len, maxLen, this.elem.name] );
		return;
	}
	if ( len > parseInt( vlen, 10 ) )
	{
		this.throwError( [this.elem.fName, len] );
	}	
	if ( vlen > maxLen )
	{
		this.throwError( [this.elem.fName, maxLen, vlen], 1 );
	}
}
/*/>*/
/*< alnum extended *******************************************************************/
fValidate.prototype.alnum = function( minLen, tCase, numbers, spaces, puncs )
{
	if ( this.typeMismatch( 'text' ) ) return;

	tCase = this.setArg( tCase, "a" );
	
	//alert( [minLen,tCase,numbers,spaces,puncs] );

	numbers = ( numbers == "true" || numbers == "1" );
	spaces = ( spaces == "true" || spaces == "1" );

	//alert( [minLen,tCase,numbers,spaces,puncs] );
		
	var okChars = "",
		arrE	= ['None','Any','No','No','Any'];

	if ( minLen != '*' )
	{
		minLen =  parseInt( minLen, 10 );
		arrE[0] = minLen;
	} else {
		minLen = 0;
	}

	switch( tCase.toUpperCase() )
	{
		case 'U':
			okChars += 'A-Z';
			arrE[1] =  'UPPER';
			break;
		case 'L':
			okChars += 'a-z';
			arrE[1] =  'lower';
			break;
		case 'C':
			okChars += 'A-Z][a-z';
			arrE[1] =  'Intial capital';
			minLen--;
			break;
		default:
			okChars += 'a-zA-Z';
			break;		
	}

	if ( numbers == true )
	{
		okChars += '0-9';
		arrE[2] =  'Yes';
	}
	if ( spaces == true )
	{
		okChars += ' ';
		arrE[3] =  'Yes';
	}
	if ( puncs == "any" )
	{
		arrE[4]  = "Any";
	}
	else if ( puncs == "none" )
	{
		arrE[4] = "None";
	}
	else 
	{
		puncs = puncs.replace( /pipe/g, "|" );
		okChars += puncs;
		arrE[4] =  puncs; //.toPattern().replace( /\\/g, "" );
	}
	var length = ( minLen != "*" )?
		"{" + minLen + ",}":
		"+";
	var regex = ( puncs == "any" ) ?
		new RegExp( "^([" + okChars + "]|[^a-zA-Z0-9\\s])" + length + "$" ):
		new RegExp( "^[" + okChars + "]" + length + "$" );
	
	if ( !regex.test( this.elem.value ) )
	{
		this.throwError( [this.elem.value, this.elem.fName, arrE[0], arrE[1], arrE[2], arrE[3], arrE[4]] );
	}
}
/*/>*/
/*< equalto logical *******************************************************************/
fValidate.prototype.equalto = function( oName )
{
	if ( this.typeMismatch( 'text' ) ) return;
	if ( typeof oName == 'undefined' )
	{
		this.paramError( 'oName' );
	}
	var otherElem = this.form.elements[oName];
	if ( this.elem.value != otherElem.value )
	{
		this.throwError( [this.elem.fName,otherElem.fName] );			
	}
}
/*/>*/
/*< ssn extended *******************************************************************/
fValidate.prototype.ssn = function()
{
	if ( this.typeMismatch( 'text' ) ) return;
	if ( !( /^\d{3}\-\d{2}\-\d{4}$/.test( this.elem.value ) ) )
		this.throwError();
}
/*/>*/
/*< select controls *******************************************************************/
fValidate.prototype.select = function()
{
	if ( this.typeMismatch( 's1' ) ) return;
	if ( this.elem.selectedIndex == 0 )
	{
		this.throwError( [this.elem.fName] );
	}
}
/*/>*/
/*< selectm controls *******************************************************************/
fValidate.prototype.selectm = function( minS, maxS )
{
	if ( this.typeMismatch( 'sm' ) ) return;
	if ( typeof minS == 'undefined' )
	{
		this.paramError( 'minS' );
	}
	if ( maxS == 999 || maxS == '*' || typeof maxS == 'undefined' || maxS > this.elem.length ) maxS = this.elem.length;

	var count = 0;	
	for ( var opt, i = 0; ( opt = this.elem.options[i] ); i++ )
	{
		if ( opt.selected ) count++;
	}

	if ( count < minS || count > maxS )
	{
		this.throwError( [minS, maxS, this.elem.fName, count] );
	}
}
/*/>*/
/*< selecti controls *******************************************************************/
fValidate.prototype.selecti = function( indexes )
{
	
	if ( this.typeMismatch( 's1' ) ) return;
	if ( typeof indexes == 'undefined' )
	{
		this.paramError( 'indexes' );
		return;
	}
	indexes = indexes.split( "," );
	var selectOK = true;

	for ( var i = 0; i < indexes.length; i++ )
	{
		if ( this.elem.options[indexes[i]].selected )
		{
			selectOK = false;
			break;
		}
	}
	if ( !selectOK )
	{
		this.throwError( [this.elem.fName] );
	}
}
/*/>*/
/*< cazip international *******************************************************************/
fValidate.prototype.cazip = function()
{
	var elem = this.elem;
	if ( this.typeMismatch( 'text' ) ) return;
	elem.value = elem.value.toUpperCase();
	if ( !( /^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$/.test( elem.value ) ) )
	{
		this.throwError();
	}
}
fValidate.prototype.capost = fValidate.prototype.cazip;
/*/>*/
/*< ukpost international *******************************************************************/
fValidate.prototype.ukpost = function()
{
	var elem = this.elem;
	if ( this.typeMismatch( 'text' ) ) return;
	elem.value = elem.value.toUpperCase();
	if ( !( /^[A-Z]{1,2}\d[\dA-Z] ?\d[A-Z]{2}$/.test( elem.value ) ) )
	{
		this.throwError();
	}
}
/*/>*/
/*< germanpost international *******************************************************************/
fValidate.prototype.germanpost = function()
{
	var elem = this.elem;
	if ( this.typeMismatch( 'text' ) ) return;
	elem.value = elem.value.toUpperCase();
	if ( !( /^(?:CH\-)\d{4}$/.test( elem.value ) ) )
	{
		this.throwError();
	}
}
/*/>*/
/*< swisspost international *******************************************************************/
fValidate.prototype.swisspost = function()
{
	var elem = this.elem;
	if ( this.typeMismatch( 'text' ) ) return;
	elem.value = elem.value.toUpperCase();
	if ( !( /^(?:D\-)\d{5}$/.test( this.elem.value ) ) )
	{
		this.throwError();
	}
}
/*/>*/
/*< email web *******************************************************************/
fValidate.prototype.email = function( level )
{
	if ( this.typeMismatch( 'text' ) ) return;
	if ( typeof level == 'undefined' ) level = 0;
	var emailPatterns = [
		/.+@.+\..+$/i,
		/^\w.+@\w.+\.[a-z]+$/i,
		/^\w[-_a-z~.]+@\w[-_a-z~.]+\.[a-z]{2}[a-z]*$/i,
		/^\w[\w\d]+(\.[\w\d]+)*@\w[\w\d]+(\.[\w\d]+)*\.[a-z]{2,7}$/i
		];
	if ( ! emailPatterns[level].test( this.elem.value ) )
	{
		this.throwError();
	}	
}	
/*/>*/
/*< url web *******************************************************************/
fValidate.prototype.url = function( hosts, hostOptional, allowQS )
{
	if ( this.typeMismatch( 'text' ) ) return;

	this.setArg( hosts, "http" );
	
	var front = "^(?:(" + hosts.replace( /\,/g, "|" ) + ")\\:\\/\\/)";
	var end   = ( Boolean( allowQS ) == true ) ? "(\\?.*)?$" : "$";

	if ( Boolean( hostOptional ) == true ) front += "?";
	var regex = new RegExp( front + "([\\w\\d-]+\\.?)+" + end );
	
	if ( !regex.test( this.elem.value ) )
	{
		this.throwError( [this.elem.fName] );
	}
}	
/*/>*/
/*< ip web *******************************************************************/
fValidate.prototype.ip = function( portMin, portMax )
{
	if ( this.typeMismatch( 'text' ) ) return;
	portMin = this.setArg( portMin, 0 );
	portMax = this.setArg( portMax, 99999 );
	if ( !( /^\d{1,3}(\.\d{1,3}){3}(:\d+)?$/.test( this.elem.value ) ) )
	{
		this.throwError();
	}
	else
	{
		var part, i = 0, parts = this.elem.value.split( /[.:]/ );
		while ( part = parts[i++] )
		{
			if ( i == 5 ) // Check port
			{
				if ( part < portMin || part > portMax )
				{
					this.throwError( [part, portMin, portMax], 1 );
				}
			}
			else if ( part < 0 || part > 255 )
			{
				this.throwError();
			}
		}
	}
}
/*/>*/
/*< decimal numbers *******************************************************************/
fValidate.prototype.decimal = function( lval, rval )
{
	if ( this.typeMismatch( 'text' ) ) return;
	var regex = '', elem = this.elem;
	if ( lval != '*' ) lval = parseInt( lval, 10 );
	if ( rval != '*' ) rval = parseInt( rval, 10 );
	
	if ( lval == 0 )
		regex = "^\\.[0-9]{" + rval + "}$";	
	else if ( lval == '*' )
		regex = "^[0-9]*\\.[0-9]{" + rval + "}$";
	else if ( rval == '*' )
		regex = "^[0-9]{" + lval + "}\\.[0-9]+$";
	else
		regex = "^[0-9]{" + lval + "}\\.[0-9]{" + rval + "}$";
		
	regex = new RegExp( regex );

	if ( !regex.test( elem.value ) )
	{
		this.throwError( [elem.value,elem.fName] );
	}	
}
/*/>*/
/*< decimalr numbers *******************************************************************/
fValidate.prototype.decimalr = function( lmin, lmax, rmin, rmax )
{
	if ( this.typeMismatch( 'text' ) ) return;
	lmin = ( lmin == '*' )? 0 : parseInt( lmin, 10 );
	lmax = ( lmax == '*' )? '': parseInt( lmax, 10 );
	rmin = ( rmin == '*' )? 0 : parseInt( rmin, 10 );
	rmax = ( rmax == '*' )? '': parseInt( rmax, 10 );
	var	decReg = "^[0-9]{"+lmin+","+lmax+"}\\.[0-9]{"+rmin+","+rmax+"}$"
	var regex = new RegExp(decReg);
	if ( !regex.test( this.elem.value ) )
	{
		this.throwError( [this.elem.fName] );
	}
	return true;
}
/*/>*/
/*< zip extended *******************************************************************/
fValidate.prototype.zip = function( sep )
{
	if ( this.typeMismatch( 'text' ) ) return;
	sep = this.setArg( sep, "- " );
	var regex = new RegExp( "^[0-9]{5}(|[" + sep.toPattern() + "][0-9]{4})?$" );
	if ( ! regex.test( this.elem.value ) )
	{
		this.throwError();
	}
}
/*/>*/
/*< phone extended *******************************************************************/
fValidate.prototype.phone = function( format )
{
	if ( this.typeMismatch( 'text' ) ) return;
	format       = this.setArg( format, 0 );
	var patterns = [
		/^(\(?\d\d\d\)?)?[ -]?\d\d\d[ -]?\d\d\d\d$/,	//	loose
		/^(\(\d\d\d\) )?\d\d\d[ -]\d\d\d\d$/			//	strict
		];
	if ( !patterns[format].test( this.elem.value ) )
	{
		if ( format == 1 )
		{
			this.throwError();
		} else {
			this.throwError( [], 1 );
		}
	}
}
/*/>*/
/*< date datetime *******************************************************************/
fValidate.prototype.date = function( formatStr, delim, code, specDate )
{
	if ( this.typeMismatch( 'text' ) ) return;
	if ( typeof formatStr == 'undefined' )
	{
		this.paramError( 'formatStr' );
		return;
	}

	delim = this.setArg( delim, "/" );

	var error	= [this.elem.fName, formatStr.replace( /\//g, delim )];
	var format  = formatStr.split( "/" );
	var compare = this.elem.value.split( delim );
	var order   = new Object();
	
	for ( var i = 0; i < format.length; i++ )
	{
		switch( format[i].charAt( 0 ).toLowerCase() )
		{
			case 'm' :
				order.months = i;
				break;
			case 'd' :
				order.days = i;
				break;
			case 'y' :
				order.years = i;
				break;
		}
	}
	var thisDate = new Date( compare[order.years], compare[order.months]-1, compare[order.days] );
	
	if ( isNaN( thisDate ) || thisDate.getDate() != compare[order.days] || thisDate.getMonth() != compare[order.months]-1 || thisDate.getFullYear().toString().length != formatStr.match( /y/g ).length )
	{
		this.throwError( error );
		return;
	}
	
	var compareElem = this.form.elements[specDate];
	if ( typeof compareElem != 'undefined' )
	{
		specDate = compareElem.validDate || compareElem.value;
	}
	var compareDate = ( specDate == 'today' )?
		new Date():
		new Date( specDate );
	compareDate.setHours(0);
	compareDate.setMinutes(0);
	compareDate.setSeconds(0);
	compareDate.setMilliseconds(0);
	
	var timeDiff = compareDate.getTime() - thisDate.getTime();
	var dateOk   = false;
	
	switch ( parseInt( code ) ) {
		case 1 :	// Before specDate
			dateOk	= Boolean( timeDiff > 0 );
			error	= 1;
			break;
		case 2 :	// Before or on specDate
			dateOk	= Boolean( ( timeDiff + 86400000 ) > 0 );
			error	= 2;
			break;
		case 3 :	// After specDate
			dateOk	= Boolean( timeDiff < 0 );
			error	= 3;
			break;
		case 4 :	// After or on specDate
			dateOk	= Boolean( ( timeDiff - 86400000 ) < 0 );
			error	= 4;
			break;
		default : dateOk = true;
		}
	if ( !dateOk )
	{
		this.throwError( [specDate], error );
	}
	this.elem.validDate = thisDate.toString();
}	
/*/>*/
/*< money ecommerce *******************************************************************/
fValidate.prototype.money = function( ds, grp, dml )
{
	if ( this.typeMismatch( 'text' ) ) return;
	
	ds  = ( ds == ' ' )  ? false : ds.toPattern();
	grp = ( grp == ' ' ) ? false : grp.toPattern();
	dml = ( dml == ' ' ) ? false : dml.toPattern();
	
	var moneySyntax, pattern;
	
	switch( true )
	{
		case Boolean( ds && grp && dml ):		// Dollar sign, grouping, and decimal
			pattern		= "^" + ds + "(?:(?:[0-9]{1,3}" + grp + ")(?:[0-9]{3}" + grp + ")*[0-9]{3}|[0-9]{1,3})(" + dml + "[0-9]{2})$";
			moneySyntax = ds + "XX" + grp + "XXX" + dml + "XX";
			break;
		case Boolean( ds && grp && !dml ):		// Dollar sign and grouping
			pattern		= "^" + ds + "(?:(?:[0-9]{1,3}" + grp + ")(?:[0-9]{3}" + grp + ")*[0-9]{3}|[0-9]{1,3})$";
			moneySyntax = "" + ds + "XX" + grp + "XXX";
			break;
		case Boolean( ds && !grp && dml ):		// Dollar sign and decimal
			pattern		="^" + ds + "[0-9]*(\\.[0-9]{2})$";
			moneySyntax ="" + ds + "XXXXX" + dml + "XX";
			break;
		case Boolean( !ds && grp && dml ):		// Grouping and decimal
			pattern		="^(?:(?:[0-9]{1,3}" + grp + ")(?:[0-9]{3}" + grp + ")*[0-9]{3}|[0-9]{1,3})(" + dml + "[0-9]{2})?$";
			moneySyntax ="XX" + grp + "XXX" + dml + "XX";
			break;
		case Boolean( ds && !grp && !dml ):		// Dollar sign only
			pattern		="^" + ds + "[0-9]*$";
			moneySyntax ="" + ds + "XXXXX";
			break;
		case Boolean( !ds && grp && !dml ):		// Grouping only
			pattern		="^(?:(?:[0-9]{1,3}" + grp + ")(?:[0-9]{3}" + grp + ")*[0-9]{3}|[0-9]{1,3})$";
			moneySyntax ="XX" + grp + "XXX";
			break;
		case Boolean( !ds && !grp && dml ):		// Decimal only
			pattern		="^[0-9]*(" + dml + "[0-9]{2})$";
			moneySyntax ="XXXXX" + dml + "XX";
			break;
		case Boolean( !ds && !grp && !dml ):	// No params set, all special chars become optional
			pattern		="^.?(?:(?:[0-9]{1,3}.?)(?:[0-9]{3}.?)*[0-9]{3}|[0-9]{1,3})(.[0-9]{2})?$";
			moneySyntax ="[?]XX[?]XXX[?XX]";
	}
			
	var regex = new RegExp( pattern );
	if ( !regex.test( this.elem.value ) )
	{
		this.throwError( [this.elem.fName, moneySyntax.replace( /\\/g, '' )] );
	}
}
/*/>*/
/*< checkbox controls *******************************************************************/
fValidate.prototype.checkbox = function( minC, maxC )
{
	if ( this.typeMismatch( 'cb' ) ) return;
	if ( typeof minC == 'undefined' )
	{
		this.paramError( 'minC' );
		return;
	}
	if ( this.elem == this.form.elements[this.elem.name] && !this.elem.checked )
	{
		this.throwError( [this.elem.fName] );
	}
	else
	{
		this.elem = this.form.elements[this.elem.name];
		var len   = this.elem.length;
		var count = 0;
		
		if ( maxC == 999 || maxC == '*' || typeof maxC == 'undefined' || maxC > this.elem.length )
		{
			maxC == len;
		}
		var i = len;
		while( i-- > 0 )
		{
			if ( this.elem[i].checked )
			{
				count++;
			}
		}
		if ( count < minC || count > maxC )
		{
			this.throwError( [minC, maxC, this.elem[0].fName, count] );
		}			
	}
}
/*/>*/
/*< radio controls *******************************************************************/
fValidate.prototype.radio = function()
{
	if ( this.typeMismatch( 'rg' ) ) return;
	if ( this.elem == this.form.elements[this.elem.name] && !this.elem.checked )
	{
		this.throwError( [this.elem.fName] );
	}
	else
	{
		this.elem = this.form.elements[this.elem.name];
		
		for ( var i = 0; i < this.elem.length; i++ )
		{
			if ( this.elem.item( i ).checked )
			{
				return;
			}
		}
		this.throwError( [this.elem[0].fName] );
	}
}
/*/>*/
/*< eitheror logical *******************************************************************/
fValidate.prototype.eitheror = function()
{
	if ( this.typeMismatch( 'hidden' ) ) return;
	if ( typeof arguments[0] == 'undefined' )
	{
		this.paramError( 'delim' );
		return;
	}
	if ( typeof arguments[1] == 'undefined' )
	{
		this.paramError( 'fields' );
		return;
	}
	var arg, i  = 0,
		fields  = new Array(),
		field,
		nbCount = 0,		
		args    = arguments[1].split( arguments[0] );		

	this.elem.fields = new Array();
	
	while ( arg = args[i++] )
	{
		field = this.form.elements[arg];
		fields.push( field.fName );
		this.elem.fields.push( field );

		if ( !this.isBlank( arg ) )
		{
			nbCount++;
		}
	}
	if ( nbCount != 1 )
	{
		this.throwError( [fields.join( "\n\t-" )] );
	}
}
/*/>*/
/*< atleast logical *******************************************************************/
fValidate.prototype.atleast = function()
{
	if ( this.typeMismatch( 'hidden' ) ) return;
	if ( typeof arguments[0] == undefined )
	{
		this.paramError( 'qty' );
		return;
	}
	if ( typeof arguments[1] == undefined )
	{
		this.paramError( 'delim' );
		return;
	}
	if ( typeof arguments[2] == undefined )
	{
		this.paramError( 'fields' );
		return;
	}
	var arg, i  = 0,
		fields  = new Array(),
		field,
		nbCount = 0,
		args    = arguments[2].split( arguments[1] );

	this.elem.fields = new Array();
	
	while ( arg = args[i++] )
	{
		field = this.form.elements[arg];
		fields.push( field.fName );
		this.elem.fields.push( field );

		if ( !this.isBlank( arg ) )
		{
			nbCount++;
		}
	}
	if ( nbCount < arguments[0] )
	{
		this.throwError( [arguments[0], fields.join( "\n\t-" ), nbCount] );
	}
}
/*/>*/
/*< allornone logical *******************************************************************/
fValidate.prototype.allornone = function()
{
	if ( this.typeMismatch( 'hidden' ) ) return;
	if ( typeof arguments[0] == 'undefined' )
	{
		this.paramError( 'delim' );
		return;
	}
	if ( typeof arguments[1] == 'undefined' )
	{
		this.paramError( 'fields' );
		return;
	}
	var arg, i  = 0,
		fields  = new Array(),
		field,
		nbCount = 0,
		args    = arguments[1].split( arguments[0] );
	
	this.elem.fields = new Array();

	while ( arg = args[i++] )
	{
		field = this.form.elements[arg];
		fields.push( field.fName );
		this.elem.fields.push( field );

		if ( !this.isBlank( arg ) )
		{
			nbCount++;
		}
	}
	if ( nbCount > 0 && nbCount < args.length )
	{
		this.throwError( [fields.join( "\n\t-" ), nbCount] );
	}
}
/*/>*/
/*< comparison logical *******************************************************************/
fValidate.prototype.comparison = function( field1, operator, field2 )
{
	if ( this.typeMismatch( 'hidden' ) ) return;
	var elem1	= this.form.elements[field1],
		elem2	= this.form.elements[field2],
		value1	= this.getValue( elem1 ),
		value2	= this.getValue( elem2 );
		i18n	= this.i18n.comparison;
		i		= -1;
	
	var operators =
	[
		['>',	i18n.gt],
		['<',	i18n.lt],
		['>=',	i18n.gte],
		['<=',	i18n.lte],
		['==',	i18n.eq],
		['!=',	i18n.neq]
	];
	while( operators[++i][0] != operator ){ }
	this.elem.fields = [elem1, elem2];
	if ( ! eval( value1 + operator + value2 ) )
	{
		this.throwError( [elem1.fName, operators[i][1], elem2.fName] );
	}
}
/*/>*/
/*< file controls *******************************************************************/
fValidate.prototype.file = function( extensions, cSens )
{
	if ( this.typeMismatch( 'file' ) ) return;
	if ( typeof extensions == 'undefined' )
	{
		this.paramError( 'extensions' );
		return;
	}
	cSens = Boolean( cSens ) ? "" : "i";
	var regex = new RegExp( "^.+\\.(" + extensions.replace( /,/g, "|" ) + ")$", cSens );
	if ( ! regex.test( this.elem.value ) )
	{
		this.throwError( [extensions.replace( /,/g, "\n" )] );
	}
}
/*/>*/
/*< custom special *******************************************************************/
fValidate.prototype.custom = function( flags, reverseTest )
{
	if ( this.typeMismatch( 'text' ) ) return;
	flags     = ( flags ) ? flags.replace( /[^gim]/ig ) : "";
	var regex = new RegExp( this.elem.getAttribute( this.config.pattern ), flags );
	if ( !regex.test( this.elem.value ) )
	{
		this.throwError( [this.elem.fName] );
	}	
}
/*/>*/
/*< cc ecommerce *******************************************************************/
fValidate.prototype.cc = function()
{
	if ( this.typeMismatch( 'text' ) ) return;
	var typeElem = this.form.elements[this.config.ccType];
	if ( !typeElem )
	{
		this.devError( 'noCCType' )
		return;
	}
	var ccType   = typeElem.options[typeElem.selectedIndex].value.toUpperCase();
	var types    = {
		'VISA'    : /^4\d{12}(\d{3})?$/,
		'MC'      : /^5[1-5]\d{14}$/,
		'DISC'    : /^6011\d{12}$/,
		'AMEX'    : /^3[4|7]\d{13}$/,        
		'DINERS'  : /^3[0|6|8]\d{12}$/,
		'ENROUTE' : /^2[014|149]\d{11}$/,
		'JCB'     : /^3[088|096|112|158|337|528]\d{12}$/,
		'SWITCH'  : /^(49030[2-9]|49033[5-9]|49110[1-2]|4911(7[4-9]|8[1-2])|4936[0-9]{2}|564182|6333[0-4][0-9]|6759[0-9]{2})\d{10}(\d{2,3})?$/,
		'DELTA'   : /^4(1373[3-7]|462[0-9]{2}|5397[8|9]|54313|5443[2-5]|54742|567(2[5-9]|3[0-9]|4[0-5])|658[3-7][0-9]|659(0[1-9]|[1-4][0-9]|50)|844[09|10]|909[6-7][0-9]|9218[1|2]|98824)\d{10}$/,
		'SOLO'    : /^(6334[5-9][0-9]|6767[0-9]{2})\d{10}(\d{2,3})?$/
		};
	if ( typeElem.validated == false && this.groupError == true ) return;
	if ( typeof types[ccType] == 'undefined' && typeElem.validated == false && this.groupError == false )
	{
		this.devError( [ccType] );
		return;
	}
	this.elem.value = this.elem.value.replace( /[^\d]/g, "" );
	if ( !types[ccType].test( this.elem.value ) || !this.elem.value.luhn() )
	{
		this.throwError( [this.elem.fName] );
	}
}

String.prototype.luhn = function()
{
	var i = this.length;
	var checkSum = "", digit;
	while ( digit = this.charAt( --i ) )
	{
		checkSum += ( i % 2 == 0 ) ? digit * 2 : digit;
	}
	checkSum = eval( checkSum.split('').join('+') );
	return ( checkSum % 10 == 0 );
}
/*/>*/
/*	EOF */