prometheus-net

Форк
0
1288 строк · 41.6 Кб
1
/*
2
* This file has been commented to support Visual Studio Intellisense.
3
* You should not use this file at runtime inside the browser--it is only
4
* intended to be used only for design-time IntelliSense.  Please use the
5
* standard jQuery library for all production use.
6
*
7
* Comment version: 1.17.0
8
*/
9

10
/*
11
* Note: While Microsoft is not the author of this file, Microsoft is
12
* offering you a license subject to the terms of the Microsoft Software
13
* License Terms for Microsoft ASP.NET Model View Controller 3.
14
* Microsoft reserves all other rights. The notices below are provided
15
* for informational purposes only and are not the license terms under
16
* which Microsoft distributed this file.
17
*
18
* jQuery Validation Plugin - v1.17.0 - 12/5/2016
19
* https://github.com/jzaefferer/jquery-validation
20
* Copyright (c) 2013 Jörn Zaefferer; Licensed MIT
21
*
22
*/
23

24
(function($) {
25

26
$.extend($.fn, {
27
	// http://docs.jquery.com/Plugins/Validation/validate
28
	validate: function( options ) {
29
		/// <summary>
30
		/// Validates the selected form. This method sets up event handlers for submit, focus,
31
		/// keyup, blur and click to trigger validation of the entire form or individual
32
		/// elements. Each one can be disabled, see the onxxx options (onsubmit, onfocusout,
33
		/// onkeyup, onclick). focusInvalid focuses elements when submitting a invalid form.
34
		/// </summary>
35
		/// <param name="options" type="Object">
36
		/// A set of key/value pairs that configure the validate. All options are optional.
37
		/// </param>
38

39
		// if nothing is selected, return nothing; can't chain anyway
40
		if (!this.length) {
41
			options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
42
			return;
43
		}
44

45
		// check if a validator for this form was already created
46
		var validator = $.data(this[0], 'validator');
47
		if ( validator ) {
48
			return validator;
49
		}
50
		
51
		validator = new $.validator( options, this[0] );
52
		$.data(this[0], 'validator', validator); 
53
		
54
		if ( validator.settings.onsubmit ) {
55
		
56
			// allow suppresing validation by adding a cancel class to the submit button
57
			this.find("input, button").filter(".cancel").click(function() {
58
				validator.cancelSubmit = true;
59
			});
60
			
61
			// when a submitHandler is used, capture the submitting button
62
			if (validator.settings.submitHandler) {
63
				this.find("input, button").filter(":submit").click(function() {
64
					validator.submitButton = this;
65
				});
66
			}
67
		
68
			// validate the form on submit
69
			this.submit( function( event ) {
70
				if ( validator.settings.debug )
71
					// prevent form submit to be able to see console output
72
					event.preventDefault();
73
					
74
				function handle() {
75
					if ( validator.settings.submitHandler ) {
76
						if (validator.submitButton) {
77
							// insert a hidden input as a replacement for the missing submit button
78
							var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
79
						}
80
						validator.settings.submitHandler.call( validator, validator.currentForm );
81
						if (validator.submitButton) {
82
							// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
83
							hidden.remove();
84
						}
85
						return false;
86
					}
87
					return true;
88
				}
89
					
90
				// prevent submit for invalid forms or custom submit handlers
91
				if ( validator.cancelSubmit ) {
92
					validator.cancelSubmit = false;
93
					return handle();
94
				}
95
				if ( validator.form() ) {
96
					if ( validator.pendingRequest ) {
97
						validator.formSubmitted = true;
98
						return false;
99
					}
100
					return handle();
101
				} else {
102
					validator.focusInvalid();
103
					return false;
104
				}
105
			});
106
		}
107
		
108
		return validator;
109
	},
110
	// http://docs.jquery.com/Plugins/Validation/valid
111
	valid: function() {
112
		/// <summary>
113
		/// Checks if the selected form is valid or if all selected elements are valid.
114
		/// validate() needs to be called on the form before checking it using this method.
115
		/// </summary>
116
		/// <returns type="Boolean" />
117

118
        if ( $(this[0]).is('form')) {
119
            return this.validate().form();
120
        } else {
121
            var valid = true;
122
            var validator = $(this[0].form).validate();
123
            this.each(function() {
124
				valid &= validator.element(this);
125
            });
126
            return valid;
127
        }
128
    },
129
	// attributes: space seperated list of attributes to retrieve and remove
130
	removeAttrs: function(attributes) {
131
		/// <summary>
132
		/// Remove the specified attributes from the first matched element and return them.
133
		/// </summary>
134
		/// <param name="attributes" type="String">
135
		/// A space-seperated list of attribute names to remove.
136
		/// </param>
137

138
		var result = {},
139
			$element = this;
140
		$.each(attributes.split(/\s/), function(index, value) {
141
			result[value] = $element.attr(value);
142
			$element.removeAttr(value);
143
		});
144
		return result;
145
	},
146
	// http://docs.jquery.com/Plugins/Validation/rules
147
	rules: function(command, argument) {
148
		/// <summary>
149
		/// Return the validations rules for the first selected element.
150
		/// </summary>
151
		/// <param name="command" type="String">
152
		/// Can be either "add" or "remove".
153
		/// </param>
154
		/// <param name="argument" type="">
155
		/// A list of rules to add or remove.
156
		/// </param>
157

158
		var element = this[0];
159
		
160
		if (command) {
161
			var settings = $.data(element.form, 'validator').settings;
162
			var staticRules = settings.rules;
163
			var existingRules = $.validator.staticRules(element);
164
			switch(command) {
165
			case "add":
166
				$.extend(existingRules, $.validator.normalizeRule(argument));
167
				staticRules[element.name] = existingRules;
168
				if (argument.messages)
169
					settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
170
				break;
171
			case "remove":
172
				if (!argument) {
173
					delete staticRules[element.name];
174
					return existingRules;
175
				}
176
				var filtered = {};
177
				$.each(argument.split(/\s/), function(index, method) {
178
					filtered[method] = existingRules[method];
179
					delete existingRules[method];
180
				});
181
				return filtered;
182
			}
183
		}
184
		
185
		var data = $.validator.normalizeRules(
186
		$.extend(
187
			{},
188
			$.validator.metadataRules(element),
189
			$.validator.classRules(element),
190
			$.validator.attributeRules(element),
191
			$.validator.staticRules(element)
192
		), element);
193
		
194
		// make sure required is at front
195
		if (data.required) {
196
			var param = data.required;
197
			delete data.required;
198
			data = $.extend({required: param}, data);
199
		}
200
		
201
		return data;
202
	}
203
});
204

205
// Custom selectors
206
$.extend($.expr[":"], {
207
	// http://docs.jquery.com/Plugins/Validation/blank
208
	blank: function(a) {return !$.trim("" + a.value);},
209
	// http://docs.jquery.com/Plugins/Validation/filled
210
	filled: function(a) {return !!$.trim("" + a.value);},
211
	// http://docs.jquery.com/Plugins/Validation/unchecked
212
	unchecked: function(a) {return !a.checked;}
213
});
214

215
// constructor for validator
216
$.validator = function( options, form ) {
217
	this.settings = $.extend( true, {}, $.validator.defaults, options );
218
	this.currentForm = form;
219
	this.init();
220
};
221

222
$.validator.format = function(source, params) {
223
	/// <summary>
224
	/// Replaces {n} placeholders with arguments.
225
	/// One or more arguments can be passed, in addition to the string template itself, to insert
226
	/// into the string.
227
	/// </summary>
228
	/// <param name="source" type="String">
229
	/// The string to format.
230
	/// </param>
231
	/// <param name="params" type="String">
232
	/// The first argument to insert, or an array of Strings to insert
233
	/// </param>
234
	/// <returns type="String" />
235

236
	if ( arguments.length == 1 ) 
237
		return function() {
238
			var args = $.makeArray(arguments);
239
			args.unshift(source);
240
			return $.validator.format.apply( this, args );
241
		};
242
	if ( arguments.length > 2 && params.constructor != Array  ) {
243
		params = $.makeArray(arguments).slice(1);
244
	}
245
	if ( params.constructor != Array ) {
246
		params = [ params ];
247
	}
248
	$.each(params, function(i, n) {
249
		source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
250
	});
251
	return source;
252
};
253

254
$.extend($.validator, {
255
	
256
	defaults: {
257
		messages: {},
258
		groups: {},
259
		rules: {},
260
		errorClass: "error",
261
		validClass: "valid",
262
		errorElement: "label",
263
		focusInvalid: true,
264
		errorContainer: $( [] ),
265
		errorLabelContainer: $( [] ),
266
		onsubmit: true,
267
		ignore: [],
268
		ignoreTitle: false,
269
		onfocusin: function(element) {
270
			this.lastActive = element;
271
				
272
			// hide error label and remove error class on focus if enabled
273
			if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
274
				this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
275
				this.addWrapper(this.errorsFor(element)).hide();
276
			}
277
		},
278
		onfocusout: function(element) {
279
			if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
280
				this.element(element);
281
			}
282
		},
283
		onkeyup: function(element) {
284
			if ( element.name in this.submitted || element == this.lastElement ) {
285
				this.element(element);
286
			}
287
		},
288
		onclick: function(element) {
289
			// click on selects, radiobuttons and checkboxes
290
			if ( element.name in this.submitted )
291
				this.element(element);
292
			// or option elements, check parent select in that case
293
			else if (element.parentNode.name in this.submitted)
294
				this.element(element.parentNode);
295
		},
296
		highlight: function( element, errorClass, validClass ) {
297
			$(element).addClass(errorClass).removeClass(validClass);
298
		},
299
		unhighlight: function( element, errorClass, validClass ) {
300
			$(element).removeClass(errorClass).addClass(validClass);
301
		}
302
	},
303

304
	// http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
305
	setDefaults: function(settings) {
306
		/// <summary>
307
		/// Modify default settings for validation.
308
		/// Accepts everything that Plugins/Validation/validate accepts.
309
		/// </summary>
310
		/// <param name="settings" type="Options">
311
		/// Options to set as default.
312
		/// </param>
313

314
		$.extend( $.validator.defaults, settings );
315
	},
316

317
	messages: {
318
		required: "This field is required.",
319
		remote: "Please fix this field.",
320
		email: "Please enter a valid email address.",
321
		url: "Please enter a valid URL.",
322
		date: "Please enter a valid date.",
323
		dateISO: "Please enter a valid date (ISO).",
324
		number: "Please enter a valid number.",
325
		digits: "Please enter only digits.",
326
		creditcard: "Please enter a valid credit card number.",
327
		equalTo: "Please enter the same value again.",
328
		accept: "Please enter a value with a valid extension.",
329
		maxlength: $.validator.format("Please enter no more than {0} characters."),
330
		minlength: $.validator.format("Please enter at least {0} characters."),
331
		rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
332
		range: $.validator.format("Please enter a value between {0} and {1}."),
333
		max: $.validator.format("Please enter a value less than or equal to {0}."),
334
		min: $.validator.format("Please enter a value greater than or equal to {0}.")
335
	},
336
	
337
	autoCreateRanges: false,
338
	
339
	prototype: {
340
		
341
		init: function() {
342
			this.labelContainer = $(this.settings.errorLabelContainer);
343
			this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
344
			this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
345
			this.submitted = {};
346
			this.valueCache = {};
347
			this.pendingRequest = 0;
348
			this.pending = {};
349
			this.invalid = {};
350
			this.reset();
351
			
352
			var groups = (this.groups = {});
353
			$.each(this.settings.groups, function(key, value) {
354
				$.each(value.split(/\s/), function(index, name) {
355
					groups[name] = key;
356
				});
357
			});
358
			var rules = this.settings.rules;
359
			$.each(rules, function(key, value) {
360
				rules[key] = $.validator.normalizeRule(value);
361
			});
362
			
363
			function delegate(event) {
364
				var validator = $.data(this[0].form, "validator"),
365
					eventType = "on" + event.type.replace(/^validate/, "");
366
				validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
367
			}
368
			$(this.currentForm)
369
				.validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
370
				.validateDelegate(":radio, :checkbox, select, option", "click", delegate);
371

372
			if (this.settings.invalidHandler)
373
				$(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
374
		},
375

376
		// http://docs.jquery.com/Plugins/Validation/Validator/form
377
		form: function() {
378
			/// <summary>
379
			/// Validates the form, returns true if it is valid, false otherwise.
380
			/// This behaves as a normal submit event, but returns the result.
381
			/// </summary>
382
			/// <returns type="Boolean" />
383

384
			this.checkForm();
385
			$.extend(this.submitted, this.errorMap);
386
			this.invalid = $.extend({}, this.errorMap);
387
			if (!this.valid())
388
				$(this.currentForm).triggerHandler("invalid-form", [this]);
389
			this.showErrors();
390
			return this.valid();
391
		},
392
		
393
		checkForm: function() {
394
			this.prepareForm();
395
			for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
396
				this.check( elements[i] );
397
			}
398
			return this.valid(); 
399
		},
400
		
401
		// http://docs.jquery.com/Plugins/Validation/Validator/element
402
		element: function( element ) {
403
			/// <summary>
404
			/// Validates a single element, returns true if it is valid, false otherwise.
405
			/// This behaves as validation on blur or keyup, but returns the result.
406
			/// </summary>
407
			/// <param name="element" type="Selector">
408
			/// An element to validate, must be inside the validated form.
409
			/// </param>
410
			/// <returns type="Boolean" />
411

412
			element = this.clean( element );
413
			this.lastElement = element;
414
			this.prepareElement( element );
415
			this.currentElements = $(element);
416
			var result = this.check( element );
417
			if ( result ) {
418
				delete this.invalid[element.name];
419
			} else {
420
				this.invalid[element.name] = true;
421
			}
422
			if ( !this.numberOfInvalids() ) {
423
				// Hide error containers on last error
424
				this.toHide = this.toHide.add( this.containers );
425
			}
426
			this.showErrors();
427
			return result;
428
		},
429

430
		// http://docs.jquery.com/Plugins/Validation/Validator/showErrors
431
		showErrors: function(errors) {
432
			/// <summary>
433
			/// Show the specified messages.
434
			/// Keys have to refer to the names of elements, values are displayed for those elements, using the configured error placement.
435
			/// </summary>
436
			/// <param name="errors" type="Object">
437
			/// One or more key/value pairs of input names and messages.
438
			/// </param>
439

440
			if(errors) {
441
				// add items to error list and map
442
				$.extend( this.errorMap, errors );
443
				this.errorList = [];
444
				for ( var name in errors ) {
445
					this.errorList.push({
446
						message: errors[name],
447
						element: this.findByName(name)[0]
448
					});
449
				}
450
				// remove items from success list
451
				this.successList = $.grep( this.successList, function(element) {
452
					return !(element.name in errors);
453
				});
454
			}
455
			this.settings.showErrors
456
				? this.settings.showErrors.call( this, this.errorMap, this.errorList )
457
				: this.defaultShowErrors();
458
		},
459
		
460
		// http://docs.jquery.com/Plugins/Validation/Validator/resetForm
461
		resetForm: function() {
462
			/// <summary>
463
			/// Resets the controlled form.
464
			/// Resets input fields to their original value (requires form plugin), removes classes
465
			/// indicating invalid elements and hides error messages.
466
			/// </summary>
467

468
			if ( $.fn.resetForm )
469
				$( this.currentForm ).resetForm();
470
			this.submitted = {};
471
			this.prepareForm();
472
			this.hideErrors();
473
			this.elements().removeClass( this.settings.errorClass );
474
		},
475
		
476
		numberOfInvalids: function() {
477
			/// <summary>
478
			/// Returns the number of invalid fields.
479
			/// This depends on the internal validator state. It covers all fields only after
480
			/// validating the complete form (on submit or via $("form").valid()). After validating
481
			/// a single element, only that element is counted. Most useful in combination with the
482
			/// invalidHandler-option.
483
			/// </summary>
484
			/// <returns type="Number" />
485

486
			return this.objectLength(this.invalid);
487
		},
488
		
489
		objectLength: function( obj ) {
490
			var count = 0;
491
			for ( var i in obj )
492
				count++;
493
			return count;
494
		},
495
		
496
		hideErrors: function() {
497
			this.addWrapper( this.toHide ).hide();
498
		},
499
		
500
		valid: function() {
501
			return this.size() == 0;
502
		},
503
		
504
		size: function() {
505
			return this.errorList.length;
506
		},
507
		
508
		focusInvalid: function() {
509
			if( this.settings.focusInvalid ) {
510
				try {
511
					$(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
512
					.filter(":visible")
513
					.focus()
514
					// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
515
					.trigger("focusin");
516
				} catch(e) {
517
					// ignore IE throwing errors when focusing hidden elements
518
				}
519
			}
520
		},
521
		
522
		findLastActive: function() {
523
			var lastActive = this.lastActive;
524
			return lastActive && $.grep(this.errorList, function(n) {
525
				return n.element.name == lastActive.name;
526
			}).length == 1 && lastActive;
527
		},
528
		
529
		elements: function() {
530
			var validator = this,
531
				rulesCache = {};
532
			
533
			// select all valid inputs inside the form (no submit or reset buttons)
534
			// workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
535
			return $([]).add(this.currentForm.elements)
536
			.filter(":input")
537
			.not(":submit, :reset, :image, [disabled]")
538
			.not( this.settings.ignore )
539
			.filter(function() {
540
				!this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
541
			
542
				// select only the first element for each name, and only those with rules specified
543
				if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
544
					return false;
545
				
546
				rulesCache[this.name] = true;
547
				return true;
548
			});
549
		},
550
		
551
		clean: function( selector ) {
552
			return $( selector )[0];
553
		},
554
		
555
		errors: function() {
556
			return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
557
		},
558
		
559
		reset: function() {
560
			this.successList = [];
561
			this.errorList = [];
562
			this.errorMap = {};
563
			this.toShow = $([]);
564
			this.toHide = $([]);
565
			this.currentElements = $([]);
566
		},
567
		
568
		prepareForm: function() {
569
			this.reset();
570
			this.toHide = this.errors().add( this.containers );
571
		},
572
		
573
		prepareElement: function( element ) {
574
			this.reset();
575
			this.toHide = this.errorsFor(element);
576
		},
577
	
578
		check: function( element ) {
579
			element = this.clean( element );
580
			
581
			// if radio/checkbox, validate first element in group instead
582
			if (this.checkable(element)) {
583
			    element = this.findByName(element.name).not(this.settings.ignore)[0];
584
			}
585
			
586
			var rules = $(element).rules();
587
			var dependencyMismatch = false;
588
			for (var method in rules) {
589
				var rule = { method: method, parameters: rules[method] };
590
				try {
591
					var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
592
					
593
					// if a method indicates that the field is optional and therefore valid,
594
					// don't mark it as valid when there are no other rules
595
					if ( result == "dependency-mismatch" ) {
596
						dependencyMismatch = true;
597
						continue;
598
					}
599
					dependencyMismatch = false;
600
					
601
					if ( result == "pending" ) {
602
						this.toHide = this.toHide.not( this.errorsFor(element) );
603
						return;
604
					}
605
					
606
					if( !result ) {
607
						this.formatAndAdd( element, rule );
608
						return false;
609
					}
610
				} catch(e) {
611
					this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
612
						 + ", check the '" + rule.method + "' method", e);
613
					throw e;
614
				}
615
			}
616
			if (dependencyMismatch)
617
				return;
618
			if ( this.objectLength(rules) )
619
				this.successList.push(element);
620
			return true;
621
		},
622
		
623
		// return the custom message for the given element and validation method
624
		// specified in the element's "messages" metadata
625
		customMetaMessage: function(element, method) {
626
			if (!$.metadata)
627
				return;
628
			
629
			var meta = this.settings.meta
630
				? $(element).metadata()[this.settings.meta]
631
				: $(element).metadata();
632
			
633
			return meta && meta.messages && meta.messages[method];
634
		},
635
		
636
		// return the custom message for the given element name and validation method
637
		customMessage: function( name, method ) {
638
			var m = this.settings.messages[name];
639
			return m && (m.constructor == String
640
				? m
641
				: m[method]);
642
		},
643
		
644
		// return the first defined argument, allowing empty strings
645
		findDefined: function() {
646
			for(var i = 0; i < arguments.length; i++) {
647
				if (arguments[i] !== undefined)
648
					return arguments[i];
649
			}
650
			return undefined;
651
		},
652
		
653
		defaultMessage: function( element, method) {
654
			return this.findDefined(
655
				this.customMessage( element.name, method ),
656
				this.customMetaMessage( element, method ),
657
				// title is never undefined, so handle empty string as undefined
658
				!this.settings.ignoreTitle && element.title || undefined,
659
				$.validator.messages[method],
660
				"<strong>Warning: No message defined for " + element.name + "</strong>"
661
			);
662
		},
663
		
664
		formatAndAdd: function( element, rule ) {
665
			var message = this.defaultMessage( element, rule.method ),
666
				theregex = /\$?\{(\d+)\}/g;
667
			if ( typeof message == "function" ) {
668
				message = message.call(this, rule.parameters, element);
669
			} else if (theregex.test(message)) {
670
				message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
671
			}			
672
			this.errorList.push({
673
				message: message,
674
				element: element
675
			});
676
			
677
			this.errorMap[element.name] = message;
678
			this.submitted[element.name] = message;
679
		},
680
		
681
		addWrapper: function(toToggle) {
682
			if ( this.settings.wrapper )
683
				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
684
			return toToggle;
685
		},
686
		
687
		defaultShowErrors: function() {
688
			for ( var i = 0; this.errorList[i]; i++ ) {
689
				var error = this.errorList[i];
690
				this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
691
				this.showLabel( error.element, error.message );
692
			}
693
			if( this.errorList.length ) {
694
				this.toShow = this.toShow.add( this.containers );
695
			}
696
			if (this.settings.success) {
697
				for ( var i = 0; this.successList[i]; i++ ) {
698
					this.showLabel( this.successList[i] );
699
				}
700
			}
701
			if (this.settings.unhighlight) {
702
				for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
703
					this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
704
				}
705
			}
706
			this.toHide = this.toHide.not( this.toShow );
707
			this.hideErrors();
708
			this.addWrapper( this.toShow ).show();
709
		},
710
		
711
		validElements: function() {
712
			return this.currentElements.not(this.invalidElements());
713
		},
714
		
715
		invalidElements: function() {
716
			return $(this.errorList).map(function() {
717
				return this.element;
718
			});
719
		},
720
		
721
		showLabel: function(element, message) {
722
			var label = this.errorsFor( element );
723
			if ( label.length ) {
724
				// refresh error/success class
725
				label.removeClass().addClass( this.settings.errorClass );
726
			
727
				// check if we have a generated label, replace the message then
728
				label.attr("generated") && label.html(message);
729
			} else {
730
				// create label
731
				label = $("<" + this.settings.errorElement + "/>")
732
					.attr({"for":  this.idOrName(element), generated: true})
733
					.addClass(this.settings.errorClass)
734
					.html(message || "");
735
				if ( this.settings.wrapper ) {
736
					// make sure the element is visible, even in IE
737
					// actually showing the wrapped element is handled elsewhere
738
					label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
739
				}
740
				if ( !this.labelContainer.append(label).length )
741
					this.settings.errorPlacement
742
						? this.settings.errorPlacement(label, $(element) )
743
						: label.insertAfter(element);
744
			}
745
			if ( !message && this.settings.success ) {
746
				label.text("");
747
				typeof this.settings.success == "string"
748
					? label.addClass( this.settings.success )
749
					: this.settings.success( label );
750
			}
751
			this.toShow = this.toShow.add(label);
752
		},
753
		
754
		errorsFor: function(element) {
755
			var name = this.idOrName(element);
756
    		return this.errors().filter(function() {
757
				return $(this).attr('for') == name;
758
			});
759
		},
760
		
761
		idOrName: function(element) {
762
			return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
763
		},
764

765
		checkable: function( element ) {
766
			return /radio|checkbox/i.test(element.type);
767
		},
768
		
769
		findByName: function( name ) {
770
			// select by name and filter by form for performance over form.find("[name=...]")
771
			var form = this.currentForm;
772
			return $(document.getElementsByName(name)).map(function(index, element) {
773
				return element.form == form && element.name == name && element  || null;
774
			});
775
		},
776
		
777
		getLength: function(value, element) {
778
			switch( element.nodeName.toLowerCase() ) {
779
			case 'select':
780
				return $("option:selected", element).length;
781
			case 'input':
782
				if( this.checkable( element) )
783
					return this.findByName(element.name).filter(':checked').length;
784
			}
785
			return value.length;
786
		},
787
	
788
		depend: function(param, element) {
789
			return this.dependTypes[typeof param]
790
				? this.dependTypes[typeof param](param, element)
791
				: true;
792
		},
793
	
794
		dependTypes: {
795
			"boolean": function(param, element) {
796
				return param;
797
			},
798
			"string": function(param, element) {
799
				return !!$(param, element.form).length;
800
			},
801
			"function": function(param, element) {
802
				return param(element);
803
			}
804
		},
805
		
806
		optional: function(element) {
807
			return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
808
		},
809
		
810
		startRequest: function(element) {
811
			if (!this.pending[element.name]) {
812
				this.pendingRequest++;
813
				this.pending[element.name] = true;
814
			}
815
		},
816
		
817
		stopRequest: function(element, valid) {
818
			this.pendingRequest--;
819
			// sometimes synchronization fails, make sure pendingRequest is never < 0
820
			if (this.pendingRequest < 0)
821
				this.pendingRequest = 0;
822
			delete this.pending[element.name];
823
			if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
824
				$(this.currentForm).submit();
825
				this.formSubmitted = false;
826
			} else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
827
				$(this.currentForm).triggerHandler("invalid-form", [this]);
828
				this.formSubmitted = false;
829
			}
830
		},
