src/pyams_skin/resources/js/ext/jquery-validate-1.17.0.js
changeset 557 bca7a7e058a3
equal deleted inserted replaced
-1:000000000000 557:bca7a7e058a3
       
     1 /*!
       
     2  * jQuery Validation Plugin v1.17.0
       
     3  *
       
     4  * https://jqueryvalidation.org/
       
     5  *
       
     6  * Copyright (c) 2017 Jörn Zaefferer
       
     7  * Released under the MIT license
       
     8  */
       
     9 (function( factory ) {
       
    10 	if ( typeof define === "function" && define.amd ) {
       
    11 		define( ["jquery"], factory );
       
    12 	} else if (typeof module === "object" && module.exports) {
       
    13 		module.exports = factory( require( "jquery" ) );
       
    14 	} else {
       
    15 		factory( jQuery );
       
    16 	}
       
    17 }(function( $ ) {
       
    18 
       
    19 $.extend( $.fn, {
       
    20 
       
    21 	// https://jqueryvalidation.org/validate/
       
    22 	validate: function( options ) {
       
    23 
       
    24 		// If nothing is selected, return nothing; can't chain anyway
       
    25 		if ( !this.length ) {
       
    26 			if ( options && options.debug && window.console ) {
       
    27 				console.warn( "Nothing selected, can't validate, returning nothing." );
       
    28 			}
       
    29 			return;
       
    30 		}
       
    31 
       
    32 		// Check if a validator for this form was already created
       
    33 		var validator = $.data( this[ 0 ], "validator" );
       
    34 		if ( validator ) {
       
    35 			return validator;
       
    36 		}
       
    37 
       
    38 		// Add novalidate tag if HTML5.
       
    39 		this.attr( "novalidate", "novalidate" );
       
    40 
       
    41 		validator = new $.validator( options, this[ 0 ] );
       
    42 		$.data( this[ 0 ], "validator", validator );
       
    43 
       
    44 		if ( validator.settings.onsubmit ) {
       
    45 
       
    46 			this.on( "click.validate", ":submit", function( event ) {
       
    47 
       
    48 				// Track the used submit button to properly handle scripted
       
    49 				// submits later.
       
    50 				validator.submitButton = event.currentTarget;
       
    51 
       
    52 				// Allow suppressing validation by adding a cancel class to the submit button
       
    53 				if ( $( this ).hasClass( "cancel" ) ) {
       
    54 					validator.cancelSubmit = true;
       
    55 				}
       
    56 
       
    57 				// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
       
    58 				if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
       
    59 					validator.cancelSubmit = true;
       
    60 				}
       
    61 			} );
       
    62 
       
    63 			// Validate the form on submit
       
    64 			this.on( "submit.validate", function( event ) {
       
    65 				if ( validator.settings.debug ) {
       
    66 
       
    67 					// Prevent form submit to be able to see console output
       
    68 					event.preventDefault();
       
    69 				}
       
    70 				function handle() {
       
    71 					var hidden, result;
       
    72 
       
    73 					// Insert a hidden input as a replacement for the missing submit button
       
    74 					// The hidden input is inserted in two cases:
       
    75 					//   - A user defined a `submitHandler`
       
    76 					//   - There was a pending request due to `remote` method and `stopRequest()`
       
    77 					//     was called to submit the form in case it's valid
       
    78 					if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
       
    79 						hidden = $( "<input type='hidden'/>" )
       
    80 							.attr( "name", validator.submitButton.name )
       
    81 							.val( $( validator.submitButton ).val() )
       
    82 							.appendTo( validator.currentForm );
       
    83 					}
       
    84 
       
    85 					if ( validator.settings.submitHandler ) {
       
    86 						result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
       
    87 						if ( hidden ) {
       
    88 
       
    89 							// And clean up afterwards; thanks to no-block-scope, hidden can be referenced
       
    90 							hidden.remove();
       
    91 						}
       
    92 						if ( result !== undefined ) {
       
    93 							return result;
       
    94 						}
       
    95 						return false;
       
    96 					}
       
    97 					return true;
       
    98 				}
       
    99 
       
   100 				// Prevent submit for invalid forms or custom submit handlers
       
   101 				if ( validator.cancelSubmit ) {
       
   102 					validator.cancelSubmit = false;
       
   103 					return handle();
       
   104 				}
       
   105 				if ( validator.form() ) {
       
   106 					if ( validator.pendingRequest ) {
       
   107 						validator.formSubmitted = true;
       
   108 						return false;
       
   109 					}
       
   110 					return handle();
       
   111 				} else {
       
   112 					validator.focusInvalid();
       
   113 					return false;
       
   114 				}
       
   115 			} );
       
   116 		}
       
   117 
       
   118 		return validator;
       
   119 	},
       
   120 
       
   121 	// https://jqueryvalidation.org/valid/
       
   122 	valid: function() {
       
   123 		var valid, validator, errorList;
       
   124 
       
   125 		if ( $( this[ 0 ] ).is( "form" ) ) {
       
   126 			valid = this.validate().form();
       
   127 		} else {
       
   128 			errorList = [];
       
   129 			valid = true;
       
   130 			validator = $( this[ 0 ].form ).validate();
       
   131 			this.each( function() {
       
   132 				valid = validator.element( this ) && valid;
       
   133 				if ( !valid ) {
       
   134 					errorList = errorList.concat( validator.errorList );
       
   135 				}
       
   136 			} );
       
   137 			validator.errorList = errorList;
       
   138 		}
       
   139 		return valid;
       
   140 	},
       
   141 
       
   142 	// https://jqueryvalidation.org/rules/
       
   143 	rules: function( command, argument ) {
       
   144 		var element = this[ 0 ],
       
   145 			settings, staticRules, existingRules, data, param, filtered;
       
   146 
       
   147 		// If nothing is selected, return empty object; can't chain anyway
       
   148 		if ( element == null ) {
       
   149 			return;
       
   150 		}
       
   151 
       
   152 		if ( !element.form && element.hasAttribute( "contenteditable" ) ) {
       
   153 			element.form = this.closest( "form" )[ 0 ];
       
   154 			element.name = this.attr( "name" );
       
   155 		}
       
   156 
       
   157 		if ( element.form == null ) {
       
   158 			return;
       
   159 		}
       
   160 
       
   161 		if ( command ) {
       
   162 			settings = $.data( element.form, "validator" ).settings;
       
   163 			staticRules = settings.rules;
       
   164 			existingRules = $.validator.staticRules( element );
       
   165 			switch ( command ) {
       
   166 			case "add":
       
   167 				$.extend( existingRules, $.validator.normalizeRule( argument ) );
       
   168 
       
   169 				// Remove messages from rules, but allow them to be set separately
       
   170 				delete existingRules.messages;
       
   171 				staticRules[ element.name ] = existingRules;
       
   172 				if ( argument.messages ) {
       
   173 					settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
       
   174 				}
       
   175 				break;
       
   176 			case "remove":
       
   177 				if ( !argument ) {
       
   178 					delete staticRules[ element.name ];
       
   179 					return existingRules;
       
   180 				}
       
   181 				filtered = {};
       
   182 				$.each( argument.split( /\s/ ), function( index, method ) {
       
   183 					filtered[ method ] = existingRules[ method ];
       
   184 					delete existingRules[ method ];
       
   185 				} );
       
   186 				return filtered;
       
   187 			}
       
   188 		}
       
   189 
       
   190 		data = $.validator.normalizeRules(
       
   191 		$.extend(
       
   192 			{},
       
   193 			$.validator.classRules( element ),
       
   194 			$.validator.attributeRules( element ),
       
   195 			$.validator.dataRules( element ),
       
   196 			$.validator.staticRules( element )
       
   197 		), element );
       
   198 
       
   199 		// Make sure required is at front
       
   200 		if ( data.required ) {
       
   201 			param = data.required;
       
   202 			delete data.required;
       
   203 			data = $.extend( { required: param }, data );
       
   204 		}
       
   205 
       
   206 		// Make sure remote is at back
       
   207 		if ( data.remote ) {
       
   208 			param = data.remote;
       
   209 			delete data.remote;
       
   210 			data = $.extend( data, { remote: param } );
       
   211 		}
       
   212 
       
   213 		return data;
       
   214 	}
       
   215 } );
       
   216 
       
   217 // Custom selectors
       
   218 $.extend( $.expr.pseudos || $.expr[ ":" ], {		// '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support
       
   219 
       
   220 	// https://jqueryvalidation.org/blank-selector/
       
   221 	blank: function( a ) {
       
   222 		return !$.trim( "" + $( a ).val() );
       
   223 	},
       
   224 
       
   225 	// https://jqueryvalidation.org/filled-selector/
       
   226 	filled: function( a ) {
       
   227 		var val = $( a ).val();
       
   228 		return val !== null && !!$.trim( "" + val );
       
   229 	},
       
   230 
       
   231 	// https://jqueryvalidation.org/unchecked-selector/
       
   232 	unchecked: function( a ) {
       
   233 		return !$( a ).prop( "checked" );
       
   234 	}
       
   235 } );
       
   236 
       
   237 // Constructor for validator
       
   238 $.validator = function( options, form ) {
       
   239 	this.settings = $.extend( true, {}, $.validator.defaults, options );
       
   240 	this.currentForm = form;
       
   241 	this.init();
       
   242 };
       
   243 
       
   244 // https://jqueryvalidation.org/jQuery.validator.format/
       
   245 $.validator.format = function( source, params ) {
       
   246 	if ( arguments.length === 1 ) {
       
   247 		return function() {
       
   248 			var args = $.makeArray( arguments );
       
   249 			args.unshift( source );
       
   250 			return $.validator.format.apply( this, args );
       
   251 		};
       
   252 	}
       
   253 	if ( params === undefined ) {
       
   254 		return source;
       
   255 	}
       
   256 	if ( arguments.length > 2 && params.constructor !== Array  ) {
       
   257 		params = $.makeArray( arguments ).slice( 1 );
       
   258 	}
       
   259 	if ( params.constructor !== Array ) {
       
   260 		params = [ params ];
       
   261 	}
       
   262 	$.each( params, function( i, n ) {
       
   263 		source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
       
   264 			return n;
       
   265 		} );
       
   266 	} );
       
   267 	return source;
       
   268 };
       
   269 
       
   270 $.extend( $.validator, {
       
   271 
       
   272 	defaults: {
       
   273 		messages: {},
       
   274 		groups: {},
       
   275 		rules: {},
       
   276 		errorClass: "error",
       
   277 		pendingClass: "pending",
       
   278 		validClass: "valid",
       
   279 		errorElement: "label",
       
   280 		focusCleanup: false,
       
   281 		focusInvalid: true,
       
   282 		errorContainer: $( [] ),
       
   283 		errorLabelContainer: $( [] ),
       
   284 		onsubmit: true,
       
   285 		ignore: ":hidden",
       
   286 		ignoreTitle: false,
       
   287 		onfocusin: function( element ) {
       
   288 			this.lastActive = element;
       
   289 
       
   290 			// Hide error label and remove error class on focus if enabled
       
   291 			if ( this.settings.focusCleanup ) {
       
   292 				if ( this.settings.unhighlight ) {
       
   293 					this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
       
   294 				}
       
   295 				this.hideThese( this.errorsFor( element ) );
       
   296 			}
       
   297 		},
       
   298 		onfocusout: function( element ) {
       
   299 			if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
       
   300 				this.element( element );
       
   301 			}
       
   302 		},
       
   303 		onkeyup: function( element, event ) {
       
   304 
       
   305 			// Avoid revalidate the field when pressing one of the following keys
       
   306 			// Shift       => 16
       
   307 			// Ctrl        => 17
       
   308 			// Alt         => 18
       
   309 			// Caps lock   => 20
       
   310 			// End         => 35
       
   311 			// Home        => 36
       
   312 			// Left arrow  => 37
       
   313 			// Up arrow    => 38
       
   314 			// Right arrow => 39
       
   315 			// Down arrow  => 40
       
   316 			// Insert      => 45
       
   317 			// Num lock    => 144
       
   318 			// AltGr key   => 225
       
   319 			var excludedKeys = [
       
   320 				16, 17, 18, 20, 35, 36, 37,
       
   321 				38, 39, 40, 45, 144, 225
       
   322 			];
       
   323 
       
   324 			if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
       
   325 				return;
       
   326 			} else if ( element.name in this.submitted || element.name in this.invalid ) {
       
   327 				this.element( element );
       
   328 			}
       
   329 		},
       
   330 		onclick: function( element ) {
       
   331 
       
   332 			// Click on selects, radiobuttons and checkboxes
       
   333 			if ( element.name in this.submitted ) {
       
   334 				this.element( element );
       
   335 
       
   336 			// Or option elements, check parent select in that case
       
   337 			} else if ( element.parentNode.name in this.submitted ) {
       
   338 				this.element( element.parentNode );
       
   339 			}
       
   340 		},
       
   341 		highlight: function( element, errorClass, validClass ) {
       
   342 			if ( element.type === "radio" ) {
       
   343 				this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
       
   344 			} else {
       
   345 				$( element ).addClass( errorClass ).removeClass( validClass );
       
   346 			}
       
   347 		},
       
   348 		unhighlight: function( element, errorClass, validClass ) {
       
   349 			if ( element.type === "radio" ) {
       
   350 				this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
       
   351 			} else {
       
   352 				$( element ).removeClass( errorClass ).addClass( validClass );
       
   353 			}
       
   354 		}
       
   355 	},
       
   356 
       
   357 	// https://jqueryvalidation.org/jQuery.validator.setDefaults/
       
   358 	setDefaults: function( settings ) {
       
   359 		$.extend( $.validator.defaults, settings );
       
   360 	},
       
   361 
       
   362 	messages: {
       
   363 		required: "This field is required.",
       
   364 		remote: "Please fix this field.",
       
   365 		email: "Please enter a valid email address.",
       
   366 		url: "Please enter a valid URL.",
       
   367 		date: "Please enter a valid date.",
       
   368 		dateISO: "Please enter a valid date (ISO).",
       
   369 		number: "Please enter a valid number.",
       
   370 		digits: "Please enter only digits.",
       
   371 		equalTo: "Please enter the same value again.",
       
   372 		maxlength: $.validator.format( "Please enter no more than {0} characters." ),
       
   373 		minlength: $.validator.format( "Please enter at least {0} characters." ),
       
   374 		rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
       
   375 		range: $.validator.format( "Please enter a value between {0} and {1}." ),
       
   376 		max: $.validator.format( "Please enter a value less than or equal to {0}." ),
       
   377 		min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
       
   378 		step: $.validator.format( "Please enter a multiple of {0}." )
       
   379 	},
       
   380 
       
   381 	autoCreateRanges: false,
       
   382 
       
   383 	prototype: {
       
   384 
       
   385 		init: function() {
       
   386 			this.labelContainer = $( this.settings.errorLabelContainer );
       
   387 			this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
       
   388 			this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
       
   389 			this.submitted = {};
       
   390 			this.valueCache = {};
       
   391 			this.pendingRequest = 0;
       
   392 			this.pending = {};
       
   393 			this.invalid = {};
       
   394 			this.reset();
       
   395 
       
   396 			var groups = ( this.groups = {} ),
       
   397 				rules;
       
   398 			$.each( this.settings.groups, function( key, value ) {
       
   399 				if ( typeof value === "string" ) {
       
   400 					value = value.split( /\s/ );
       
   401 				}
       
   402 				$.each( value, function( index, name ) {
       
   403 					groups[ name ] = key;
       
   404 				} );
       
   405 			} );
       
   406 			rules = this.settings.rules;
       
   407 			$.each( rules, function( key, value ) {
       
   408 				rules[ key ] = $.validator.normalizeRule( value );
       
   409 			} );
       
   410 
       
   411 			function delegate( event ) {
       
   412 
       
   413 				// Set form expando on contenteditable
       
   414 				if ( !this.form && this.hasAttribute( "contenteditable" ) ) {
       
   415 					this.form = $( this ).closest( "form" )[ 0 ];
       
   416 					this.name = $( this ).attr( "name" );
       
   417 				}
       
   418 
       
   419 				var validator = $.data( this.form, "validator" ),
       
   420 					eventType = "on" + event.type.replace( /^validate/, "" ),
       
   421 					settings = validator.settings;
       
   422 				if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
       
   423 					settings[ eventType ].call( validator, this, event );
       
   424 				}
       
   425 			}
       
   426 
       
   427 			$( this.currentForm )
       
   428 				.on( "focusin.validate focusout.validate keyup.validate",
       
   429 					":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
       
   430 					"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
       
   431 					"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
       
   432 					"[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )
       
   433 
       
   434 				// Support: Chrome, oldIE
       
   435 				// "select" is provided as event.target when clicking a option
       
   436 				.on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );
       
   437 
       
   438 			if ( this.settings.invalidHandler ) {
       
   439 				$( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
       
   440 			}
       
   441 		},
       
   442 
       
   443 		// https://jqueryvalidation.org/Validator.form/
       
   444 		form: function() {
       
   445 			this.checkForm();
       
   446 			$.extend( this.submitted, this.errorMap );
       
   447 			this.invalid = $.extend( {}, this.errorMap );
       
   448 			if ( !this.valid() ) {
       
   449 				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
       
   450 			}
       
   451 			this.showErrors();
       
   452 			return this.valid();
       
   453 		},
       
   454 
       
   455 		checkForm: function() {
       
   456 			this.prepareForm();
       
   457 			for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
       
   458 				this.check( elements[ i ] );
       
   459 			}
       
   460 			return this.valid();
       
   461 		},
       
   462 
       
   463 		// https://jqueryvalidation.org/Validator.element/
       
   464 		element: function( element ) {
       
   465 			var cleanElement = this.clean( element ),
       
   466 				checkElement = this.validationTargetFor( cleanElement ),
       
   467 				v = this,
       
   468 				result = true,
       
   469 				rs, group;
       
   470 
       
   471 			if ( checkElement === undefined ) {
       
   472 				delete this.invalid[ cleanElement.name ];
       
   473 			} else {
       
   474 				this.prepareElement( checkElement );
       
   475 				this.currentElements = $( checkElement );
       
   476 
       
   477 				// If this element is grouped, then validate all group elements already
       
   478 				// containing a value
       
   479 				group = this.groups[ checkElement.name ];
       
   480 				if ( group ) {
       
   481 					$.each( this.groups, function( name, testgroup ) {
       
   482 						if ( testgroup === group && name !== checkElement.name ) {
       
   483 							cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
       
   484 							if ( cleanElement && cleanElement.name in v.invalid ) {
       
   485 								v.currentElements.push( cleanElement );
       
   486 								result = v.check( cleanElement ) && result;
       
   487 							}
       
   488 						}
       
   489 					} );
       
   490 				}
       
   491 
       
   492 				rs = this.check( checkElement ) !== false;
       
   493 				result = result && rs;
       
   494 				if ( rs ) {
       
   495 					this.invalid[ checkElement.name ] = false;
       
   496 				} else {
       
   497 					this.invalid[ checkElement.name ] = true;
       
   498 				}
       
   499 
       
   500 				if ( !this.numberOfInvalids() ) {
       
   501 
       
   502 					// Hide error containers on last error
       
   503 					this.toHide = this.toHide.add( this.containers );
       
   504 				}
       
   505 				this.showErrors();
       
   506 
       
   507 				// Add aria-invalid status for screen readers
       
   508 				$( element ).attr( "aria-invalid", !rs );
       
   509 			}
       
   510 
       
   511 			return result;
       
   512 		},
       
   513 
       
   514 		// https://jqueryvalidation.org/Validator.showErrors/
       
   515 		showErrors: function( errors ) {
       
   516 			if ( errors ) {
       
   517 				var validator = this;
       
   518 
       
   519 				// Add items to error list and map
       
   520 				$.extend( this.errorMap, errors );
       
   521 				this.errorList = $.map( this.errorMap, function( message, name ) {
       
   522 					return {
       
   523 						message: message,
       
   524 						element: validator.findByName( name )[ 0 ]
       
   525 					};
       
   526 				} );
       
   527 
       
   528 				// Remove items from success list
       
   529 				this.successList = $.grep( this.successList, function( element ) {
       
   530 					return !( element.name in errors );
       
   531 				} );
       
   532 			}
       
   533 			if ( this.settings.showErrors ) {
       
   534 				this.settings.showErrors.call( this, this.errorMap, this.errorList );
       
   535 			} else {
       
   536 				this.defaultShowErrors();
       
   537 			}
       
   538 		},
       
   539 
       
   540 		// https://jqueryvalidation.org/Validator.resetForm/
       
   541 		resetForm: function() {
       
   542 			if ( $.fn.resetForm ) {
       
   543 				$( this.currentForm ).resetForm();
       
   544 			}
       
   545 			this.invalid = {};
       
   546 			this.submitted = {};
       
   547 			this.prepareForm();
       
   548 			this.hideErrors();
       
   549 			var elements = this.elements()
       
   550 				.removeData( "previousValue" )
       
   551 				.removeAttr( "aria-invalid" );
       
   552 
       
   553 			this.resetElements( elements );
       
   554 		},
       
   555 
       
   556 		resetElements: function( elements ) {
       
   557 			var i;
       
   558 
       
   559 			if ( this.settings.unhighlight ) {
       
   560 				for ( i = 0; elements[ i ]; i++ ) {
       
   561 					this.settings.unhighlight.call( this, elements[ i ],
       
   562 						this.settings.errorClass, "" );
       
   563 					this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
       
   564 				}
       
   565 			} else {
       
   566 				elements
       
   567 					.removeClass( this.settings.errorClass )
       
   568 					.removeClass( this.settings.validClass );
       
   569 			}
       
   570 		},
       
   571 
       
   572 		numberOfInvalids: function() {
       
   573 			return this.objectLength( this.invalid );
       
   574 		},
       
   575 
       
   576 		objectLength: function( obj ) {
       
   577 			/* jshint unused: false */
       
   578 			var count = 0,
       
   579 				i;
       
   580 			for ( i in obj ) {
       
   581 
       
   582 				// This check allows counting elements with empty error
       
   583 				// message as invalid elements
       
   584 				if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
       
   585 					count++;
       
   586 				}
       
   587 			}
       
   588 			return count;
       
   589 		},
       
   590 
       
   591 		hideErrors: function() {
       
   592 			this.hideThese( this.toHide );
       
   593 		},
       
   594 
       
   595 		hideThese: function( errors ) {
       
   596 			errors.not( this.containers ).text( "" );
       
   597 			this.addWrapper( errors ).hide();
       
   598 		},
       
   599 
       
   600 		valid: function() {
       
   601 			return this.size() === 0;
       
   602 		},
       
   603 
       
   604 		size: function() {
       
   605 			return this.errorList.length;
       
   606 		},
       
   607 
       
   608 		focusInvalid: function() {
       
   609 			if ( this.settings.focusInvalid ) {
       
   610 				try {
       
   611 					$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
       
   612 					.filter( ":visible" )
       
   613 					.focus()
       
   614 
       
   615 					// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
       
   616 					.trigger( "focusin" );
       
   617 				} catch ( e ) {
       
   618 
       
   619 					// Ignore IE throwing errors when focusing hidden elements
       
   620 				}
       
   621 			}
       
   622 		},
       
   623 
       
   624 		findLastActive: function() {
       
   625 			var lastActive = this.lastActive;
       
   626 			return lastActive && $.grep( this.errorList, function( n ) {
       
   627 				return n.element.name === lastActive.name;
       
   628 			} ).length === 1 && lastActive;
       
   629 		},
       
   630 
       
   631 		elements: function() {
       
   632 			var validator = this,
       
   633 				rulesCache = {};
       
   634 
       
   635 			// Select all valid inputs inside the form (no submit or reset buttons)
       
   636 			return $( this.currentForm )
       
   637 			.find( "input, select, textarea, [contenteditable]" )
       
   638 			.not( ":submit, :reset, :image, :disabled" )
       
   639 			.not( this.settings.ignore )
       
   640 			.filter( function() {
       
   641 				var name = this.name || $( this ).attr( "name" ); // For contenteditable
       
   642 				if ( !name && validator.settings.debug && window.console ) {
       
   643 					console.error( "%o has no name assigned", this );
       
   644 				}
       
   645 
       
   646 				// Set form expando on contenteditable
       
   647 				if ( this.hasAttribute( "contenteditable" ) ) {
       
   648 					this.form = $( this ).closest( "form" )[ 0 ];
       
   649 					this.name = name;
       
   650 				}
       
   651 
       
   652 				// Select only the first element for each name, and only those with rules specified
       
   653 				if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
       
   654 					return false;
       
   655 				}
       
   656 
       
   657 				rulesCache[ name ] = true;
       
   658 				return true;
       
   659 			} );
       
   660 		},
       
   661 
       
   662 		clean: function( selector ) {
       
   663 			return $( selector )[ 0 ];
       
   664 		},
       
   665 
       
   666 		errors: function() {
       
   667 			var errorClass = this.settings.errorClass.split( " " ).join( "." );
       
   668 			return $( this.settings.errorElement + "." + errorClass, this.errorContext );
       
   669 		},
       
   670 
       
   671 		resetInternals: function() {
       
   672 			this.successList = [];
       
   673 			this.errorList = [];
       
   674 			this.errorMap = {};
       
   675 			this.toShow = $( [] );
       
   676 			this.toHide = $( [] );
       
   677 		},
       
   678 
       
   679 		reset: function() {
       
   680 			this.resetInternals();
       
   681 			this.currentElements = $( [] );
       
   682 		},
       
   683 
       
   684 		prepareForm: function() {
       
   685 			this.reset();
       
   686 			this.toHide = this.errors().add( this.containers );
       
   687 		},
       
   688 
       
   689 		prepareElement: function( element ) {
       
   690 			this.reset();
       
   691 			this.toHide = this.errorsFor( element );
       
   692 		},
       
   693 
       
   694 		elementValue: function( element ) {
       
   695 			var $element = $( element ),
       
   696 				type = element.type,
       
   697 				val, idx;
       
   698 
       
   699 			if ( type === "radio" || type === "checkbox" ) {
       
   700 				return this.findByName( element.name ).filter( ":checked" ).val();
       
   701 			} else if ( type === "number" && typeof element.validity !== "undefined" ) {
       
   702 				return element.validity.badInput ? "NaN" : $element.val();
       
   703 			}
       
   704 
       
   705 			if ( element.hasAttribute( "contenteditable" ) ) {
       
   706 				val = $element.text();
       
   707 			} else {
       
   708 				val = $element.val();
       
   709 			}
       
   710 
       
   711 			if ( type === "file" ) {
       
   712 
       
   713 				// Modern browser (chrome & safari)
       
   714 				if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
       
   715 					return val.substr( 12 );
       
   716 				}
       
   717 
       
   718 				// Legacy browsers
       
   719 				// Unix-based path
       
   720 				idx = val.lastIndexOf( "/" );
       
   721 				if ( idx >= 0 ) {
       
   722 					return val.substr( idx + 1 );
       
   723 				}
       
   724 
       
   725 				// Windows-based path
       
   726 				idx = val.lastIndexOf( "\\" );
       
   727 				if ( idx >= 0 ) {
       
   728 					return val.substr( idx + 1 );
       
   729 				}
       
   730 
       
   731 				// Just the file name
       
   732 				return val;
       
   733 			}
       
   734 
       
   735 			if ( typeof val === "string" ) {
       
   736 				return val.replace( /\r/g, "" );
       
   737 			}
       
   738 			return val;
       
   739 		},
       
   740 
       
   741 		check: function( element ) {
       
   742 			element = this.validationTargetFor( this.clean( element ) );
       
   743 
       
   744 			var rules = $( element ).rules(),
       
   745 				rulesCount = $.map( rules, function( n, i ) {
       
   746 					return i;
       
   747 				} ).length,
       
   748 				dependencyMismatch = false,
       
   749 				val = this.elementValue( element ),
       
   750 				result, method, rule, normalizer;
       
   751 
       
   752 			// Prioritize the local normalizer defined for this element over the global one
       
   753 			// if the former exists, otherwise user the global one in case it exists.
       
   754 			if ( typeof rules.normalizer === "function" ) {
       
   755 				normalizer = rules.normalizer;
       
   756 			} else if (	typeof this.settings.normalizer === "function" ) {
       
   757 				normalizer = this.settings.normalizer;
       
   758 			}
       
   759 
       
   760 			// If normalizer is defined, then call it to retreive the changed value instead
       
   761 			// of using the real one.
       
   762 			// Note that `this` in the normalizer is `element`.
       
   763 			if ( normalizer ) {
       
   764 				val = normalizer.call( element, val );
       
   765 
       
   766 				if ( typeof val !== "string" ) {
       
   767 					throw new TypeError( "The normalizer should return a string value." );
       
   768 				}
       
   769 
       
   770 				// Delete the normalizer from rules to avoid treating it as a pre-defined method.
       
   771 				delete rules.normalizer;
       
   772 			}
       
   773 
       
   774 			for ( method in rules ) {
       
   775 				rule = { method: method, parameters: rules[ method ] };
       
   776 				try {
       
   777 					result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
       
   778 
       
   779 					// If a method indicates that the field is optional and therefore valid,
       
   780 					// don't mark it as valid when there are no other rules
       
   781 					if ( result === "dependency-mismatch" && rulesCount === 1 ) {
       
   782 						dependencyMismatch = true;
       
   783 						continue;
       
   784 					}
       
   785 					dependencyMismatch = false;
       
   786 
       
   787 					if ( result === "pending" ) {
       
   788 						this.toHide = this.toHide.not( this.errorsFor( element ) );
       
   789 						return;
       
   790 					}
       
   791 
       
   792 					if ( !result ) {
       
   793 						this.formatAndAdd( element, rule );
       
   794 						return false;
       
   795 					}
       
   796 				} catch ( e ) {
       
   797 					if ( this.settings.debug && window.console ) {
       
   798 						console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
       
   799 					}
       
   800 					if ( e instanceof TypeError ) {
       
   801 						e.message += ".  Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
       
   802 					}
       
   803 
       
   804 					throw e;
       
   805 				}
       
   806 			}
       
   807 			if ( dependencyMismatch ) {
       
   808 				return;
       
   809 			}
       
   810 			if ( this.objectLength( rules ) ) {
       
   811 				this.successList.push( element );
       
   812 			}
       
   813 			return true;
       
   814 		},
       
   815 
       
   816 		// Return the custom message for the given element and validation method
       
   817 		// specified in the element's HTML5 data attribute
       
   818 		// return the generic message if present and no method specific message is present
       
   819 		customDataMessage: function( element, method ) {
       
   820 			return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
       
   821 				method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
       
   822 		},
       
   823 
       
   824 		// Return the custom message for the given element name and validation method
       
   825 		customMessage: function( name, method ) {
       
   826 			var m = this.settings.messages[ name ];
       
   827 			return m && ( m.constructor === String ? m : m[ method ] );
       
   828 		},
       
   829 
       
   830 		// Return the first defined argument, allowing empty strings
       
   831 		findDefined: function() {
       
   832 			for ( var i = 0; i < arguments.length; i++ ) {
       
   833 				if ( arguments[ i ] !== undefined ) {
       
   834 					return arguments[ i ];
       
   835 				}
       
   836 			}
       
   837 			return undefined;
       
   838 		},
       
   839 
       
   840 		// The second parameter 'rule' used to be a string, and extended to an object literal
       
   841 		// of the following form:
       
   842 		// rule = {
       
   843 		//     method: "method name",
       
   844 		//     parameters: "the given method parameters"
       
   845 		// }
       
   846 		//
       
   847 		// The old behavior still supported, kept to maintain backward compatibility with
       
   848 		// old code, and will be removed in the next major release.
       
   849 		defaultMessage: function( element, rule ) {
       
   850 			if ( typeof rule === "string" ) {
       
   851 				rule = { method: rule };
       
   852 			}
       
   853 
       
   854 			var message = this.findDefined(
       
   855 					this.customMessage( element.name, rule.method ),
       
   856 					this.customDataMessage( element, rule.method ),
       
   857 
       
   858 					// 'title' is never undefined, so handle empty string as undefined
       
   859 					!this.settings.ignoreTitle && element.title || undefined,
       
   860 					$.validator.messages[ rule.method ],
       
   861 					"<strong>Warning: No message defined for " + element.name + "</strong>"
       
   862 				),
       
   863 				theregex = /\$?\{(\d+)\}/g;
       
   864 			if ( typeof message === "function" ) {
       
   865 				message = message.call( this, rule.parameters, element );
       
   866 			} else if ( theregex.test( message ) ) {
       
   867 				message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
       
   868 			}
       
   869 
       
   870 			return message;
       
   871 		},
       
   872 
       
   873 		formatAndAdd: function( element, rule ) {
       
   874 			var message = this.defaultMessage( element, rule );
       
   875 
       
   876 			this.errorList.push( {
       
   877 				message: message,
       
   878 				element: element,
       
   879 				method: rule.method
       
   880 			} );
       
   881 
       
   882 			this.errorMap[ element.name ] = message;
       
   883 			this.submitted[ element.name ] = message;
       
   884 		},
       
   885 
       
   886 		addWrapper: function( toToggle ) {
       
   887 			if ( this.settings.wrapper ) {
       
   888 				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
       
   889 			}
       
   890 			return toToggle;
       
   891 		},
       
   892 
       
   893 		defaultShowErrors: function() {
       
   894 			var i, elements, error;
       
   895 			for ( i = 0; this.errorList[ i ]; i++ ) {
       
   896 				error = this.errorList[ i ];
       
   897 				if ( this.settings.highlight ) {
       
   898 					this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
       
   899 				}
       
   900 				this.showLabel( error.element, error.message );
       
   901 			}
       
   902 			if ( this.errorList.length ) {
       
   903 				this.toShow = this.toShow.add( this.containers );
       
   904 			}
       
   905 			if ( this.settings.success ) {
       
   906 				for ( i = 0; this.successList[ i ]; i++ ) {
       
   907 					this.showLabel( this.successList[ i ] );
       
   908 				}
       
   909 			}
       
   910 			if ( this.settings.unhighlight ) {
       
   911 				for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
       
   912 					this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
       
   913 				}
       
   914 			}
       
   915 			this.toHide = this.toHide.not( this.toShow );
       
   916 			this.hideErrors();
       
   917 			this.addWrapper( this.toShow ).show();
       
   918 		},
       
   919 
       
   920 		validElements: function() {
       
   921 			return this.currentElements.not( this.invalidElements() );
       
   922 		},
       
   923 
       
   924 		invalidElements: function() {
       
   925 			return $( this.errorList ).map( function() {
       
   926 				return this.element;
       
   927 			} );
       
   928 		},
       
   929 
       
   930 		showLabel: function( element, message ) {
       
   931 			var place, group, errorID, v,
       
   932 				error = this.errorsFor( element ),
       
   933 				elementID = this.idOrName( element ),
       
   934 				describedBy = $( element ).attr( "aria-describedby" );
       
   935 
       
   936 			if ( error.length ) {
       
   937 
       
   938 				// Refresh error/success class
       
   939 				error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
       
   940 
       
   941 				// Replace message on existing label
       
   942 				error.html( message );
       
   943 			} else {
       
   944 
       
   945 				// Create error element
       
   946 				error = $( "<" + this.settings.errorElement + ">" )
       
   947 					.attr( "id", elementID + "-error" )
       
   948 					.addClass( this.settings.errorClass )
       
   949 					.html( message || "" );
       
   950 
       
   951 				// Maintain reference to the element to be placed into the DOM
       
   952 				place = error;
       
   953 				if ( this.settings.wrapper ) {
       
   954 
       
   955 					// Make sure the element is visible, even in IE
       
   956 					// actually showing the wrapped element is handled elsewhere
       
   957 					place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
       
   958 				}
       
   959 				if ( this.labelContainer.length ) {
       
   960 					this.labelContainer.append( place );
       
   961 				} else if ( this.settings.errorPlacement ) {
       
   962 					this.settings.errorPlacement.call( this, place, $( element ) );
       
   963 				} else {
       
   964 					place.insertAfter( element );
       
   965 				}
       
   966 
       
   967 				// Link error back to the element
       
   968 				if ( error.is( "label" ) ) {
       
   969 
       
   970 					// If the error is a label, then associate using 'for'
       
   971 					error.attr( "for", elementID );
       
   972 
       
   973 					// If the element is not a child of an associated label, then it's necessary
       
   974 					// to explicitly apply aria-describedby
       
   975 				} else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
       
   976 					errorID = error.attr( "id" );
       
   977 
       
   978 					// Respect existing non-error aria-describedby
       
   979 					if ( !describedBy ) {
       
   980 						describedBy = errorID;
       
   981 					} else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {
       
   982 
       
   983 						// Add to end of list if not already present
       
   984 						describedBy += " " + errorID;
       
   985 					}
       
   986 					$( element ).attr( "aria-describedby", describedBy );
       
   987 
       
   988 					// If this element is grouped, then assign to all elements in the same group
       
   989 					group = this.groups[ element.name ];
       
   990 					if ( group ) {
       
   991 						v = this;
       
   992 						$.each( v.groups, function( name, testgroup ) {
       
   993 							if ( testgroup === group ) {
       
   994 								$( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
       
   995 									.attr( "aria-describedby", error.attr( "id" ) );
       
   996 							}
       
   997 						} );
       
   998 					}
       
   999 				}
       
  1000 			}
       
  1001 			if ( !message && this.settings.success ) {
       
  1002 				error.text( "" );
       
  1003 				if ( typeof this.settings.success === "string" ) {
       
  1004 					error.addClass( this.settings.success );
       
  1005 				} else {
       
  1006 					this.settings.success( error, element );
       
  1007 				}
       
  1008 			}
       
  1009 			this.toShow = this.toShow.add( error );
       
  1010 		},
       
  1011 
       
  1012 		errorsFor: function( element ) {
       
  1013 			var name = this.escapeCssMeta( this.idOrName( element ) ),
       
  1014 				describer = $( element ).attr( "aria-describedby" ),
       
  1015 				selector = "label[for='" + name + "'], label[for='" + name + "'] *";
       
  1016 
       
  1017 			// 'aria-describedby' should directly reference the error element
       
  1018 			if ( describer ) {
       
  1019 				selector = selector + ", #" + this.escapeCssMeta( describer )
       
  1020 					.replace( /\s+/g, ", #" );
       
  1021 			}
       
  1022 
       
  1023 			return this
       
  1024 				.errors()
       
  1025 				.filter( selector );
       
  1026 		},
       
  1027 
       
  1028 		// See https://api.jquery.com/category/selectors/, for CSS
       
  1029 		// meta-characters that should be escaped in order to be used with JQuery
       
  1030 		// as a literal part of a name/id or any selector.
       
  1031 		escapeCssMeta: function( string ) {
       
  1032 			return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
       
  1033 		},
       
  1034 
       
  1035 		idOrName: function( element ) {
       
  1036 			return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
       
  1037 		},
       
  1038 
       
  1039 		validationTargetFor: function( element ) {
       
  1040 
       
  1041 			// If radio/checkbox, validate first element in group instead
       
  1042 			if ( this.checkable( element ) ) {
       
  1043 				element = this.findByName( element.name );
       
  1044 			}
       
  1045 
       
  1046 			// Always apply ignore filter
       
  1047 			return $( element ).not( this.settings.ignore )[ 0 ];
       
  1048 		},
       
  1049 
       
  1050 		checkable: function( element ) {
       
  1051 			return ( /radio|checkbox/i ).test( element.type );
       
  1052 		},
       
  1053 
       
  1054 		findByName: function( name ) {
       
  1055 			return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
       
  1056 		},
       
  1057 
       
  1058 		getLength: function( value, element ) {
       
  1059 			switch ( element.nodeName.toLowerCase() ) {
       
  1060 			case "select":
       
  1061 				return $( "option:selected", element ).length;
       
  1062 			case "input":
       
  1063 				if ( this.checkable( element ) ) {
       
  1064 					return this.findByName( element.name ).filter( ":checked" ).length;
       
  1065 				}
       
  1066 			}
       
  1067 			return value.length;
       
  1068 		},
       
  1069 
       
  1070 		depend: function( param, element ) {
       
  1071 			return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
       
  1072 		},
       
  1073 
       
  1074 		dependTypes: {
       
  1075 			"boolean": function( param ) {
       
  1076 				return param;
       
  1077 			},
       
  1078 			"string": function( param, element ) {
       
  1079 				return !!$( param, element.form ).length;
       
  1080 			},
       
  1081 			"function": function( param, element ) {
       
  1082 				return param( element );
       
  1083 			}
       
  1084 		},
       
  1085 
       
  1086 		optional: function( element ) {
       
  1087 			var val = this.elementValue( element );
       
  1088 			return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
       
  1089 		},
       
  1090 
       
  1091 		startRequest: function( element ) {
       
  1092 			if ( !this.pending[ element.name ] ) {
       
  1093 				this.pendingRequest++;
       
  1094 				$( element ).addClass( this.settings.pendingClass );
       
  1095 				this.pending[ element.name ] = true;
       
  1096 			}
       
  1097 		},
       
  1098 
       
  1099 		stopRequest: function( element, valid ) {
       
  1100 			this.pendingRequest--;
       
  1101 
       
  1102 			// Sometimes synchronization fails, make sure pendingRequest is never < 0
       
  1103 			if ( this.pendingRequest < 0 ) {
       
  1104 				this.pendingRequest = 0;
       
  1105 			}
       
  1106 			delete this.pending[ element.name ];
       
  1107 			$( element ).removeClass( this.settings.pendingClass );
       
  1108 			if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
       
  1109 				$( this.currentForm ).submit();
       
  1110 
       
  1111 				// Remove the hidden input that was used as a replacement for the
       
  1112 				// missing submit button. The hidden input is added by `handle()`
       
  1113 				// to ensure that the value of the used submit button is passed on
       
  1114 				// for scripted submits triggered by this method
       
  1115 				if ( this.submitButton ) {
       
  1116 					$( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
       
  1117 				}
       
  1118 
       
  1119 				this.formSubmitted = false;
       
  1120 			} else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
       
  1121 				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
       
  1122 				this.formSubmitted = false;
       
  1123 			}
       
  1124 		},
       
  1125 
       
  1126 		previousValue: function( element, method ) {
       
  1127 			method = typeof method === "string" && method || "remote";
       
  1128 
       
  1129 			return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
       
  1130 				old: null,
       
  1131 				valid: true,
       
  1132 				message: this.defaultMessage( element, { method: method } )
       
  1133 			} );
       
  1134 		},
       
  1135 
       
  1136 		// Cleans up all forms and elements, removes validator-specific events
       
  1137 		destroy: function() {
       
  1138 			this.resetForm();
       
  1139 
       
  1140 			$( this.currentForm )
       
  1141 				.off( ".validate" )
       
  1142 				.removeData( "validator" )
       
  1143 				.find( ".validate-equalTo-blur" )
       
  1144 					.off( ".validate-equalTo" )
       
  1145 					.removeClass( "validate-equalTo-blur" );
       
  1146 		}
       
  1147 
       
  1148 	},
       
  1149 
       
  1150 	classRuleSettings: {
       
  1151 		required: { required: true },
       
  1152 		email: { email: true },
       
  1153 		url: { url: true },
       
  1154 		date: { date: true },
       
  1155 		dateISO: { dateISO: true },
       
  1156 		number: { number: true },
       
  1157 		digits: { digits: true },
       
  1158 		creditcard: { creditcard: true }
       
  1159 	},
       
  1160 
       
  1161 	addClassRules: function( className, rules ) {
       
  1162 		if ( className.constructor === String ) {
       
  1163 			this.classRuleSettings[ className ] = rules;
       
  1164 		} else {
       
  1165 			$.extend( this.classRuleSettings, className );
       
  1166 		}
       
  1167 	},
       
  1168 
       
  1169 	classRules: function( element ) {
       
  1170 		var rules = {},
       
  1171 			classes = $( element ).attr( "class" );
       
  1172 
       
  1173 		if ( classes ) {
       
  1174 			$.each( classes.split( " " ), function() {
       
  1175 				if ( this in $.validator.classRuleSettings ) {
       
  1176 					$.extend( rules, $.validator.classRuleSettings[ this ] );
       
  1177 				}
       
  1178 			} );
       
  1179 		}
       
  1180 		return rules;
       
  1181 	},
       
  1182 
       
  1183 	normalizeAttributeRule: function( rules, type, method, value ) {
       
  1184 
       
  1185 		// Convert the value to a number for number inputs, and for text for backwards compability
       
  1186 		// allows type="date" and others to be compared as strings
       
  1187 		if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
       
  1188 			value = Number( value );
       
  1189 
       
  1190 			// Support Opera Mini, which returns NaN for undefined minlength
       
  1191 			if ( isNaN( value ) ) {
       
  1192 				value = undefined;
       
  1193 			}
       
  1194 		}
       
  1195 
       
  1196 		if ( value || value === 0 ) {
       
  1197 			rules[ method ] = value;
       
  1198 		} else if ( type === method && type !== "range" ) {
       
  1199 
       
  1200 			// Exception: the jquery validate 'range' method
       
  1201 			// does not test for the html5 'range' type
       
  1202 			rules[ method ] = true;
       
  1203 		}
       
  1204 	},
       
  1205 
       
  1206 	attributeRules: function( element ) {
       
  1207 		var rules = {},
       
  1208 			$element = $( element ),
       
  1209 			type = element.getAttribute( "type" ),
       
  1210 			method, value;
       
  1211 
       
  1212 		for ( method in $.validator.methods ) {
       
  1213 
       
  1214 			// Support for <input required> in both html5 and older browsers
       
  1215 			if ( method === "required" ) {
       
  1216 				value = element.getAttribute( method );
       
  1217 
       
  1218 				// Some browsers return an empty string for the required attribute
       
  1219 				// and non-HTML5 browsers might have required="" markup
       
  1220 				if ( value === "" ) {
       
  1221 					value = true;
       
  1222 				}
       
  1223 
       
  1224 				// Force non-HTML5 browsers to return bool
       
  1225 				value = !!value;
       
  1226 			} else {
       
  1227 				value = $element.attr( method );
       
  1228 			}
       
  1229 
       
  1230 			this.normalizeAttributeRule( rules, type, method, value );
       
  1231 		}
       
  1232 
       
  1233 		// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
       
  1234 		if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
       
  1235 			delete rules.maxlength;
       
  1236 		}
       
  1237 
       
  1238 		return rules;
       
  1239 	},
       
  1240 
       
  1241 	dataRules: function( element ) {
       
  1242 		var rules = {},
       
  1243 			$element = $( element ),
       
  1244 			type = element.getAttribute( "type" ),
       
  1245 			method, value;
       
  1246 
       
  1247 		for ( method in $.validator.methods ) {
       
  1248 			value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
       
  1249 			this.normalizeAttributeRule( rules, type, method, value );
       
  1250 		}
       
  1251 		return rules;
       
  1252 	},
       
  1253 
       
  1254 	staticRules: function( element ) {
       
  1255 		var rules = {},
       
  1256 			validator = $.data( element.form, "validator" );
       
  1257 
       
  1258 		if ( validator.settings.rules ) {
       
  1259 			rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
       
  1260 		}
       
  1261 		return rules;
       
  1262 	},
       
  1263 
       
  1264 	normalizeRules: function( rules, element ) {
       
  1265 
       
  1266 		// Handle dependency check
       
  1267 		$.each( rules, function( prop, val ) {
       
  1268 
       
  1269 			// Ignore rule when param is explicitly false, eg. required:false
       
  1270 			if ( val === false ) {
       
  1271 				delete rules[ prop ];
       
  1272 				return;
       
  1273 			}
       
  1274 			if ( val.param || val.depends ) {
       
  1275 				var keepRule = true;
       
  1276 				switch ( typeof val.depends ) {
       
  1277 				case "string":
       
  1278 					keepRule = !!$( val.depends, element.form ).length;
       
  1279 					break;
       
  1280 				case "function":
       
  1281 					keepRule = val.depends.call( element, element );
       
  1282 					break;
       
  1283 				}
       
  1284 				if ( keepRule ) {
       
  1285 					rules[ prop ] = val.param !== undefined ? val.param : true;
       
  1286 				} else {
       
  1287 					$.data( element.form, "validator" ).resetElements( $( element ) );
       
  1288 					delete rules[ prop ];
       
  1289 				}
       
  1290 			}
       
  1291 		} );
       
  1292 
       
  1293 		// Evaluate parameters
       
  1294 		$.each( rules, function( rule, parameter ) {
       
  1295 			rules[ rule ] = $.isFunction( parameter ) && rule !== "normalizer" ? parameter( element ) : parameter;
       
  1296 		} );
       
  1297 
       
  1298 		// Clean number parameters
       
  1299 		$.each( [ "minlength", "maxlength" ], function() {
       
  1300 			if ( rules[ this ] ) {
       
  1301 				rules[ this ] = Number( rules[ this ] );
       
  1302 			}
       
  1303 		} );
       
  1304 		$.each( [ "rangelength", "range" ], function() {
       
  1305 			var parts;
       
  1306 			if ( rules[ this ] ) {
       
  1307 				if ( $.isArray( rules[ this ] ) ) {
       
  1308 					rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
       
  1309 				} else if ( typeof rules[ this ] === "string" ) {
       
  1310 					parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
       
  1311 					rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
       
  1312 				}
       
  1313 			}
       
  1314 		} );
       
  1315 
       
  1316 		if ( $.validator.autoCreateRanges ) {
       
  1317 
       
  1318 			// Auto-create ranges
       
  1319 			if ( rules.min != null && rules.max != null ) {
       
  1320 				rules.range = [ rules.min, rules.max ];
       
  1321 				delete rules.min;
       
  1322 				delete rules.max;
       
  1323 			}
       
  1324 			if ( rules.minlength != null && rules.maxlength != null ) {
       
  1325 				rules.rangelength = [ rules.minlength, rules.maxlength ];
       
  1326 				delete rules.minlength;
       
  1327 				delete rules.maxlength;
       
  1328 			}
       
  1329 		}
       
  1330 
       
  1331 		return rules;
       
  1332 	},
       
  1333 
       
  1334 	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
       
  1335 	normalizeRule: function( data ) {
       
  1336 		if ( typeof data === "string" ) {
       
  1337 			var transformed = {};
       
  1338 			$.each( data.split( /\s/ ), function() {
       
  1339 				transformed[ this ] = true;
       
  1340 			} );
       
  1341 			data = transformed;
       
  1342 		}
       
  1343 		return data;
       
  1344 	},
       
  1345 
       
  1346 	// https://jqueryvalidation.org/jQuery.validator.addMethod/
       
  1347 	addMethod: function( name, method, message ) {
       
  1348 		$.validator.methods[ name ] = method;
       
  1349 		$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
       
  1350 		if ( method.length < 3 ) {
       
  1351 			$.validator.addClassRules( name, $.validator.normalizeRule( name ) );
       
  1352 		}
       
  1353 	},
       
  1354 
       
  1355 	// https://jqueryvalidation.org/jQuery.validator.methods/
       
  1356 	methods: {
       
  1357 
       
  1358 		// https://jqueryvalidation.org/required-method/
       
  1359 		required: function( value, element, param ) {
       
  1360 
       
  1361 			// Check if dependency is met
       
  1362 			if ( !this.depend( param, element ) ) {
       
  1363 				return "dependency-mismatch";
       
  1364 			}
       
  1365 			if ( element.nodeName.toLowerCase() === "select" ) {
       
  1366 
       
  1367 				// Could be an array for select-multiple or a string, both are fine this way
       
  1368 				var val = $( element ).val();
       
  1369 				return val && val.length > 0;
       
  1370 			}
       
  1371 			if ( this.checkable( element ) ) {
       
  1372 				return this.getLength( value, element ) > 0;
       
  1373 			}
       
  1374 			return value.length > 0;
       
  1375 		},
       
  1376 
       
  1377 		// https://jqueryvalidation.org/email-method/
       
  1378 		email: function( value, element ) {
       
  1379 
       
  1380 			// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
       
  1381 			// Retrieved 2014-01-14
       
  1382 			// If you have a problem with this implementation, report a bug against the above spec
       
  1383 			// Or use custom methods to implement your own email validation
       
  1384 			return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
       
  1385 		},
       
  1386 
       
  1387 		// https://jqueryvalidation.org/url-method/
       
  1388 		url: function( value, element ) {
       
  1389 
       
  1390 			// Copyright (c) 2010-2013 Diego Perini, MIT licensed
       
  1391 			// https://gist.github.com/dperini/729294
       
  1392 			// see also https://mathiasbynens.be/demo/url-regex
       
  1393 			// modified to allow protocol-relative URLs
       
  1394 			return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
       
  1395 		},
       
  1396 
       
  1397 		// https://jqueryvalidation.org/date-method/
       
  1398 		date: function( value, element ) {
       
  1399 			return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
       
  1400 		},
       
  1401 
       
  1402 		// https://jqueryvalidation.org/dateISO-method/
       
  1403 		dateISO: function( value, element ) {
       
  1404 			return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
       
  1405 		},
       
  1406 
       
  1407 		// https://jqueryvalidation.org/number-method/
       
  1408 		number: function( value, element ) {
       
  1409 			return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
       
  1410 		},
       
  1411 
       
  1412 		// https://jqueryvalidation.org/digits-method/
       
  1413 		digits: function( value, element ) {
       
  1414 			return this.optional( element ) || /^\d+$/.test( value );
       
  1415 		},
       
  1416 
       
  1417 		// https://jqueryvalidation.org/minlength-method/
       
  1418 		minlength: function( value, element, param ) {
       
  1419 			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
       
  1420 			return this.optional( element ) || length >= param;
       
  1421 		},
       
  1422 
       
  1423 		// https://jqueryvalidation.org/maxlength-method/
       
  1424 		maxlength: function( value, element, param ) {
       
  1425 			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
       
  1426 			return this.optional( element ) || length <= param;
       
  1427 		},
       
  1428 
       
  1429 		// https://jqueryvalidation.org/rangelength-method/
       
  1430 		rangelength: function( value, element, param ) {
       
  1431 			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
       
  1432 			return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
       
  1433 		},
       
  1434 
       
  1435 		// https://jqueryvalidation.org/min-method/
       
  1436 		min: function( value, element, param ) {
       
  1437 			return this.optional( element ) || value >= param;
       
  1438 		},
       
  1439 
       
  1440 		// https://jqueryvalidation.org/max-method/
       
  1441 		max: function( value, element, param ) {
       
  1442 			return this.optional( element ) || value <= param;
       
  1443 		},
       
  1444 
       
  1445 		// https://jqueryvalidation.org/range-method/
       
  1446 		range: function( value, element, param ) {
       
  1447 			return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
       
  1448 		},
       
  1449 
       
  1450 		// https://jqueryvalidation.org/step-method/
       
  1451 		step: function( value, element, param ) {
       
  1452 			var type = $( element ).attr( "type" ),
       
  1453 				errorMessage = "Step attribute on input type " + type + " is not supported.",
       
  1454 				supportedTypes = [ "text", "number", "range" ],
       
  1455 				re = new RegExp( "\\b" + type + "\\b" ),
       
  1456 				notSupported = type && !re.test( supportedTypes.join() ),
       
  1457 				decimalPlaces = function( num ) {
       
  1458 					var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
       
  1459 					if ( !match ) {
       
  1460 						return 0;
       
  1461 					}
       
  1462 
       
  1463 					// Number of digits right of decimal point.
       
  1464 					return match[ 1 ] ? match[ 1 ].length : 0;
       
  1465 				},
       
  1466 				toInt = function( num ) {
       
  1467 					return Math.round( num * Math.pow( 10, decimals ) );
       
  1468 				},
       
  1469 				valid = true,
       
  1470 				decimals;
       
  1471 
       
  1472 			// Works only for text, number and range input types
       
  1473 			// TODO find a way to support input types date, datetime, datetime-local, month, time and week
       
  1474 			if ( notSupported ) {
       
  1475 				throw new Error( errorMessage );
       
  1476 			}
       
  1477 
       
  1478 			decimals = decimalPlaces( param );
       
  1479 
       
  1480 			// Value can't have too many decimals
       
  1481 			if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
       
  1482 				valid = false;
       
  1483 			}
       
  1484 
       
  1485 			return this.optional( element ) || valid;
       
  1486 		},
       
  1487 
       
  1488 		// https://jqueryvalidation.org/equalTo-method/
       
  1489 		equalTo: function( value, element, param ) {
       
  1490 
       
  1491 			// Bind to the blur event of the target in order to revalidate whenever the target field is updated
       
  1492 			var target = $( param );
       
  1493 			if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
       
  1494 				target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
       
  1495 					$( element ).valid();
       
  1496 				} );
       
  1497 			}
       
  1498 			return value === target.val();
       
  1499 		},
       
  1500 
       
  1501 		// https://jqueryvalidation.org/remote-method/
       
  1502 		remote: function( value, element, param, method ) {
       
  1503 			if ( this.optional( element ) ) {
       
  1504 				return "dependency-mismatch";
       
  1505 			}
       
  1506 
       
  1507 			method = typeof method === "string" && method || "remote";
       
  1508 
       
  1509 			var previous = this.previousValue( element, method ),
       
  1510 				validator, data, optionDataString;
       
  1511 
       
  1512 			if ( !this.settings.messages[ element.name ] ) {
       
  1513 				this.settings.messages[ element.name ] = {};
       
  1514 			}
       
  1515 			previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
       
  1516 			this.settings.messages[ element.name ][ method ] = previous.message;
       
  1517 
       
  1518 			param = typeof param === "string" && { url: param } || param;
       
  1519 			optionDataString = $.param( $.extend( { data: value }, param.data ) );
       
  1520 			if ( previous.old === optionDataString ) {
       
  1521 				return previous.valid;
       
  1522 			}
       
  1523 
       
  1524 			previous.old = optionDataString;
       
  1525 			validator = this;
       
  1526 			this.startRequest( element );
       
  1527 			data = {};
       
  1528 			data[ element.name ] = value;
       
  1529 			$.ajax( $.extend( true, {
       
  1530 				mode: "abort",
       
  1531 				port: "validate" + element.name,
       
  1532 				dataType: "json",
       
  1533 				data: data,
       
  1534 				context: validator.currentForm,
       
  1535 				success: function( response ) {
       
  1536 					var valid = response === true || response === "true",
       
  1537 						errors, message, submitted;
       
  1538 
       
  1539 					validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
       
  1540 					if ( valid ) {
       
  1541 						submitted = validator.formSubmitted;
       
  1542 						validator.resetInternals();
       
  1543 						validator.toHide = validator.errorsFor( element );
       
  1544 						validator.formSubmitted = submitted;
       
  1545 						validator.successList.push( element );
       
  1546 						validator.invalid[ element.name ] = false;
       
  1547 						validator.showErrors();
       
  1548 					} else {
       
  1549 						errors = {};
       
  1550 						message = response || validator.defaultMessage( element, { method: method, parameters: value } );
       
  1551 						errors[ element.name ] = previous.message = message;
       
  1552 						validator.invalid[ element.name ] = true;
       
  1553 						validator.showErrors( errors );
       
  1554 					}
       
  1555 					previous.valid = valid;
       
  1556 					validator.stopRequest( element, valid );
       
  1557 				}
       
  1558 			}, param ) );
       
  1559 			return "pending";
       
  1560 		}
       
  1561 	}
       
  1562 
       
  1563 } );
       
  1564 
       
  1565 // Ajax mode: abort
       
  1566 // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
       
  1567 // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
       
  1568 
       
  1569 var pendingRequests = {},
       
  1570 	ajax;
       
  1571 
       
  1572 // Use a prefilter if available (1.5+)
       
  1573 if ( $.ajaxPrefilter ) {
       
  1574 	$.ajaxPrefilter( function( settings, _, xhr ) {
       
  1575 		var port = settings.port;
       
  1576 		if ( settings.mode === "abort" ) {
       
  1577 			if ( pendingRequests[ port ] ) {
       
  1578 				pendingRequests[ port ].abort();
       
  1579 			}
       
  1580 			pendingRequests[ port ] = xhr;
       
  1581 		}
       
  1582 	} );
       
  1583 } else {
       
  1584 
       
  1585 	// Proxy ajax
       
  1586 	ajax = $.ajax;
       
  1587 	$.ajax = function( settings ) {
       
  1588 		var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
       
  1589 			port = ( "port" in settings ? settings : $.ajaxSettings ).port;
       
  1590 		if ( mode === "abort" ) {
       
  1591 			if ( pendingRequests[ port ] ) {
       
  1592 				pendingRequests[ port ].abort();
       
  1593 			}
       
  1594 			pendingRequests[ port ] = ajax.apply( this, arguments );
       
  1595 			return pendingRequests[ port ];
       
  1596 		}
       
  1597 		return ajax.apply( this, arguments );
       
  1598 	};
       
  1599 }
       
  1600 return $;
       
  1601 }));
       
  1602 
       
  1603 /*!
       
  1604  * jQuery Validation Plugin v1.17.0
       
  1605  *
       
  1606  * https://jqueryvalidation.org/
       
  1607  *
       
  1608  * Copyright (c) 2017 Jörn Zaefferer
       
  1609  * Released under the MIT license
       
  1610  */
       
  1611 (function( factory ) {
       
  1612 	if ( typeof define === "function" && define.amd ) {
       
  1613 		define( ["jquery", "./jquery.validate"], factory );
       
  1614 	} else if (typeof module === "object" && module.exports) {
       
  1615 		module.exports = factory( require( "jquery" ) );
       
  1616 	} else {
       
  1617 		factory( jQuery );
       
  1618 	}
       
  1619 }(function( $ ) {
       
  1620 
       
  1621 ( function() {
       
  1622 
       
  1623 	function stripHtml( value ) {
       
  1624 
       
  1625 		// Remove html tags and space chars
       
  1626 		return value.replace( /<.[^<>]*?>/g, " " ).replace( /&nbsp;|&#160;/gi, " " )
       
  1627 
       
  1628 		// Remove punctuation
       
  1629 		.replace( /[.(),;:!?%#$'\"_+=\/\-“”’]*/g, "" );
       
  1630 	}
       
  1631 
       
  1632 	$.validator.addMethod( "maxWords", function( value, element, params ) {
       
  1633 		return this.optional( element ) || stripHtml( value ).match( /\b\w+\b/g ).length <= params;
       
  1634 	}, $.validator.format( "Please enter {0} words or less." ) );
       
  1635 
       
  1636 	$.validator.addMethod( "minWords", function( value, element, params ) {
       
  1637 		return this.optional( element ) || stripHtml( value ).match( /\b\w+\b/g ).length >= params;
       
  1638 	}, $.validator.format( "Please enter at least {0} words." ) );
       
  1639 
       
  1640 	$.validator.addMethod( "rangeWords", function( value, element, params ) {
       
  1641 		var valueStripped = stripHtml( value ),
       
  1642 			regex = /\b\w+\b/g;
       
  1643 		return this.optional( element ) || valueStripped.match( regex ).length >= params[ 0 ] && valueStripped.match( regex ).length <= params[ 1 ];
       
  1644 	}, $.validator.format( "Please enter between {0} and {1} words." ) );
       
  1645 
       
  1646 }() );
       
  1647 
       
  1648 // Accept a value from a file input based on a required mimetype
       
  1649 $.validator.addMethod( "accept", function( value, element, param ) {
       
  1650 
       
  1651 	// Split mime on commas in case we have multiple types we can accept
       
  1652 	var typeParam = typeof param === "string" ? param.replace( /\s/g, "" ) : "image/*",
       
  1653 		optionalValue = this.optional( element ),
       
  1654 		i, file, regex;
       
  1655 
       
  1656 	// Element is optional
       
  1657 	if ( optionalValue ) {
       
  1658 		return optionalValue;
       
  1659 	}
       
  1660 
       
  1661 	if ( $( element ).attr( "type" ) === "file" ) {
       
  1662 
       
  1663 		// Escape string to be used in the regex
       
  1664 		// see: https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
       
  1665 		// Escape also "/*" as "/.*" as a wildcard
       
  1666 		typeParam = typeParam
       
  1667 				.replace( /[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g, "\\$&" )
       
  1668 				.replace( /,/g, "|" )
       
  1669 				.replace( /\/\*/g, "/.*" );
       
  1670 
       
  1671 		// Check if the element has a FileList before checking each file
       
  1672 		if ( element.files && element.files.length ) {
       
  1673 			regex = new RegExp( ".?(" + typeParam + ")$", "i" );
       
  1674 			for ( i = 0; i < element.files.length; i++ ) {
       
  1675 				file = element.files[ i ];
       
  1676 
       
  1677 				// Grab the mimetype from the loaded file, verify it matches
       
  1678 				if ( !file.type.match( regex ) ) {
       
  1679 					return false;
       
  1680 				}
       
  1681 			}
       
  1682 		}
       
  1683 	}
       
  1684 
       
  1685 	// Either return true because we've validated each file, or because the
       
  1686 	// browser does not support element.files and the FileList feature
       
  1687 	return true;
       
  1688 }, $.validator.format( "Please enter a value with a valid mimetype." ) );
       
  1689 
       
  1690 $.validator.addMethod( "alphanumeric", function( value, element ) {
       
  1691 	return this.optional( element ) || /^\w+$/i.test( value );
       
  1692 }, "Letters, numbers, and underscores only please" );
       
  1693 
       
  1694 /*
       
  1695  * Dutch bank account numbers (not 'giro' numbers) have 9 digits
       
  1696  * and pass the '11 check'.
       
  1697  * We accept the notation with spaces, as that is common.
       
  1698  * acceptable: 123456789 or 12 34 56 789
       
  1699  */
       
  1700 $.validator.addMethod( "bankaccountNL", function( value, element ) {
       
  1701 	if ( this.optional( element ) ) {
       
  1702 		return true;
       
  1703 	}
       
  1704 	if ( !( /^[0-9]{9}|([0-9]{2} ){3}[0-9]{3}$/.test( value ) ) ) {
       
  1705 		return false;
       
  1706 	}
       
  1707 
       
  1708 	// Now '11 check'
       
  1709 	var account = value.replace( / /g, "" ), // Remove spaces
       
  1710 		sum = 0,
       
  1711 		len = account.length,
       
  1712 		pos, factor, digit;
       
  1713 	for ( pos = 0; pos < len; pos++ ) {
       
  1714 		factor = len - pos;
       
  1715 		digit = account.substring( pos, pos + 1 );
       
  1716 		sum = sum + factor * digit;
       
  1717 	}
       
  1718 	return sum % 11 === 0;
       
  1719 }, "Please specify a valid bank account number" );
       
  1720 
       
  1721 $.validator.addMethod( "bankorgiroaccountNL", function( value, element ) {
       
  1722 	return this.optional( element ) ||
       
  1723 			( $.validator.methods.bankaccountNL.call( this, value, element ) ) ||
       
  1724 			( $.validator.methods.giroaccountNL.call( this, value, element ) );
       
  1725 }, "Please specify a valid bank or giro account number" );
       
  1726 
       
  1727 /**
       
  1728  * BIC is the business identifier code (ISO 9362). This BIC check is not a guarantee for authenticity.
       
  1729  *
       
  1730  * BIC pattern: BBBBCCLLbbb (8 or 11 characters long; bbb is optional)
       
  1731  *
       
  1732  * Validation is case-insensitive. Please make sure to normalize input yourself.
       
  1733  *
       
  1734  * BIC definition in detail:
       
  1735  * - First 4 characters - bank code (only letters)
       
  1736  * - Next 2 characters - ISO 3166-1 alpha-2 country code (only letters)
       
  1737  * - Next 2 characters - location code (letters and digits)
       
  1738  *   a. shall not start with '0' or '1'
       
  1739  *   b. second character must be a letter ('O' is not allowed) or digit ('0' for test (therefore not allowed), '1' denoting passive participant, '2' typically reverse-billing)
       
  1740  * - Last 3 characters - branch code, optional (shall not start with 'X' except in case of 'XXX' for primary office) (letters and digits)
       
  1741  */
       
  1742 $.validator.addMethod( "bic", function( value, element ) {
       
  1743     return this.optional( element ) || /^([A-Z]{6}[A-Z2-9][A-NP-Z1-9])(X{3}|[A-WY-Z0-9][A-Z0-9]{2})?$/.test( value.toUpperCase() );
       
  1744 }, "Please specify a valid BIC code" );
       
  1745 
       
  1746 /*
       
  1747  * Código de identificación fiscal ( CIF ) is the tax identification code for Spanish legal entities
       
  1748  * Further rules can be found in Spanish on http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal
       
  1749  *
       
  1750  * Spanish CIF structure:
       
  1751  *
       
  1752  * [ T ][ P ][ P ][ N ][ N ][ N ][ N ][ N ][ C ]
       
  1753  *
       
  1754  * Where:
       
  1755  *
       
  1756  * T: 1 character. Kind of Organization Letter: [ABCDEFGHJKLMNPQRSUVW]
       
  1757  * P: 2 characters. Province.
       
  1758  * N: 5 characters. Secuencial Number within the province.
       
  1759  * C: 1 character. Control Digit: [0-9A-J].
       
  1760  *
       
  1761  * [ T ]: Kind of Organizations. Possible values:
       
  1762  *
       
  1763  *   A. Corporations
       
  1764  *   B. LLCs
       
  1765  *   C. General partnerships
       
  1766  *   D. Companies limited partnerships
       
  1767  *   E. Communities of goods
       
  1768  *   F. Cooperative Societies
       
  1769  *   G. Associations
       
  1770  *   H. Communities of homeowners in horizontal property regime
       
  1771  *   J. Civil Societies
       
  1772  *   K. Old format
       
  1773  *   L. Old format
       
  1774  *   M. Old format
       
  1775  *   N. Nonresident entities
       
  1776  *   P. Local authorities
       
  1777  *   Q. Autonomous bodies, state or not, and the like, and congregations and religious institutions
       
  1778  *   R. Congregations and religious institutions (since 2008 ORDER EHA/451/2008)
       
  1779  *   S. Organs of State Administration and regions
       
  1780  *   V. Agrarian Transformation
       
  1781  *   W. Permanent establishments of non-resident in Spain
       
  1782  *
       
  1783  * [ C ]: Control Digit. It can be a number or a letter depending on T value:
       
  1784  * [ T ]  -->  [ C ]
       
  1785  * ------    ----------
       
  1786  *   A         Number
       
  1787  *   B         Number
       
  1788  *   E         Number
       
  1789  *   H         Number
       
  1790  *   K         Letter
       
  1791  *   P         Letter
       
  1792  *   Q         Letter
       
  1793  *   S         Letter
       
  1794  *
       
  1795  */
       
  1796 $.validator.addMethod( "cifES", function( value, element ) {
       
  1797 	"use strict";
       
  1798 
       
  1799 	if ( this.optional( element ) ) {
       
  1800 		return true;
       
  1801 	}
       
  1802 
       
  1803 	var cifRegEx = new RegExp( /^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/gi );
       
  1804 	var letter  = value.substring( 0, 1 ), // [ T ]
       
  1805 		number  = value.substring( 1, 8 ), // [ P ][ P ][ N ][ N ][ N ][ N ][ N ]
       
  1806 		control = value.substring( 8, 9 ), // [ C ]
       
  1807 		all_sum = 0,
       
  1808 		even_sum = 0,
       
  1809 		odd_sum = 0,
       
  1810 		i, n,
       
  1811 		control_digit,
       
  1812 		control_letter;
       
  1813 
       
  1814 	function isOdd( n ) {
       
  1815 		return n % 2 === 0;
       
  1816 	}
       
  1817 
       
  1818 	// Quick format test
       
  1819 	if ( value.length !== 9 || !cifRegEx.test( value ) ) {
       
  1820 		return false;
       
  1821 	}
       
  1822 
       
  1823 	for ( i = 0; i < number.length; i++ ) {
       
  1824 		n = parseInt( number[ i ], 10 );
       
  1825 
       
  1826 		// Odd positions
       
  1827 		if ( isOdd( i ) ) {
       
  1828 
       
  1829 			// Odd positions are multiplied first.
       
  1830 			n *= 2;
       
  1831 
       
  1832 			// If the multiplication is bigger than 10 we need to adjust
       
  1833 			odd_sum += n < 10 ? n : n - 9;
       
  1834 
       
  1835 		// Even positions
       
  1836 		// Just sum them
       
  1837 		} else {
       
  1838 			even_sum += n;
       
  1839 		}
       
  1840 	}
       
  1841 
       
  1842 	all_sum = even_sum + odd_sum;
       
  1843 	control_digit = ( 10 - ( all_sum ).toString().substr( -1 ) ).toString();
       
  1844 	control_digit = parseInt( control_digit, 10 ) > 9 ? "0" : control_digit;
       
  1845 	control_letter = "JABCDEFGHI".substr( control_digit, 1 ).toString();
       
  1846 
       
  1847 	// Control must be a digit
       
  1848 	if ( letter.match( /[ABEH]/ ) ) {
       
  1849 		return control === control_digit;
       
  1850 
       
  1851 	// Control must be a letter
       
  1852 	} else if ( letter.match( /[KPQS]/ ) ) {
       
  1853 		return control === control_letter;
       
  1854 	}
       
  1855 
       
  1856 	// Can be either
       
  1857 	return control === control_digit || control === control_letter;
       
  1858 
       
  1859 }, "Please specify a valid CIF number." );
       
  1860 
       
  1861 /*
       
  1862  * Brazillian CPF number (Cadastrado de Pessoas Físicas) is the equivalent of a Brazilian tax registration number.
       
  1863  * CPF numbers have 11 digits in total: 9 numbers followed by 2 check numbers that are being used for validation.
       
  1864  */
       
  1865 $.validator.addMethod( "cpfBR", function( value ) {
       
  1866 
       
  1867 	// Removing special characters from value
       
  1868 	value = value.replace( /([~!@#$%^&*()_+=`{}\[\]\-|\\:;'<>,.\/? ])+/g, "" );
       
  1869 
       
  1870 	// Checking value to have 11 digits only
       
  1871 	if ( value.length !== 11 ) {
       
  1872 		return false;
       
  1873 	}
       
  1874 
       
  1875 	var sum = 0,
       
  1876 		firstCN, secondCN, checkResult, i;
       
  1877 
       
  1878 	firstCN = parseInt( value.substring( 9, 10 ), 10 );
       
  1879 	secondCN = parseInt( value.substring( 10, 11 ), 10 );
       
  1880 
       
  1881 	checkResult = function( sum, cn ) {
       
  1882 		var result = ( sum * 10 ) % 11;
       
  1883 		if ( ( result === 10 ) || ( result === 11 ) ) {
       
  1884 			result = 0;
       
  1885 		}
       
  1886 		return ( result === cn );
       
  1887 	};
       
  1888 
       
  1889 	// Checking for dump data
       
  1890 	if ( value === "" ||
       
  1891 		value === "00000000000" ||
       
  1892 		value === "11111111111" ||
       
  1893 		value === "22222222222" ||
       
  1894 		value === "33333333333" ||
       
  1895 		value === "44444444444" ||
       
  1896 		value === "55555555555" ||
       
  1897 		value === "66666666666" ||
       
  1898 		value === "77777777777" ||
       
  1899 		value === "88888888888" ||
       
  1900 		value === "99999999999"
       
  1901 	) {
       
  1902 		return false;
       
  1903 	}
       
  1904 
       
  1905 	// Step 1 - using first Check Number:
       
  1906 	for ( i = 1; i <= 9; i++ ) {
       
  1907 		sum = sum + parseInt( value.substring( i - 1, i ), 10 ) * ( 11 - i );
       
  1908 	}
       
  1909 
       
  1910 	// If first Check Number (CN) is valid, move to Step 2 - using second Check Number:
       
  1911 	if ( checkResult( sum, firstCN ) ) {
       
  1912 		sum = 0;
       
  1913 		for ( i = 1; i <= 10; i++ ) {
       
  1914 			sum = sum + parseInt( value.substring( i - 1, i ), 10 ) * ( 12 - i );
       
  1915 		}
       
  1916 		return checkResult( sum, secondCN );
       
  1917 	}
       
  1918 	return false;
       
  1919 
       
  1920 }, "Please specify a valid CPF number" );
       
  1921 
       
  1922 // https://jqueryvalidation.org/creditcard-method/
       
  1923 // based on https://en.wikipedia.org/wiki/Luhn_algorithm
       
  1924 $.validator.addMethod( "creditcard", function( value, element ) {
       
  1925 	if ( this.optional( element ) ) {
       
  1926 		return "dependency-mismatch";
       
  1927 	}
       
  1928 
       
  1929 	// Accept only spaces, digits and dashes
       
  1930 	if ( /[^0-9 \-]+/.test( value ) ) {
       
  1931 		return false;
       
  1932 	}
       
  1933 
       
  1934 	var nCheck = 0,
       
  1935 		nDigit = 0,
       
  1936 		bEven = false,
       
  1937 		n, cDigit;
       
  1938 
       
  1939 	value = value.replace( /\D/g, "" );
       
  1940 
       
  1941 	// Basing min and max length on
       
  1942 	// https://developer.ean.com/general_info/Valid_Credit_Card_Types
       
  1943 	if ( value.length < 13 || value.length > 19 ) {
       
  1944 		return false;
       
  1945 	}
       
  1946 
       
  1947 	for ( n = value.length - 1; n >= 0; n-- ) {
       
  1948 		cDigit = value.charAt( n );
       
  1949 		nDigit = parseInt( cDigit, 10 );
       
  1950 		if ( bEven ) {
       
  1951 			if ( ( nDigit *= 2 ) > 9 ) {
       
  1952 				nDigit -= 9;
       
  1953 			}
       
  1954 		}
       
  1955 
       
  1956 		nCheck += nDigit;
       
  1957 		bEven = !bEven;
       
  1958 	}
       
  1959 
       
  1960 	return ( nCheck % 10 ) === 0;
       
  1961 }, "Please enter a valid credit card number." );
       
  1962 
       
  1963 /* NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator
       
  1964  * Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0
       
  1965  * Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)
       
  1966  */
       
  1967 $.validator.addMethod( "creditcardtypes", function( value, element, param ) {
       
  1968 	if ( /[^0-9\-]+/.test( value ) ) {
       
  1969 		return false;
       
  1970 	}
       
  1971 
       
  1972 	value = value.replace( /\D/g, "" );
       
  1973 
       
  1974 	var validTypes = 0x0000;
       
  1975 
       
  1976 	if ( param.mastercard ) {
       
  1977 		validTypes |= 0x0001;
       
  1978 	}
       
  1979 	if ( param.visa ) {
       
  1980 		validTypes |= 0x0002;
       
  1981 	}
       
  1982 	if ( param.amex ) {
       
  1983 		validTypes |= 0x0004;
       
  1984 	}
       
  1985 	if ( param.dinersclub ) {
       
  1986 		validTypes |= 0x0008;
       
  1987 	}
       
  1988 	if ( param.enroute ) {
       
  1989 		validTypes |= 0x0010;
       
  1990 	}
       
  1991 	if ( param.discover ) {
       
  1992 		validTypes |= 0x0020;
       
  1993 	}
       
  1994 	if ( param.jcb ) {
       
  1995 		validTypes |= 0x0040;
       
  1996 	}
       
  1997 	if ( param.unknown ) {
       
  1998 		validTypes |= 0x0080;
       
  1999 	}
       
  2000 	if ( param.all ) {
       
  2001 		validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;
       
  2002 	}
       
  2003 	if ( validTypes & 0x0001 && /^(5[12345])/.test( value ) ) { // Mastercard
       
  2004 		return value.length === 16;
       
  2005 	}
       
  2006 	if ( validTypes & 0x0002 && /^(4)/.test( value ) ) { // Visa
       
  2007 		return value.length === 16;
       
  2008 	}
       
  2009 	if ( validTypes & 0x0004 && /^(3[47])/.test( value ) ) { // Amex
       
  2010 		return value.length === 15;
       
  2011 	}
       
  2012 	if ( validTypes & 0x0008 && /^(3(0[012345]|[68]))/.test( value ) ) { // Dinersclub
       
  2013 		return value.length === 14;
       
  2014 	}
       
  2015 	if ( validTypes & 0x0010 && /^(2(014|149))/.test( value ) ) { // Enroute
       
  2016 		return value.length === 15;
       
  2017 	}
       
  2018 	if ( validTypes & 0x0020 && /^(6011)/.test( value ) ) { // Discover
       
  2019 		return value.length === 16;
       
  2020 	}
       
  2021 	if ( validTypes & 0x0040 && /^(3)/.test( value ) ) { // Jcb
       
  2022 		return value.length === 16;
       
  2023 	}
       
  2024 	if ( validTypes & 0x0040 && /^(2131|1800)/.test( value ) ) { // Jcb
       
  2025 		return value.length === 15;
       
  2026 	}
       
  2027 	if ( validTypes & 0x0080 ) { // Unknown
       
  2028 		return true;
       
  2029 	}
       
  2030 	return false;
       
  2031 }, "Please enter a valid credit card number." );
       
  2032 
       
  2033 /**
       
  2034  * Validates currencies with any given symbols by @jameslouiz
       
  2035  * Symbols can be optional or required. Symbols required by default
       
  2036  *
       
  2037  * Usage examples:
       
  2038  *  currency: ["£", false] - Use false for soft currency validation
       
  2039  *  currency: ["$", false]
       
  2040  *  currency: ["RM", false] - also works with text based symbols such as "RM" - Malaysia Ringgit etc
       
  2041  *
       
  2042  *  <input class="currencyInput" name="currencyInput">
       
  2043  *
       
  2044  * Soft symbol checking
       
  2045  *  currencyInput: {
       
  2046  *     currency: ["$", false]
       
  2047  *  }
       
  2048  *
       
  2049  * Strict symbol checking (default)
       
  2050  *  currencyInput: {
       
  2051  *     currency: "$"
       
  2052  *     //OR
       
  2053  *     currency: ["$", true]
       
  2054  *  }
       
  2055  *
       
  2056  * Multiple Symbols
       
  2057  *  currencyInput: {
       
  2058  *     currency: "$,£,¢"
       
  2059  *  }
       
  2060  */
       
  2061 $.validator.addMethod( "currency", function( value, element, param ) {
       
  2062     var isParamString = typeof param === "string",
       
  2063         symbol = isParamString ? param : param[ 0 ],
       
  2064         soft = isParamString ? true : param[ 1 ],
       
  2065         regex;
       
  2066 
       
  2067     symbol = symbol.replace( /,/g, "" );
       
  2068     symbol = soft ? symbol + "]" : symbol + "]?";
       
  2069     regex = "^[" + symbol + "([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$";
       
  2070     regex = new RegExp( regex );
       
  2071     return this.optional( element ) || regex.test( value );
       
  2072 
       
  2073 }, "Please specify a valid currency" );
       
  2074 
       
  2075 $.validator.addMethod( "dateFA", function( value, element ) {
       
  2076 	return this.optional( element ) || /^[1-4]\d{3}\/((0?[1-6]\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\/(30|([1-2][0-9])|(0?[1-9]))))$/.test( value );
       
  2077 }, $.validator.messages.date );
       
  2078 
       
  2079 /**
       
  2080  * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
       
  2081  *
       
  2082  * @example $.validator.methods.date("01/01/1900")
       
  2083  * @result true
       
  2084  *
       
  2085  * @example $.validator.methods.date("01/13/1990")
       
  2086  * @result false
       
  2087  *
       
  2088  * @example $.validator.methods.date("01.01.1900")
       
  2089  * @result false
       
  2090  *
       
  2091  * @example <input name="pippo" class="{dateITA:true}" />
       
  2092  * @desc Declares an optional input element whose value must be a valid date.
       
  2093  *
       
  2094  * @name $.validator.methods.dateITA
       
  2095  * @type Boolean
       
  2096  * @cat Plugins/Validate/Methods
       
  2097  */
       
  2098 $.validator.addMethod( "dateITA", function( value, element ) {
       
  2099 	var check = false,
       
  2100 		re = /^\d{1,2}\/\d{1,2}\/\d{4}$/,
       
  2101 		adata, gg, mm, aaaa, xdata;
       
  2102 	if ( re.test( value ) ) {
       
  2103 		adata = value.split( "/" );
       
  2104 		gg = parseInt( adata[ 0 ], 10 );
       
  2105 		mm = parseInt( adata[ 1 ], 10 );
       
  2106 		aaaa = parseInt( adata[ 2 ], 10 );
       
  2107 		xdata = new Date( Date.UTC( aaaa, mm - 1, gg, 12, 0, 0, 0 ) );
       
  2108 		if ( ( xdata.getUTCFullYear() === aaaa ) && ( xdata.getUTCMonth() === mm - 1 ) && ( xdata.getUTCDate() === gg ) ) {
       
  2109 			check = true;
       
  2110 		} else {
       
  2111 			check = false;
       
  2112 		}
       
  2113 	} else {
       
  2114 		check = false;
       
  2115 	}
       
  2116 	return this.optional( element ) || check;
       
  2117 }, $.validator.messages.date );
       
  2118 
       
  2119 $.validator.addMethod( "dateNL", function( value, element ) {
       
  2120 	return this.optional( element ) || /^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test( value );
       
  2121 }, $.validator.messages.date );
       
  2122 
       
  2123 // Older "accept" file extension method. Old docs: http://docs.jquery.com/Plugins/Validation/Methods/accept
       
  2124 $.validator.addMethod( "extension", function( value, element, param ) {
       
  2125 	param = typeof param === "string" ? param.replace( /,/g, "|" ) : "png|jpe?g|gif";
       
  2126 	return this.optional( element ) || value.match( new RegExp( "\\.(" + param + ")$", "i" ) );
       
  2127 }, $.validator.format( "Please enter a value with a valid extension." ) );
       
  2128 
       
  2129 /**
       
  2130  * Dutch giro account numbers (not bank numbers) have max 7 digits
       
  2131  */
       
  2132 $.validator.addMethod( "giroaccountNL", function( value, element ) {
       
  2133 	return this.optional( element ) || /^[0-9]{1,7}$/.test( value );
       
  2134 }, "Please specify a valid giro account number" );
       
  2135 
       
  2136 /**
       
  2137  * IBAN is the international bank account number.
       
  2138  * It has a country - specific format, that is checked here too
       
  2139  *
       
  2140  * Validation is case-insensitive. Please make sure to normalize input yourself.
       
  2141  */
       
  2142 $.validator.addMethod( "iban", function( value, element ) {
       
  2143 
       
  2144 	// Some quick simple tests to prevent needless work
       
  2145 	if ( this.optional( element ) ) {
       
  2146 		return true;
       
  2147 	}
       
  2148 
       
  2149 	// Remove spaces and to upper case
       
  2150 	var iban = value.replace( / /g, "" ).toUpperCase(),
       
  2151 		ibancheckdigits = "",
       
  2152 		leadingZeroes = true,
       
  2153 		cRest = "",
       
  2154 		cOperator = "",
       
  2155 		countrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p;
       
  2156 
       
  2157 	// Check for IBAN code length.
       
  2158 	// It contains:
       
  2159 	// country code ISO 3166-1 - two letters,
       
  2160 	// two check digits,
       
  2161 	// Basic Bank Account Number (BBAN) - up to 30 chars
       
  2162 	var minimalIBANlength = 5;
       
  2163 	if ( iban.length < minimalIBANlength ) {
       
  2164 		return false;
       
  2165 	}
       
  2166 
       
  2167 	// Check the country code and find the country specific format
       
  2168 	countrycode = iban.substring( 0, 2 );
       
  2169 	bbancountrypatterns = {
       
  2170 		"AL": "\\d{8}[\\dA-Z]{16}",
       
  2171 		"AD": "\\d{8}[\\dA-Z]{12}",
       
  2172 		"AT": "\\d{16}",
       
  2173 		"AZ": "[\\dA-Z]{4}\\d{20}",
       
  2174 		"BE": "\\d{12}",
       
  2175 		"BH": "[A-Z]{4}[\\dA-Z]{14}",
       
  2176 		"BA": "\\d{16}",
       
  2177 		"BR": "\\d{23}[A-Z][\\dA-Z]",
       
  2178 		"BG": "[A-Z]{4}\\d{6}[\\dA-Z]{8}",
       
  2179 		"CR": "\\d{17}",
       
  2180 		"HR": "\\d{17}",
       
  2181 		"CY": "\\d{8}[\\dA-Z]{16}",
       
  2182 		"CZ": "\\d{20}",
       
  2183 		"DK": "\\d{14}",
       
  2184 		"DO": "[A-Z]{4}\\d{20}",
       
  2185 		"EE": "\\d{16}",
       
  2186 		"FO": "\\d{14}",
       
  2187 		"FI": "\\d{14}",
       
  2188 		"FR": "\\d{10}[\\dA-Z]{11}\\d{2}",
       
  2189 		"GE": "[\\dA-Z]{2}\\d{16}",
       
  2190 		"DE": "\\d{18}",
       
  2191 		"GI": "[A-Z]{4}[\\dA-Z]{15}",
       
  2192 		"GR": "\\d{7}[\\dA-Z]{16}",
       
  2193 		"GL": "\\d{14}",
       
  2194 		"GT": "[\\dA-Z]{4}[\\dA-Z]{20}",
       
  2195 		"HU": "\\d{24}",
       
  2196 		"IS": "\\d{22}",
       
  2197 		"IE": "[\\dA-Z]{4}\\d{14}",
       
  2198 		"IL": "\\d{19}",
       
  2199 		"IT": "[A-Z]\\d{10}[\\dA-Z]{12}",
       
  2200 		"KZ": "\\d{3}[\\dA-Z]{13}",
       
  2201 		"KW": "[A-Z]{4}[\\dA-Z]{22}",
       
  2202 		"LV": "[A-Z]{4}[\\dA-Z]{13}",
       
  2203 		"LB": "\\d{4}[\\dA-Z]{20}",
       
  2204 		"LI": "\\d{5}[\\dA-Z]{12}",
       
  2205 		"LT": "\\d{16}",
       
  2206 		"LU": "\\d{3}[\\dA-Z]{13}",
       
  2207 		"MK": "\\d{3}[\\dA-Z]{10}\\d{2}",
       
  2208 		"MT": "[A-Z]{4}\\d{5}[\\dA-Z]{18}",
       
  2209 		"MR": "\\d{23}",
       
  2210 		"MU": "[A-Z]{4}\\d{19}[A-Z]{3}",
       
  2211 		"MC": "\\d{10}[\\dA-Z]{11}\\d{2}",
       
  2212 		"MD": "[\\dA-Z]{2}\\d{18}",
       
  2213 		"ME": "\\d{18}",
       
  2214 		"NL": "[A-Z]{4}\\d{10}",
       
  2215 		"NO": "\\d{11}",
       
  2216 		"PK": "[\\dA-Z]{4}\\d{16}",
       
  2217 		"PS": "[\\dA-Z]{4}\\d{21}",
       
  2218 		"PL": "\\d{24}",
       
  2219 		"PT": "\\d{21}",
       
  2220 		"RO": "[A-Z]{4}[\\dA-Z]{16}",
       
  2221 		"SM": "[A-Z]\\d{10}[\\dA-Z]{12}",
       
  2222 		"SA": "\\d{2}[\\dA-Z]{18}",
       
  2223 		"RS": "\\d{18}",
       
  2224 		"SK": "\\d{20}",
       
  2225 		"SI": "\\d{15}",
       
  2226 		"ES": "\\d{20}",
       
  2227 		"SE": "\\d{20}",
       
  2228 		"CH": "\\d{5}[\\dA-Z]{12}",
       
  2229 		"TN": "\\d{20}",
       
  2230 		"TR": "\\d{5}[\\dA-Z]{17}",
       
  2231 		"AE": "\\d{3}\\d{16}",
       
  2232 		"GB": "[A-Z]{4}\\d{14}",
       
  2233 		"VG": "[\\dA-Z]{4}\\d{16}"
       
  2234 	};
       
  2235 
       
  2236 	bbanpattern = bbancountrypatterns[ countrycode ];
       
  2237 
       
  2238 	// As new countries will start using IBAN in the
       
  2239 	// future, we only check if the countrycode is known.
       
  2240 	// This prevents false negatives, while almost all
       
  2241 	// false positives introduced by this, will be caught
       
  2242 	// by the checksum validation below anyway.
       
  2243 	// Strict checking should return FALSE for unknown
       
  2244 	// countries.
       
  2245 	if ( typeof bbanpattern !== "undefined" ) {
       
  2246 		ibanregexp = new RegExp( "^[A-Z]{2}\\d{2}" + bbanpattern + "$", "" );
       
  2247 		if ( !( ibanregexp.test( iban ) ) ) {
       
  2248 			return false; // Invalid country specific format
       
  2249 		}
       
  2250 	}
       
  2251 
       
  2252 	// Now check the checksum, first convert to digits
       
  2253 	ibancheck = iban.substring( 4, iban.length ) + iban.substring( 0, 4 );
       
  2254 	for ( i = 0; i < ibancheck.length; i++ ) {
       
  2255 		charAt = ibancheck.charAt( i );
       
  2256 		if ( charAt !== "0" ) {
       
  2257 			leadingZeroes = false;
       
  2258 		}
       
  2259 		if ( !leadingZeroes ) {
       
  2260 			ibancheckdigits += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf( charAt );
       
  2261 		}
       
  2262 	}
       
  2263 
       
  2264 	// Calculate the result of: ibancheckdigits % 97
       
  2265 	for ( p = 0; p < ibancheckdigits.length; p++ ) {
       
  2266 		cChar = ibancheckdigits.charAt( p );
       
  2267 		cOperator = "" + cRest + "" + cChar;
       
  2268 		cRest = cOperator % 97;
       
  2269 	}
       
  2270 	return cRest === 1;
       
  2271 }, "Please specify a valid IBAN" );
       
  2272 
       
  2273 $.validator.addMethod( "integer", function( value, element ) {
       
  2274 	return this.optional( element ) || /^-?\d+$/.test( value );
       
  2275 }, "A positive or negative non-decimal number please" );
       
  2276 
       
  2277 $.validator.addMethod( "ipv4", function( value, element ) {
       
  2278 	return this.optional( element ) || /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i.test( value );
       
  2279 }, "Please enter a valid IP v4 address." );
       
  2280 
       
  2281 $.validator.addMethod( "ipv6", function( value, element ) {
       
  2282 	return this.optional( element ) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test( value );
       
  2283 }, "Please enter a valid IP v6 address." );
       
  2284 
       
  2285 $.validator.addMethod( "lettersonly", function( value, element ) {
       
  2286 	return this.optional( element ) || /^[a-z]+$/i.test( value );
       
  2287 }, "Letters only please" );
       
  2288 
       
  2289 $.validator.addMethod( "letterswithbasicpunc", function( value, element ) {
       
  2290 	return this.optional( element ) || /^[a-z\-.,()'"\s]+$/i.test( value );
       
  2291 }, "Letters or punctuation only please" );
       
  2292 
       
  2293 $.validator.addMethod( "mobileNL", function( value, element ) {
       
  2294 	return this.optional( element ) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)6((\s|\s?\-\s?)?[0-9]){8}$/.test( value );
       
  2295 }, "Please specify a valid mobile number" );
       
  2296 
       
  2297 /* For UK phone functions, do the following server side processing:
       
  2298  * Compare original input with this RegEx pattern:
       
  2299  * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
       
  2300  * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
       
  2301  * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
       
  2302  * A number of very detailed GB telephone number RegEx patterns can also be found at:
       
  2303  * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
       
  2304  */
       
  2305 $.validator.addMethod( "mobileUK", function( phone_number, element ) {
       
  2306 	phone_number = phone_number.replace( /\(|\)|\s+|-/g, "" );
       
  2307 	return this.optional( element ) || phone_number.length > 9 &&
       
  2308 		phone_number.match( /^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[1345789]\d{2}|624)\s?\d{3}\s?\d{3})$/ );
       
  2309 }, "Please specify a valid mobile number" );
       
  2310 
       
  2311 $.validator.addMethod( "netmask", function( value, element ) {
       
  2312     return this.optional( element ) || /^(254|252|248|240|224|192|128)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(254|252|248|240|224|192|128|0)/i.test( value );
       
  2313 }, "Please enter a valid netmask." );
       
  2314 
       
  2315 /*
       
  2316  * The NIE (Número de Identificación de Extranjero) is a Spanish tax identification number assigned by the Spanish
       
  2317  * authorities to any foreigner.
       
  2318  *
       
  2319  * The NIE is the equivalent of a Spaniards Número de Identificación Fiscal (NIF) which serves as a fiscal
       
  2320  * identification number. The CIF number (Certificado de Identificación Fiscal) is equivalent to the NIF, but applies to
       
  2321  * companies rather than individuals. The NIE consists of an 'X' or 'Y' followed by 7 or 8 digits then another letter.
       
  2322  */
       
  2323 $.validator.addMethod( "nieES", function( value, element ) {
       
  2324 	"use strict";
       
  2325 
       
  2326 	if ( this.optional( element ) ) {
       
  2327 		return true;
       
  2328 	}
       
  2329 
       
  2330 	var nieRegEx = new RegExp( /^[MXYZ]{1}[0-9]{7,8}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/gi );
       
  2331 	var validChars = "TRWAGMYFPDXBNJZSQVHLCKET",
       
  2332 		letter = value.substr( value.length - 1 ).toUpperCase(),
       
  2333 		number;
       
  2334 
       
  2335 	value = value.toString().toUpperCase();
       
  2336 
       
  2337 	// Quick format test
       
  2338 	if ( value.length > 10 || value.length < 9 || !nieRegEx.test( value ) ) {
       
  2339 		return false;
       
  2340 	}
       
  2341 
       
  2342 	// X means same number
       
  2343 	// Y means number + 10000000
       
  2344 	// Z means number + 20000000
       
  2345 	value = value.replace( /^[X]/, "0" )
       
  2346 		.replace( /^[Y]/, "1" )
       
  2347 		.replace( /^[Z]/, "2" );
       
  2348 
       
  2349 	number = value.length === 9 ? value.substr( 0, 8 ) : value.substr( 0, 9 );
       
  2350 
       
  2351 	return validChars.charAt( parseInt( number, 10 ) % 23 ) === letter;
       
  2352 
       
  2353 }, "Please specify a valid NIE number." );
       
  2354 
       
  2355 /*
       
  2356  * The Número de Identificación Fiscal ( NIF ) is the way tax identification used in Spain for individuals
       
  2357  */
       
  2358 $.validator.addMethod( "nifES", function( value, element ) {
       
  2359 	"use strict";
       
  2360 
       
  2361 	if ( this.optional( element ) ) {
       
  2362 		return true;
       
  2363 	}
       
  2364 
       
  2365 	value = value.toUpperCase();
       
  2366 
       
  2367 	// Basic format test
       
  2368 	if ( !value.match( "((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)" ) ) {
       
  2369 		return false;
       
  2370 	}
       
  2371 
       
  2372 	// Test NIF
       
  2373 	if ( /^[0-9]{8}[A-Z]{1}$/.test( value ) ) {
       
  2374 		return ( "TRWAGMYFPDXBNJZSQVHLCKE".charAt( value.substring( 8, 0 ) % 23 ) === value.charAt( 8 ) );
       
  2375 	}
       
  2376 
       
  2377 	// Test specials NIF (starts with K, L or M)
       
  2378 	if ( /^[KLM]{1}/.test( value ) ) {
       
  2379 		return ( value[ 8 ] === "TRWAGMYFPDXBNJZSQVHLCKE".charAt( value.substring( 8, 1 ) % 23 ) );
       
  2380 	}
       
  2381 
       
  2382 	return false;
       
  2383 
       
  2384 }, "Please specify a valid NIF number." );
       
  2385 
       
  2386 /*
       
  2387  * Numer identyfikacji podatkowej ( NIP ) is the way tax identification used in Poland for companies
       
  2388  */
       
  2389 $.validator.addMethod( "nipPL", function( value ) {
       
  2390 	"use strict";
       
  2391 
       
  2392 	value = value.replace( /[^0-9]/g, "" );
       
  2393 
       
  2394 	if ( value.length !== 10 ) {
       
  2395 		return false;
       
  2396 	}
       
  2397 
       
  2398 	var arrSteps = [ 6, 5, 7, 2, 3, 4, 5, 6, 7 ];
       
  2399 	var intSum = 0;
       
  2400 	for ( var i = 0; i < 9; i++ ) {
       
  2401 		intSum += arrSteps[ i ] * value[ i ];
       
  2402 	}
       
  2403 	var int2 = intSum % 11;
       
  2404 	var intControlNr = ( int2 === 10 ) ? 0 : int2;
       
  2405 
       
  2406 	return ( intControlNr === parseInt( value[ 9 ], 10 ) );
       
  2407 }, "Please specify a valid NIP number." );
       
  2408 
       
  2409 $.validator.addMethod( "notEqualTo", function( value, element, param ) {
       
  2410 	return this.optional( element ) || !$.validator.methods.equalTo.call( this, value, element, param );
       
  2411 }, "Please enter a different value, values must not be the same." );
       
  2412 
       
  2413 $.validator.addMethod( "nowhitespace", function( value, element ) {
       
  2414 	return this.optional( element ) || /^\S+$/i.test( value );
       
  2415 }, "No white space please" );
       
  2416 
       
  2417 /**
       
  2418 * Return true if the field value matches the given format RegExp
       
  2419 *
       
  2420 * @example $.validator.methods.pattern("AR1004",element,/^AR\d{4}$/)
       
  2421 * @result true
       
  2422 *
       
  2423 * @example $.validator.methods.pattern("BR1004",element,/^AR\d{4}$/)
       
  2424 * @result false
       
  2425 *
       
  2426 * @name $.validator.methods.pattern
       
  2427 * @type Boolean
       
  2428 * @cat Plugins/Validate/Methods
       
  2429 */
       
  2430 $.validator.addMethod( "pattern", function( value, element, param ) {
       
  2431 	if ( this.optional( element ) ) {
       
  2432 		return true;
       
  2433 	}
       
  2434 	if ( typeof param === "string" ) {
       
  2435 		param = new RegExp( "^(?:" + param + ")$" );
       
  2436 	}
       
  2437 	return param.test( value );
       
  2438 }, $.validator.messages.invalidformat || "Invalid format." );
       
  2439 
       
  2440 /**
       
  2441  * Dutch phone numbers have 10 digits (or 11 and start with +31).
       
  2442  */
       
  2443 $.validator.addMethod( "phoneNL", function( value, element ) {
       
  2444 	return this.optional( element ) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test( value );
       
  2445 }, "Please specify a valid phone number." );
       
  2446 
       
  2447 /* For UK phone functions, do the following server side processing:
       
  2448  * Compare original input with this RegEx pattern:
       
  2449  * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
       
  2450  * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
       
  2451  * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
       
  2452  * A number of very detailed GB telephone number RegEx patterns can also be found at:
       
  2453  * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
       
  2454  */
       
  2455 
       
  2456 // Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers
       
  2457 $.validator.addMethod( "phonesUK", function( phone_number, element ) {
       
  2458 	phone_number = phone_number.replace( /\(|\)|\s+|-/g, "" );
       
  2459 	return this.optional( element ) || phone_number.length > 9 &&
       
  2460 		phone_number.match( /^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[1345789]\d{8}|624\d{6})))$/ );
       
  2461 }, "Please specify a valid uk phone number" );
       
  2462 
       
  2463 /* For UK phone functions, do the following server side processing:
       
  2464  * Compare original input with this RegEx pattern:
       
  2465  * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
       
  2466  * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
       
  2467  * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
       
  2468  * A number of very detailed GB telephone number RegEx patterns can also be found at:
       
  2469  * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
       
  2470  */
       
  2471 $.validator.addMethod( "phoneUK", function( phone_number, element ) {
       
  2472 	phone_number = phone_number.replace( /\(|\)|\s+|-/g, "" );
       
  2473 	return this.optional( element ) || phone_number.length > 9 &&
       
  2474 		phone_number.match( /^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/ );
       
  2475 }, "Please specify a valid phone number" );
       
  2476 
       
  2477 /**
       
  2478  * Matches US phone number format
       
  2479  *
       
  2480  * where the area code may not start with 1 and the prefix may not start with 1
       
  2481  * allows '-' or ' ' as a separator and allows parens around area code
       
  2482  * some people may want to put a '1' in front of their number
       
  2483  *
       
  2484  * 1(212)-999-2345 or
       
  2485  * 212 999 2344 or
       
  2486  * 212-999-0983
       
  2487  *
       
  2488  * but not
       
  2489  * 111-123-5434
       
  2490  * and not
       
  2491  * 212 123 4567
       
  2492  */
       
  2493 $.validator.addMethod( "phoneUS", function( phone_number, element ) {
       
  2494 	phone_number = phone_number.replace( /\s+/g, "" );
       
  2495 	return this.optional( element ) || phone_number.length > 9 &&
       
  2496 		phone_number.match( /^(\+?1-?)?(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))-?[2-9]([02-9]\d|1[02-9])-?\d{4}$/ );
       
  2497 }, "Please specify a valid phone number" );
       
  2498 
       
  2499 /*
       
  2500 * Valida CEPs do brasileiros:
       
  2501 *
       
  2502 * Formatos aceitos:
       
  2503 * 99999-999
       
  2504 * 99.999-999
       
  2505 * 99999999
       
  2506 */
       
  2507 $.validator.addMethod( "postalcodeBR", function( cep_value, element ) {
       
  2508 	return this.optional( element ) || /^\d{2}.\d{3}-\d{3}?$|^\d{5}-?\d{3}?$/.test( cep_value );
       
  2509 }, "Informe um CEP válido." );
       
  2510 
       
  2511 /**
       
  2512  * Matches a valid Canadian Postal Code
       
  2513  *
       
  2514  * @example jQuery.validator.methods.postalCodeCA( "H0H 0H0", element )
       
  2515  * @result true
       
  2516  *
       
  2517  * @example jQuery.validator.methods.postalCodeCA( "H0H0H0", element )
       
  2518  * @result false
       
  2519  *
       
  2520  * @name jQuery.validator.methods.postalCodeCA
       
  2521  * @type Boolean
       
  2522  * @cat Plugins/Validate/Methods
       
  2523  */
       
  2524 $.validator.addMethod( "postalCodeCA", function( value, element ) {
       
  2525 	return this.optional( element ) || /^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ] *\d[ABCEGHJKLMNPRSTVWXYZ]\d$/i.test( value );
       
  2526 }, "Please specify a valid postal code" );
       
  2527 
       
  2528 /* Matches Italian postcode (CAP) */
       
  2529 $.validator.addMethod( "postalcodeIT", function( value, element ) {
       
  2530 	return this.optional( element ) || /^\d{5}$/.test( value );
       
  2531 }, "Please specify a valid postal code" );
       
  2532 
       
  2533 $.validator.addMethod( "postalcodeNL", function( value, element ) {
       
  2534 	return this.optional( element ) || /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test( value );
       
  2535 }, "Please specify a valid postal code" );
       
  2536 
       
  2537 // Matches UK postcode. Does not match to UK Channel Islands that have their own postcodes (non standard UK)
       
  2538 $.validator.addMethod( "postcodeUK", function( value, element ) {
       
  2539 	return this.optional( element ) || /^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test( value );
       
  2540 }, "Please specify a valid UK postcode" );
       
  2541 
       
  2542 /*
       
  2543  * Lets you say "at least X inputs that match selector Y must be filled."
       
  2544  *
       
  2545  * The end result is that neither of these inputs:
       
  2546  *
       
  2547  *	<input class="productinfo" name="partnumber">
       
  2548  *	<input class="productinfo" name="description">
       
  2549  *
       
  2550  *	...will validate unless at least one of them is filled.
       
  2551  *
       
  2552  * partnumber:	{require_from_group: [1,".productinfo"]},
       
  2553  * description: {require_from_group: [1,".productinfo"]}
       
  2554  *
       
  2555  * options[0]: number of fields that must be filled in the group
       
  2556  * options[1]: CSS selector that defines the group of conditionally required fields
       
  2557  */
       
  2558 $.validator.addMethod( "require_from_group", function( value, element, options ) {
       
  2559 	var $fields = $( options[ 1 ], element.form ),
       
  2560 		$fieldsFirst = $fields.eq( 0 ),
       
  2561 		validator = $fieldsFirst.data( "valid_req_grp" ) ? $fieldsFirst.data( "valid_req_grp" ) : $.extend( {}, this ),
       
  2562 		isValid = $fields.filter( function() {
       
  2563 			return validator.elementValue( this );
       
  2564 		} ).length >= options[ 0 ];
       
  2565 
       
  2566 	// Store the cloned validator for future validation
       
  2567 	$fieldsFirst.data( "valid_req_grp", validator );
       
  2568 
       
  2569 	// If element isn't being validated, run each require_from_group field's validation rules
       
  2570 	if ( !$( element ).data( "being_validated" ) ) {
       
  2571 		$fields.data( "being_validated", true );
       
  2572 		$fields.each( function() {
       
  2573 			validator.element( this );
       
  2574 		} );
       
  2575 		$fields.data( "being_validated", false );
       
  2576 	}
       
  2577 	return isValid;
       
  2578 }, $.validator.format( "Please fill at least {0} of these fields." ) );
       
  2579 
       
  2580 /*
       
  2581  * Lets you say "either at least X inputs that match selector Y must be filled,
       
  2582  * OR they must all be skipped (left blank)."
       
  2583  *
       
  2584  * The end result, is that none of these inputs:
       
  2585  *
       
  2586  *	<input class="productinfo" name="partnumber">
       
  2587  *	<input class="productinfo" name="description">
       
  2588  *	<input class="productinfo" name="color">
       
  2589  *
       
  2590  *	...will validate unless either at least two of them are filled,
       
  2591  *	OR none of them are.
       
  2592  *
       
  2593  * partnumber:	{skip_or_fill_minimum: [2,".productinfo"]},
       
  2594  * description: {skip_or_fill_minimum: [2,".productinfo"]},
       
  2595  * color:		{skip_or_fill_minimum: [2,".productinfo"]}
       
  2596  *
       
  2597  * options[0]: number of fields that must be filled in the group
       
  2598  * options[1]: CSS selector that defines the group of conditionally required fields
       
  2599  *
       
  2600  */
       
  2601 $.validator.addMethod( "skip_or_fill_minimum", function( value, element, options ) {
       
  2602 	var $fields = $( options[ 1 ], element.form ),
       
  2603 		$fieldsFirst = $fields.eq( 0 ),
       
  2604 		validator = $fieldsFirst.data( "valid_skip" ) ? $fieldsFirst.data( "valid_skip" ) : $.extend( {}, this ),
       
  2605 		numberFilled = $fields.filter( function() {
       
  2606 			return validator.elementValue( this );
       
  2607 		} ).length,
       
  2608 		isValid = numberFilled === 0 || numberFilled >= options[ 0 ];
       
  2609 
       
  2610 	// Store the cloned validator for future validation
       
  2611 	$fieldsFirst.data( "valid_skip", validator );
       
  2612 
       
  2613 	// If element isn't being validated, run each skip_or_fill_minimum field's validation rules
       
  2614 	if ( !$( element ).data( "being_validated" ) ) {
       
  2615 		$fields.data( "being_validated", true );
       
  2616 		$fields.each( function() {
       
  2617 			validator.element( this );
       
  2618 		} );
       
  2619 		$fields.data( "being_validated", false );
       
  2620 	}
       
  2621 	return isValid;
       
  2622 }, $.validator.format( "Please either skip these fields or fill at least {0} of them." ) );
       
  2623 
       
  2624 /* Validates US States and/or Territories by @jdforsythe
       
  2625  * Can be case insensitive or require capitalization - default is case insensitive
       
  2626  * Can include US Territories or not - default does not
       
  2627  * Can include US Military postal abbreviations (AA, AE, AP) - default does not
       
  2628  *
       
  2629  * Note: "States" always includes DC (District of Colombia)
       
  2630  *
       
  2631  * Usage examples:
       
  2632  *
       
  2633  *  This is the default - case insensitive, no territories, no military zones
       
  2634  *  stateInput: {
       
  2635  *     caseSensitive: false,
       
  2636  *     includeTerritories: false,
       
  2637  *     includeMilitary: false
       
  2638  *  }
       
  2639  *
       
  2640  *  Only allow capital letters, no territories, no military zones
       
  2641  *  stateInput: {
       
  2642  *     caseSensitive: false
       
  2643  *  }
       
  2644  *
       
  2645  *  Case insensitive, include territories but not military zones
       
  2646  *  stateInput: {
       
  2647  *     includeTerritories: true
       
  2648  *  }
       
  2649  *
       
  2650  *  Only allow capital letters, include territories and military zones
       
  2651  *  stateInput: {
       
  2652  *     caseSensitive: true,
       
  2653  *     includeTerritories: true,
       
  2654  *     includeMilitary: true
       
  2655  *  }
       
  2656  *
       
  2657  */
       
  2658 $.validator.addMethod( "stateUS", function( value, element, options ) {
       
  2659 	var isDefault = typeof options === "undefined",
       
  2660 		caseSensitive = ( isDefault || typeof options.caseSensitive === "undefined" ) ? false : options.caseSensitive,
       
  2661 		includeTerritories = ( isDefault || typeof options.includeTerritories === "undefined" ) ? false : options.includeTerritories,
       
  2662 		includeMilitary = ( isDefault || typeof options.includeMilitary === "undefined" ) ? false : options.includeMilitary,
       
  2663 		regex;
       
  2664 
       
  2665 	if ( !includeTerritories && !includeMilitary ) {
       
  2666 		regex = "^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$";
       
  2667 	} else if ( includeTerritories && includeMilitary ) {
       
  2668 		regex = "^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$";
       
  2669 	} else if ( includeTerritories ) {
       
  2670 		regex = "^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$";
       
  2671 	} else {
       
  2672 		regex = "^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$";
       
  2673 	}
       
  2674 
       
  2675 	regex = caseSensitive ? new RegExp( regex ) : new RegExp( regex, "i" );
       
  2676 	return this.optional( element ) || regex.test( value );
       
  2677 }, "Please specify a valid state" );
       
  2678 
       
  2679 // TODO check if value starts with <, otherwise don't try stripping anything
       
  2680 $.validator.addMethod( "strippedminlength", function( value, element, param ) {
       
  2681 	return $( value ).text().length >= param;
       
  2682 }, $.validator.format( "Please enter at least {0} characters" ) );
       
  2683 
       
  2684 $.validator.addMethod( "time", function( value, element ) {
       
  2685 	return this.optional( element ) || /^([01]\d|2[0-3]|[0-9])(:[0-5]\d){1,2}$/.test( value );
       
  2686 }, "Please enter a valid time, between 00:00 and 23:59" );
       
  2687 
       
  2688 $.validator.addMethod( "time12h", function( value, element ) {
       
  2689 	return this.optional( element ) || /^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test( value );
       
  2690 }, "Please enter a valid time in 12-hour am/pm format" );
       
  2691 
       
  2692 // Same as url, but TLD is optional
       
  2693 $.validator.addMethod( "url2", function( value, element ) {
       
  2694 	return this.optional( element ) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test( value );
       
  2695 }, $.validator.messages.url );
       
  2696 
       
  2697 /**
       
  2698  * Return true, if the value is a valid vehicle identification number (VIN).
       
  2699  *
       
  2700  * Works with all kind of text inputs.
       
  2701  *
       
  2702  * @example <input type="text" size="20" name="VehicleID" class="{required:true,vinUS:true}" />
       
  2703  * @desc Declares a required input element whose value must be a valid vehicle identification number.
       
  2704  *
       
  2705  * @name $.validator.methods.vinUS
       
  2706  * @type Boolean
       
  2707  * @cat Plugins/Validate/Methods
       
  2708  */
       
  2709 $.validator.addMethod( "vinUS", function( v ) {
       
  2710 	if ( v.length !== 17 ) {
       
  2711 		return false;
       
  2712 	}
       
  2713 
       
  2714 	var LL = [ "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ],
       
  2715 		VL = [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9 ],
       
  2716 		FL = [ 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 ],
       
  2717 		rs = 0,
       
  2718 		i, n, d, f, cd, cdv;
       
  2719 
       
  2720 	for ( i = 0; i < 17; i++ ) {
       
  2721 		f = FL[ i ];
       
  2722 		d = v.slice( i, i + 1 );
       
  2723 		if ( i === 8 ) {
       
  2724 			cdv = d;
       
  2725 		}
       
  2726 		if ( !isNaN( d ) ) {
       
  2727 			d *= f;
       
  2728 		} else {
       
  2729 			for ( n = 0; n < LL.length; n++ ) {
       
  2730 				if ( d.toUpperCase() === LL[ n ] ) {
       
  2731 					d = VL[ n ];
       
  2732 					d *= f;
       
  2733 					if ( isNaN( cdv ) && n === 8 ) {
       
  2734 						cdv = LL[ n ];
       
  2735 					}
       
  2736 					break;
       
  2737 				}
       
  2738 			}
       
  2739 		}
       
  2740 		rs += d;
       
  2741 	}
       
  2742 	cd = rs % 11;
       
  2743 	if ( cd === 10 ) {
       
  2744 		cd = "X";
       
  2745 	}
       
  2746 	if ( cd === cdv ) {
       
  2747 		return true;
       
  2748 	}
       
  2749 	return false;
       
  2750 }, "The specified vehicle identification number (VIN) is invalid." );
       
  2751 
       
  2752 $.validator.addMethod( "zipcodeUS", function( value, element ) {
       
  2753 	return this.optional( element ) || /^\d{5}(-\d{4})?$/.test( value );
       
  2754 }, "The specified US ZIP Code is invalid" );
       
  2755 
       
  2756 $.validator.addMethod( "ziprange", function( value, element ) {
       
  2757 	return this.optional( element ) || /^90[2-5]\d\{2\}-\d{4}$/.test( value );
       
  2758 }, "Your ZIP-code must be in the range 902xx-xxxx to 905xx-xxxx" );
       
  2759 return $;
       
  2760 }));
       
  2761