831
		
832
		previousValue: function(element) {
833
			return $.data(element, "previousValue") || $.data(element, "previousValue", {
834
				old: null,
835
				valid: true,
836
				message: this.defaultMessage( element, "remote" )
837
			});
838
		}
839
		
840
	},
841
	
842
	classRuleSettings: {
843
		required: {required: true},
844
		email: {email: true},
845
		url: {url: true},
846
		date: {date: true},
847
		dateISO: {dateISO: true},
848
		dateDE: {dateDE: true},
849
		number: {number: true},
850
		numberDE: {numberDE: true},
851
		digits: {digits: true},
852
		creditcard: {creditcard: true}
853
	},
854
	
855
	addClassRules: function(className, rules) {
856
		/// <summary>
857
		/// Add a compound class method - useful to refactor common combinations of rules into a single
858
		/// class.
859
		/// </summary>
860
		/// <param name="name" type="String">
861
		/// The name of the class rule to add
862
		/// </param>
863
		/// <param name="rules" type="Options">
864
		/// The compound rules
865
		/// </param>
866

867
		className.constructor == String ?
868
			this.classRuleSettings[className] = rules :
869
			$.extend(this.classRuleSettings, className);
870
	},
871
	
872
	classRules: function(element) {
873
		var rules = {};
874
		var classes = $(element).attr('class');
875
		classes && $.each(classes.split(' '), function() {
876
			if (this in $.validator.classRuleSettings) {
877
				$.extend(rules, $.validator.classRuleSettings[this]);
878
			}
879
		});
880
		return rules;
881
	},
882
	
883
	attributeRules: function(element) {
884
		var rules = {};
885
		var $element = $(element);
886

887
		for (var method in $.validator.methods) {
888
			var value = $element.attr(method);
889
			if (value) {
890
				rules[method] = value;
891
			}
892
		}
893
		
894
		// maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
895
		if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
896
			delete rules.maxlength;
897
		}
898
		
899
		return rules;
900
	},
901
	
902
	metadataRules: function(element) {
903
		if (!$.metadata) return {};
904
		
905
		var meta = $.data(element.form, 'validator').settings.meta;
906
		return meta ?
907
			$(element).metadata()[meta] :
908
			$(element).metadata();
909
	},
910
	
911
	staticRules: function(element) {
912
		var rules = {};
913
		var validator = $.data(element.form, 'validator');
914
		if (validator.settings.rules) {
915
			rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
916
		}
917
		return rules;
918
	},
919
	
920
	normalizeRules: function(rules, element) {
921
		// handle dependency check
922
		$.each(rules, function(prop, val) {
923
			// ignore rule when param is explicitly false, eg. required:false
924
			if (val === false) {
925
				delete rules[prop];
926
				return;
927
			}
928
			if (val.param || val.depends) {
929
				var keepRule = true;
930
				switch (typeof val.depends) {
931
					case "string":
932
						keepRule = !!$(val.depends, element.form).length;
933
						break;
934
					case "function":
935
						keepRule = val.depends.call(element, element);
936
						break;
937
				}
938
				if (keepRule) {
939
					rules[prop] = val.param !== undefined ? val.param : true;
940
				} else {
941
					delete rules[prop];
942
				}
943
			}
944
		});
945
		
946
		// evaluate parameters
947
		$.each(rules, function(rule, parameter) {
948
			rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
949
		});
950
		
951
		// clean number parameters
952
		$.each(['minlength', 'maxlength', 'min', 'max'], function() {
953
			if (rules[this]) {
954
				rules[this] = Number(rules[this]);
955
			}
956
		});
957
		$.each(['rangelength', 'range'], function() {
958
			if (rules[this]) {
959
				rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
960
			}
961
		});
962
		
963
		if ($.validator.autoCreateRanges) {
964
			// auto-create ranges
965
			if (rules.min && rules.max) {
966
				rules.range = [rules.min, rules.max];
967
				delete rules.min;
968
				delete rules.max;
969
			}
970
			if (rules.minlength && rules.maxlength) {
971
				rules.rangelength = [rules.minlength, rules.maxlength];
972
				delete rules.minlength;
973
				delete rules.maxlength;
974
			}
975
		}
976
		
977
		// To support custom messages in metadata ignore rule methods titled "messages"
978
		if (rules.messages) {
979
			delete rules.messages;
980
		}
981
		
982
		return rules;
983
	},
984
	
985
	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
986
	normalizeRule: function(data) {
987
		if( typeof data == "string" ) {
988
			var transformed = {};
989
			$.each(data.split(/\s/), function() {
990
				transformed[this] = true;
991
			});
992
			data = transformed;
993
		}
994
		return data;
995
	},
996
	
997
	// http://docs.jquery.com/Plugins/Validation/Validator/addMethod
998
	addMethod: function(name, method, message) {
999
		/// <summary>
1000
		/// Add a custom validation method. It must consist of a name (must be a legal javascript 
1001
		/// identifier), a javascript based function and a default string message.
1002
		/// </summary>
1003
		/// <param name="name" type="String">
1004
		/// The name of the method, used to identify and referencing it, must be a valid javascript
1005
		/// identifier
1006
		/// </param>
1007
		/// <param name="method" type="Function">
1008
		/// The actual method implementation, returning true if an element is valid
1009
		/// </param>
1010
		/// <param name="message" type="String" optional="true">
1011
		/// (Optional) The default message to display for this method. Can be a function created by 
1012
		/// jQuery.validator.format(value). When undefined, an already existing message is used 
1013
		/// (handy for localization), otherwise the field-specific messages have to be defined.
1014
		/// </param>
1015

1016
		$.validator.methods[name] = method;
1017
		$.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
1018
		if (method.length < 3) {
1019
			$.validator.addClassRules(name, $.validator.normalizeRule(name));
1020
		}
1021
	},
1022

1023
	methods: {
1024

1025
		// http://docs.jquery.com/Plugins/Validation/Methods/required
1026
		required: function(value, element, param) {
1027
			// check if dependency is met
1028
			if ( !this.depend(param, element) )
1029
				return "dependency-mismatch";
1030
			switch( element.nodeName.toLowerCase() ) {
1031
			case 'select':
1032
				// could be an array for select-multiple or a string, both are fine this way
1033
				var val = $(element).val();
1034
				return val && val.length > 0;
1035
			case 'input':
1036
				if ( this.checkable(element) )
1037
					return this.getLength(value, element) > 0;
1038
			default:
1039
				return $.trim(value).length > 0;
1040
			}
1041
		},
1042
		
1043
		// http://docs.jquery.com/Plugins/Validation/Methods/remote
1044
		remote: function(value, element, param) {
1045
			if ( this.optional(element) )
1046
				return "dependency-mismatch";
1047
			
1048
			var previous = this.previousValue(element);
1049
			if (!this.settings.messages[element.name] )
1050
				this.settings.messages[element.name] = {};
1051
			previous.originalMessage = this.settings.messages[element.name].remote;
1052
			this.settings.messages[element.name].remote = previous.message;
1053
			
1054
			param = typeof param == "string" && {url:param} || param; 
1055
			
1056
			if ( this.pending[element.name] ) {
1057
				return "pending";
1058
			}
1059
			if ( previous.old === value ) {
1060
				return previous.valid;
1061
			}
1062

1063
			previous.old = value;
1064
			var validator = this;
1065
			this.startRequest(element);
1066
			var data = {};
1067
			data[element.name] = value;
1068
			$.ajax($.extend(true, {
1069
				url: param,
1070
				mode: "abort",
1071
				port: "validate" + element.name,
1072
				dataType: "json",
1073
				data: data,
1074
				success: function(response) {
1075
					validator.settings.messages[element.name].remote = previous.originalMessage;
1076
					var valid = response === true;
1077
					if ( valid ) {
1078
						var submitted = validator.formSubmitted;
1079
						validator.prepareElement(element);
1080
						validator.formSubmitted = submitted;
1081
						validator.successList.push(element);
1082
						validator.showErrors();
1083
					} else {
1084
						var errors = {};
1085
						var message = response || validator.defaultMessage(element, "remote");
1086
						errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
1087
						validator.showErrors(errors);
1088
					}
1089
					previous.valid = valid;
1090
					validator.stopRequest(element, valid);
1091
				}
1092
			}, param));
1093
			return "pending";
1094
		},
1095

1096
		// http://docs.jquery.com/Plugins/Validation/Methods/minlength
1097
		minlength: function(value, element, param) {
1098
			return this.optional(element) || this.getLength($.trim(value), element) >= param;
1099
		},
1100
		
1101
		// http://docs.jquery.com/Plugins/Validation/Methods/maxlength
1102
		maxlength: function(value, element, param) {
1103
			return this.optional(element) || this.getLength($.trim(value), element) <= param;
1104
		},
1105
		
1106
		// http://docs.jquery.com/Plugins/Validation/Methods/rangelength
1107
		rangelength: function(value, element, param) {
1108
			var length = this.getLength($.trim(value), element);
1109
			return this.optional(element) || ( length >= param[0] && length <= param[1] );
1110
		},
1111
		
1112
		// http://docs.jquery.com/Plugins/Validation/Methods/min
1113
		min: function( value, element, param ) {
1114
			return this.optional(element) || value >= param;
1115
		},
1116
		
1117
		// http://docs.jquery.com/Plugins/Validation/Methods/max
1118
		max: function( value, element, param ) {
1119
			return this.optional(element) || value <= param;
1120
		},
1121
		
1122
		// http://docs.jquery.com/Plugins/Validation/Methods/range
1123
		range: function( value, element, param ) {
1124
			return this.optional(element) || ( value >= param[0] && value <= param[1] );
1125
		},
1126
		
1127
		// http://docs.jquery.com/Plugins/Validation/Methods/email
1128
		email: function(value, element) {
1129
			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
1130
			return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(value);
1131
		},
1132
	
1133
		// http://docs.jquery.com/Plugins/Validation/Methods/url
1134
		url: function(value, element) {
1135
			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1136
			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);
1137
		},
1138
        
1139
		// http://docs.jquery.com/Plugins/Validation/Methods/date
1140
		date: function(value, element) {
1141
			return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
1142
		},
1143
	
1144
		// http://docs.jquery.com/Plugins/Validation/Methods/dateISO
1145
		dateISO: function(value, element) {
1146
			return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
1147
		},
1148
	
1149
		// http://docs.jquery.com/Plugins/Validation/Methods/number
1150
		number: function(value, element) {
1151
			return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
1152
		},
1153
	
1154
		// http://docs.jquery.com/Plugins/Validation/Methods/digits
1155
		digits: function(value, element) {
1156
			return this.optional(element) || /^\d+$/.test(value);
1157
		},
1158
		
1159
		// http://docs.jquery.com/Plugins/Validation/Methods/creditcard
1160
		// based on http://en.wikipedia.org/wiki/Luhn
1161
		creditcard: function(value, element) {
1162
			if ( this.optional(element) )
1163
				return "dependency-mismatch";
1164
			// accept only digits and dashes
1165
			if (/[^0-9-]+/.test(value))
1166
				return false;
1167
			var nCheck = 0,
1168
				nDigit = 0,
1169
				bEven = false;
1170

1171
			value = value.replace(/\D/g, "");
1172

1173
			for (var n = value.length - 1; n >= 0; n--) {
1174
				var cDigit = value.charAt(n);
1175
				var nDigit = parseInt(cDigit, 10);
1176
				if (bEven) {
1177
					if ((nDigit *= 2) > 9)
1178
						nDigit -= 9;
1179
				}
1180
				nCheck += nDigit;
1181
				bEven = !bEven;
1182
			}
1183

1184
			return (nCheck % 10) == 0;
1185
		},
1186
		
1187
		// http://docs.jquery.com/Plugins/Validation/Methods/accept
1188
		accept: function(value, element, param) {
1189
			param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
1190
			return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); 
1191
		},
1192
		
1193
		// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
1194
		equalTo: function(value, element, param) {
1195
			// bind to the blur event of the target in order to revalidate whenever the target field is updated
1196
			// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
1197
			var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
1198
				$(element).valid();
1199
			});
1200
			return value == target.val();
1201
		}
1202
		
1203
	}
1204
	
1205
});
1206

1207
// deprecated, use $.validator.format instead
1208
$.format = $.validator.format;
1209

1210
})(jQuery);
1211

1212
// ajax mode: abort
1213
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1214
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 
1215
;(function($) {
1216
	var pendingRequests = {};
1217
		// Use a prefilter if available (1.5+)
1218
	if ( $.ajaxPrefilter ) {
1219
		$.ajaxPrefilter(function(settings, _, xhr) {
1220
		    var port = settings.port;
1221
		    if (settings.mode == "abort") {
1222
			    if ( pendingRequests[port] ) {
1223
				    pendingRequests[port].abort();
1224
			    }				pendingRequests[port] = xhr;
1225
		    }
1226
	    });
1227
	} else {
1228
		// Proxy ajax
1229
		var ajax = $.ajax;
1230
		$.ajax = function(settings) {
1231
			var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1232
				port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1233
			if (mode == "abort") {
1234
				if ( pendingRequests[port] ) {
1235
					pendingRequests[port].abort();
1236
				}
1237

1238
			    return (pendingRequests[port] = ajax.apply(this, arguments));
1239
		    }
1240
		    return ajax.apply(this, arguments);
1241
	    };
1242
    }
1243
})(jQuery);
1244

1245
// provides cross-browser focusin and focusout events
1246
// IE has native support, in other browsers, use event caputuring (neither bubbles)
1247

1248
// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
1249
// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 
1250
;(function($) {
1251
	// only implement if not provided by jQuery core (since 1.4)
1252
	// TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
1253
	if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
1254
		$.each({
1255
			focus: 'focusin',
1256
			blur: 'focusout'	
1257
		}, function( original, fix ){
1258
			$.event.special[fix] = {
1259
				setup:function() {
1260
					this.addEventListener( original, handler, true );
1261
				},
1262
				teardown:function() {
1263
					this.removeEventListener( original, handler, true );
1264
				},
1265
				handler: function(e) {
1266
					arguments[0] = $.event.fix(e);
1267
					arguments[0].type = fix;
1268
					return $.event.handle.apply(this, arguments);
1269
				}
1270
			};
1271
			function handler(e) {
1272
				e = $.event.fix(e);
1273
				e.type = fix;
1274
				return $.event.handle.call(this, e);
1275
			}
1276
		});
1277
	};
1278
	$.extend($.fn, {
1279
		validateDelegate: function(delegate, type, handler) {
1280
			return this.bind(type, function(event) {
1281
				var target = $(event.target);
1282
				if (target.is(delegate)) {
1283
					return handler.apply(target, arguments);
1284
				}
1285
			});
1286
		}
1287
	});
1288
})(jQuery);
1289

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.